Cleanup ActivityResult callbacks

This commit is contained in:
topjohnwu 2020-10-06 02:04:19 -07:00
parent 333fe6da0e
commit fc19b50290
11 changed files with 58 additions and 106 deletions

View File

@ -1,6 +1,5 @@
package com.topjohnwu.magisk.arch
import android.content.Intent
import android.os.Bundle
import android.view.KeyEvent
import android.view.View
@ -41,11 +40,6 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
AppCompatDelegate.setDefaultNightMode(theme)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
currentFragment?.onActivityResult(requestCode, resultCode, data)
}
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(themeRes)
super.onCreate(savedInstanceState)

View File

@ -17,7 +17,7 @@ import com.topjohnwu.magisk.ktx.startAnimations
abstract class BaseUIFragment<VM : BaseViewModel, Binding : ViewDataBinding> :
Fragment(), BaseUIComponent<VM> {
protected val activity get() = requireActivity() as BaseUIActivity<*, *>
val activity get() = requireActivity() as BaseUIActivity<*, *>
protected lateinit var binding: Binding
protected abstract val layoutRes: Int

View File

@ -1,7 +1,6 @@
package com.topjohnwu.magisk.arch
import android.content.Context
import androidx.fragment.app.Fragment
import kotlinx.coroutines.CoroutineScope
/**
@ -23,5 +22,5 @@ interface ActivityExecutor {
}
interface FragmentExecutor {
operator fun invoke(fragment: Fragment)
operator fun invoke(fragment: BaseUIFragment<*, *>)
}

View File

@ -33,12 +33,12 @@ object Const {
object ID {
const val FETCH_ZIP = 2
const val SELECT_BOOT = 3
const val SELECT_FILE = 3
const val MAX_ACTIVITY_RESULT = 10
// notifications
const val MAGISK_UPDATE_NOTIFICATION_ID = 4
const val APK_UPDATE_NOTIFICATION_ID = 5
const val DTBO_NOTIFICATION_ID = 7
const val HIDE_MANAGER_NOTIFICATION_ID = 8
const val UPDATE_NOTIFICATION_CHANNEL = "update"
const val PROGRESS_NOTIFICATION_CHANNEL = "progress"

View File

@ -8,22 +8,24 @@ import android.content.pm.PackageManager
import android.content.res.Configuration
import android.os.Build
import android.widget.Toast
import androidx.annotation.CallSuper
import androidx.appcompat.app.AppCompatActivity
import androidx.collection.SparseArrayCompat
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.core.wrap
import com.topjohnwu.magisk.ktx.set
import com.topjohnwu.magisk.utils.Utils
import kotlin.random.Random
typealias RequestCallback = BaseActivity.(Int, Intent?) -> Unit
typealias ActivityResultCallback = BaseActivity.(Int, Intent?) -> Unit
abstract class BaseActivity : AppCompatActivity() {
private val resultCallbacks by lazy { SparseArrayCompat<RequestCallback>() }
private val resultCallbacks by lazy { SparseArrayCompat<ActivityResultCallback>() }
override fun applyOverrideConfiguration(config: Configuration?) {
// Force applying our preferred local
@ -38,8 +40,7 @@ abstract class BaseActivity : AppCompatActivity() {
fun withPermission(permission: String, builder: PermissionRequestBuilder.() -> Unit) {
val request = PermissionRequestBuilder().apply(builder).build()
if (permission == Manifest.permission.WRITE_EXTERNAL_STORAGE &&
Build.VERSION.SDK_INT >= 29) {
if (permission == Manifest.permission.WRITE_EXTERNAL_STORAGE && Build.VERSION.SDK_INT >= 29) {
// We do not need external rw on 29+
request.onSuccess()
return
@ -48,8 +49,11 @@ abstract class BaseActivity : AppCompatActivity() {
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
request.onSuccess()
} else {
val requestCode = Random.nextInt(256, 512)
resultCallbacks[requestCode] = { result, _ ->
var requestCode: Int
do {
requestCode = Random.nextInt(Const.ID.MAX_ACTIVITY_RESULT + 1, 1 shl 15)
} while (!resultCallbacks.containsKey(requestCode))
resultCallbacks[requestCode] = { result, _ ->
if (result > 0)
request.onSuccess()
else
@ -79,16 +83,17 @@ abstract class BaseActivity : AppCompatActivity() {
}
@CallSuper
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
resultCallbacks[requestCode]?.also {
resultCallbacks[requestCode]?.also { callback ->
resultCallbacks.remove(requestCode)
it(this, resultCode, data)
callback(this, resultCode, data)
}
}
fun startActivityForResult(intent: Intent, requestCode: Int, listener: RequestCallback) {
resultCallbacks[requestCode] = listener
fun startActivityForResult(intent: Intent, requestCode: Int, callback: ActivityResultCallback) {
resultCallbacks[requestCode] = callback
try {
startActivityForResult(intent, requestCode)
} catch (e: ActivityNotFoundException) {

View File

@ -1,45 +0,0 @@
package com.topjohnwu.magisk.events
import android.Manifest
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.widget.Toast
import androidx.annotation.RequiresPermission
import androidx.navigation.NavDirections
import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.ActivityExecutor
import com.topjohnwu.magisk.arch.BaseUIActivity
import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.utils.Utils
class InstallExternalModuleEvent : ViewEvent(), ActivityExecutor {
@RequiresPermission(allOf = [Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE])
override fun invoke(activity: BaseUIActivity<*, *>) {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "application/zip"
try {
activity.startActivityForResult(intent, Const.ID.FETCH_ZIP)
} catch (e: ActivityNotFoundException) {
Utils.toast(R.string.app_not_found, Toast.LENGTH_SHORT)
}
}
companion object {
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): NavDirections? {
if (requestCode == Const.ID.FETCH_ZIP && resultCode == Activity.RESULT_OK && data != null) {
val data = data.data
if (data != null) {
return MainDirections.actionFlashFragment(data, Const.Value.FLASH_ZIP)
}
}
return null
}
}
}

View File

@ -6,8 +6,11 @@ import android.content.Context
import android.content.Intent
import android.widget.Toast
import androidx.navigation.NavDirections
import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.*
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.base.ActivityResultCallback
import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.core.model.module.Repo
import com.topjohnwu.magisk.utils.Utils
@ -67,27 +70,16 @@ class RecreateEvent : ViewEvent(), ActivityExecutor {
}
}
class RequestFileEvent : ViewEvent(), ActivityExecutor {
class MagiskInstallFileEvent(private val callback: ActivityResultCallback)
: ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseUIActivity<*, *>) {
Intent(Intent.ACTION_GET_CONTENT)
.setType("*/*")
.addCategory(Intent.CATEGORY_OPENABLE)
.also {
try {
activity.startActivityForResult(it, REQUEST_CODE)
Utils.toast(R.string.patch_file_msg, Toast.LENGTH_LONG)
} catch (e: ActivityNotFoundException) {
Utils.toast(R.string.app_not_found, Toast.LENGTH_SHORT)
}
}
}
companion object {
private const val REQUEST_CODE = 10
fun resolve(requestCode: Int, resultCode: Int, data: Intent?) = data
?.takeIf { resultCode == Activity.RESULT_OK }
?.takeIf { requestCode == REQUEST_CODE }
?.data
val intent = Intent(Intent.ACTION_GET_CONTENT).setType("*/*")
try {
activity.startActivityForResult(intent, Const.ID.SELECT_FILE, callback)
Utils.toast(R.string.patch_file_msg, Toast.LENGTH_LONG)
} catch (e: ActivityNotFoundException) {
Utils.toast(R.string.app_not_found, Toast.LENGTH_SHORT)
}
}
}
@ -106,3 +98,22 @@ class AddHomeIconEvent : ViewEvent(), ContextExecutor {
Shortcuts.addHomeIcon(context)
}
}
class SelectModuleEvent : ViewEvent(), FragmentExecutor {
override fun invoke(fragment: BaseUIFragment<*, *>) {
val intent = Intent(Intent.ACTION_GET_CONTENT).setType("application/zip")
try {
fragment.apply {
activity.startActivityForResult(intent, Const.ID.FETCH_ZIP) { code, intent ->
if (code == Activity.RESULT_OK && intent != null) {
intent.data?.also {
MainDirections.actionFlashFragment(it, Const.Value.FLASH_ZIP).navigate()
}
}
}
}
} catch (e: ActivityNotFoundException) {
Utils.toast(R.string.app_not_found, Toast.LENGTH_SHORT)
}
}
}

View File

@ -1,12 +1,10 @@
package com.topjohnwu.magisk.ui.install
import android.content.Intent
import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.core.download.BaseDownloader
import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding
import com.topjohnwu.magisk.events.RequestFileEvent
import com.topjohnwu.magisk.ktx.coroutineScope
import org.koin.androidx.viewmodel.ext.android.viewModel
@ -15,11 +13,6 @@ class InstallFragment : BaseUIFragment<InstallViewModel, FragmentInstallMd2Bindi
override val layoutRes = R.layout.fragment_install_md2
override val viewModel by viewModel<InstallViewModel>()
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
viewModel.data = RequestFileEvent.resolve(requestCode, resultCode, data)
}
override fun onStart() {
super.onStart()
requireActivity().setTitle(R.string.install)

View File

@ -1,5 +1,6 @@
package com.topjohnwu.magisk.ui.install
import android.app.Activity
import android.net.Uri
import androidx.databinding.Bindable
import androidx.lifecycle.viewModelScope
@ -11,7 +12,7 @@ import com.topjohnwu.magisk.core.download.Action
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.data.repository.StringRepository
import com.topjohnwu.magisk.events.RequestFileEvent
import com.topjohnwu.magisk.events.MagiskInstallFileEvent
import com.topjohnwu.magisk.events.dialog.SecondSlotWarningDialog
import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.Shell
@ -35,7 +36,10 @@ class InstallViewModel(
set(value) = set(value, field, { field = it }, BR.method) {
when (it) {
R.id.method_patch -> {
RequestFileEvent().publish()
MagiskInstallFileEvent { code, intent ->
if (code == Activity.RESULT_OK)
data = intent?.data
}.publish()
}
R.id.method_inactive_slot -> {
SecondSlotWarningDialog().publish()

View File

@ -1,6 +1,5 @@
package com.topjohnwu.magisk.ui.module
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
@ -14,7 +13,6 @@ import com.topjohnwu.magisk.arch.ReselectionTarget
import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.core.download.BaseDownloader
import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding
import com.topjohnwu.magisk.events.InstallExternalModuleEvent
import com.topjohnwu.magisk.ktx.hideKeyboard
import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
@ -40,13 +38,6 @@ class ModuleFragment : BaseUIFragment<ModuleViewModel, FragmentModuleMd2Binding>
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
InstallExternalModuleEvent.onActivityResult(requestCode, resultCode, data)?.also {
it.navigate()
}
}
override fun onStart() {
super.onStart()
setHasOptionsMenu(true)

View File

@ -14,7 +14,7 @@ import com.topjohnwu.magisk.core.tasks.RepoUpdater
import com.topjohnwu.magisk.data.database.RepoByNameDao
import com.topjohnwu.magisk.data.database.RepoByUpdatedDao
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.events.InstallExternalModuleEvent
import com.topjohnwu.magisk.events.SelectModuleEvent
import com.topjohnwu.magisk.events.OpenChangelogEvent
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.events.dialog.ModuleInstallDialog
@ -311,7 +311,7 @@ class ModuleViewModel(
}
fun installPressed() = withExternalRW {
InstallExternalModuleEvent().publish()
SelectModuleEvent().publish()
}
fun infoPressed(item: RepoItem) =