Commit fc19b502 authored by topjohnwu's avatar topjohnwu

Cleanup ActivityResult callbacks

parent 333fe6da
package com.topjohnwu.magisk.arch package com.topjohnwu.magisk.arch
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.KeyEvent import android.view.KeyEvent
import android.view.View import android.view.View
...@@ -41,11 +40,6 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> : ...@@ -41,11 +40,6 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
AppCompatDelegate.setDefaultNightMode(theme) 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?) { override fun onCreate(savedInstanceState: Bundle?) {
setTheme(themeRes) setTheme(themeRes)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
......
...@@ -17,7 +17,7 @@ import com.topjohnwu.magisk.ktx.startAnimations ...@@ -17,7 +17,7 @@ import com.topjohnwu.magisk.ktx.startAnimations
abstract class BaseUIFragment<VM : BaseViewModel, Binding : ViewDataBinding> : abstract class BaseUIFragment<VM : BaseViewModel, Binding : ViewDataBinding> :
Fragment(), BaseUIComponent<VM> { Fragment(), BaseUIComponent<VM> {
protected val activity get() = requireActivity() as BaseUIActivity<*, *> val activity get() = requireActivity() as BaseUIActivity<*, *>
protected lateinit var binding: Binding protected lateinit var binding: Binding
protected abstract val layoutRes: Int protected abstract val layoutRes: Int
......
package com.topjohnwu.magisk.arch package com.topjohnwu.magisk.arch
import android.content.Context import android.content.Context
import androidx.fragment.app.Fragment
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
/** /**
...@@ -23,5 +22,5 @@ interface ActivityExecutor { ...@@ -23,5 +22,5 @@ interface ActivityExecutor {
} }
interface FragmentExecutor { interface FragmentExecutor {
operator fun invoke(fragment: Fragment) operator fun invoke(fragment: BaseUIFragment<*, *>)
} }
...@@ -33,12 +33,12 @@ object Const { ...@@ -33,12 +33,12 @@ object Const {
object ID { object ID {
const val FETCH_ZIP = 2 const val FETCH_ZIP = 2
const val SELECT_BOOT = 3 const val SELECT_FILE = 3
const val MAX_ACTIVITY_RESULT = 10
// notifications // notifications
const val MAGISK_UPDATE_NOTIFICATION_ID = 4 const val MAGISK_UPDATE_NOTIFICATION_ID = 4
const val APK_UPDATE_NOTIFICATION_ID = 5 const val APK_UPDATE_NOTIFICATION_ID = 5
const val DTBO_NOTIFICATION_ID = 7
const val HIDE_MANAGER_NOTIFICATION_ID = 8 const val HIDE_MANAGER_NOTIFICATION_ID = 8
const val UPDATE_NOTIFICATION_CHANNEL = "update" const val UPDATE_NOTIFICATION_CHANNEL = "update"
const val PROGRESS_NOTIFICATION_CHANNEL = "progress" const val PROGRESS_NOTIFICATION_CHANNEL = "progress"
......
...@@ -8,22 +8,24 @@ import android.content.pm.PackageManager ...@@ -8,22 +8,24 @@ import android.content.pm.PackageManager
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Build import android.os.Build
import android.widget.Toast import android.widget.Toast
import androidx.annotation.CallSuper
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.collection.SparseArrayCompat import androidx.collection.SparseArrayCompat
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.utils.currentLocale import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.core.wrap import com.topjohnwu.magisk.core.wrap
import com.topjohnwu.magisk.ktx.set import com.topjohnwu.magisk.ktx.set
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import kotlin.random.Random import kotlin.random.Random
typealias RequestCallback = BaseActivity.(Int, Intent?) -> Unit typealias ActivityResultCallback = BaseActivity.(Int, Intent?) -> Unit
abstract class BaseActivity : AppCompatActivity() { abstract class BaseActivity : AppCompatActivity() {
private val resultCallbacks by lazy { SparseArrayCompat<RequestCallback>() } private val resultCallbacks by lazy { SparseArrayCompat<ActivityResultCallback>() }
override fun applyOverrideConfiguration(config: Configuration?) { override fun applyOverrideConfiguration(config: Configuration?) {
// Force applying our preferred local // Force applying our preferred local
...@@ -38,8 +40,7 @@ abstract class BaseActivity : AppCompatActivity() { ...@@ -38,8 +40,7 @@ abstract class BaseActivity : AppCompatActivity() {
fun withPermission(permission: String, builder: PermissionRequestBuilder.() -> Unit) { fun withPermission(permission: String, builder: PermissionRequestBuilder.() -> Unit) {
val request = PermissionRequestBuilder().apply(builder).build() val request = PermissionRequestBuilder().apply(builder).build()
if (permission == Manifest.permission.WRITE_EXTERNAL_STORAGE && if (permission == Manifest.permission.WRITE_EXTERNAL_STORAGE && Build.VERSION.SDK_INT >= 29) {
Build.VERSION.SDK_INT >= 29) {
// We do not need external rw on 29+ // We do not need external rw on 29+
request.onSuccess() request.onSuccess()
return return
...@@ -48,7 +49,10 @@ abstract class BaseActivity : AppCompatActivity() { ...@@ -48,7 +49,10 @@ abstract class BaseActivity : AppCompatActivity() {
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) { if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
request.onSuccess() request.onSuccess()
} else { } else {
val requestCode = Random.nextInt(256, 512) var requestCode: Int
do {
requestCode = Random.nextInt(Const.ID.MAX_ACTIVITY_RESULT + 1, 1 shl 15)
} while (!resultCallbacks.containsKey(requestCode))
resultCallbacks[requestCode] = { result, _ -> resultCallbacks[requestCode] = { result, _ ->
if (result > 0) if (result > 0)
request.onSuccess() request.onSuccess()
...@@ -79,16 +83,17 @@ abstract class BaseActivity : AppCompatActivity() { ...@@ -79,16 +83,17 @@ abstract class BaseActivity : AppCompatActivity() {
} }
@CallSuper
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
resultCallbacks[requestCode]?.also { resultCallbacks[requestCode]?.also { callback ->
resultCallbacks.remove(requestCode) resultCallbacks.remove(requestCode)
it(this, resultCode, data) callback(this, resultCode, data)
} }
} }
fun startActivityForResult(intent: Intent, requestCode: Int, listener: RequestCallback) { fun startActivityForResult(intent: Intent, requestCode: Int, callback: ActivityResultCallback) {
resultCallbacks[requestCode] = listener resultCallbacks[requestCode] = callback
try { try {
startActivityForResult(intent, requestCode) startActivityForResult(intent, requestCode)
} catch (e: ActivityNotFoundException) { } catch (e: ActivityNotFoundException) {
......
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
}
}
}
...@@ -6,8 +6,11 @@ import android.content.Context ...@@ -6,8 +6,11 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.widget.Toast import android.widget.Toast
import androidx.navigation.NavDirections import androidx.navigation.NavDirections
import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.* 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.base.BaseActivity
import com.topjohnwu.magisk.core.model.module.Repo import com.topjohnwu.magisk.core.model.module.Repo
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
...@@ -67,28 +70,17 @@ class RecreateEvent : ViewEvent(), ActivityExecutor { ...@@ -67,28 +70,17 @@ class RecreateEvent : ViewEvent(), ActivityExecutor {
} }
} }
class RequestFileEvent : ViewEvent(), ActivityExecutor { class MagiskInstallFileEvent(private val callback: ActivityResultCallback)
: ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseUIActivity<*, *>) { override fun invoke(activity: BaseUIActivity<*, *>) {
Intent(Intent.ACTION_GET_CONTENT) val intent = Intent(Intent.ACTION_GET_CONTENT).setType("*/*")
.setType("*/*")
.addCategory(Intent.CATEGORY_OPENABLE)
.also {
try { try {
activity.startActivityForResult(it, REQUEST_CODE) activity.startActivityForResult(intent, Const.ID.SELECT_FILE, callback)
Utils.toast(R.string.patch_file_msg, Toast.LENGTH_LONG) Utils.toast(R.string.patch_file_msg, Toast.LENGTH_LONG)
} catch (e: ActivityNotFoundException) { } catch (e: ActivityNotFoundException) {
Utils.toast(R.string.app_not_found, Toast.LENGTH_SHORT) 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
}
} }
class NavigationEvent( class NavigationEvent(
...@@ -106,3 +98,22 @@ class AddHomeIconEvent : ViewEvent(), ContextExecutor { ...@@ -106,3 +98,22 @@ class AddHomeIconEvent : ViewEvent(), ContextExecutor {
Shortcuts.addHomeIcon(context) 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)
}
}
}
package com.topjohnwu.magisk.ui.install package com.topjohnwu.magisk.ui.install
import android.content.Intent
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseUIFragment import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.core.download.BaseDownloader import com.topjohnwu.magisk.core.download.BaseDownloader
import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding
import com.topjohnwu.magisk.events.RequestFileEvent
import com.topjohnwu.magisk.ktx.coroutineScope import com.topjohnwu.magisk.ktx.coroutineScope
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
...@@ -15,11 +13,6 @@ class InstallFragment : BaseUIFragment<InstallViewModel, FragmentInstallMd2Bindi ...@@ -15,11 +13,6 @@ class InstallFragment : BaseUIFragment<InstallViewModel, FragmentInstallMd2Bindi
override val layoutRes = R.layout.fragment_install_md2 override val layoutRes = R.layout.fragment_install_md2
override val viewModel by viewModel<InstallViewModel>() 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() { override fun onStart() {
super.onStart() super.onStart()
requireActivity().setTitle(R.string.install) requireActivity().setTitle(R.string.install)
......
package com.topjohnwu.magisk.ui.install package com.topjohnwu.magisk.ui.install
import android.app.Activity
import android.net.Uri import android.net.Uri
import androidx.databinding.Bindable import androidx.databinding.Bindable
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
...@@ -11,7 +12,7 @@ import com.topjohnwu.magisk.core.download.Action ...@@ -11,7 +12,7 @@ import com.topjohnwu.magisk.core.download.Action
import com.topjohnwu.magisk.core.download.DownloadService import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.core.download.Subject import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.data.repository.StringRepository 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.events.dialog.SecondSlotWarningDialog
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
...@@ -35,7 +36,10 @@ class InstallViewModel( ...@@ -35,7 +36,10 @@ class InstallViewModel(
set(value) = set(value, field, { field = it }, BR.method) { set(value) = set(value, field, { field = it }, BR.method) {
when (it) { when (it) {
R.id.method_patch -> { R.id.method_patch -> {
RequestFileEvent().publish() MagiskInstallFileEvent { code, intent ->
if (code == Activity.RESULT_OK)
data = intent?.data
}.publish()
} }
R.id.method_inactive_slot -> { R.id.method_inactive_slot -> {
SecondSlotWarningDialog().publish() SecondSlotWarningDialog().publish()
......
package com.topjohnwu.magisk.ui.module package com.topjohnwu.magisk.ui.module
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
...@@ -14,7 +13,6 @@ import com.topjohnwu.magisk.arch.ReselectionTarget ...@@ -14,7 +13,6 @@ import com.topjohnwu.magisk.arch.ReselectionTarget
import com.topjohnwu.magisk.arch.ViewEvent import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.core.download.BaseDownloader import com.topjohnwu.magisk.core.download.BaseDownloader
import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding
import com.topjohnwu.magisk.events.InstallExternalModuleEvent
import com.topjohnwu.magisk.ktx.hideKeyboard import com.topjohnwu.magisk.ktx.hideKeyboard
import com.topjohnwu.magisk.ui.MainActivity import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener import com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
...@@ -40,13 +38,6 @@ class ModuleFragment : BaseUIFragment<ModuleViewModel, FragmentModuleMd2Binding> ...@@ -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() { override fun onStart() {
super.onStart() super.onStart()
setHasOptionsMenu(true) setHasOptionsMenu(true)
......
...@@ -14,7 +14,7 @@ import com.topjohnwu.magisk.core.tasks.RepoUpdater ...@@ -14,7 +14,7 @@ import com.topjohnwu.magisk.core.tasks.RepoUpdater
import com.topjohnwu.magisk.data.database.RepoByNameDao import com.topjohnwu.magisk.data.database.RepoByNameDao
import com.topjohnwu.magisk.data.database.RepoByUpdatedDao import com.topjohnwu.magisk.data.database.RepoByUpdatedDao
import com.topjohnwu.magisk.databinding.RvItem 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.OpenChangelogEvent
import com.topjohnwu.magisk.events.SnackbarEvent import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.events.dialog.ModuleInstallDialog import com.topjohnwu.magisk.events.dialog.ModuleInstallDialog
...@@ -311,7 +311,7 @@ class ModuleViewModel( ...@@ -311,7 +311,7 @@ class ModuleViewModel(
} }
fun installPressed() = withExternalRW { fun installPressed() = withExternalRW {
InstallExternalModuleEvent().publish() SelectModuleEvent().publish()
} }
fun infoPressed(item: RepoItem) = fun infoPressed(item: RepoItem) =
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment