diff --git a/lawnchair/src/app/lawnchair/LawnchairLauncher.kt b/lawnchair/src/app/lawnchair/LawnchairLauncher.kt index 9883b7c2d9..ab19e673bf 100644 --- a/lawnchair/src/app/lawnchair/LawnchairLauncher.kt +++ b/lawnchair/src/app/lawnchair/LawnchairLauncher.kt @@ -17,10 +17,23 @@ package app.lawnchair import android.content.Context +import android.content.Intent +import android.content.IntentSender import android.os.Bundle +import android.os.Handler +import android.os.Looper import android.view.ViewTreeObserver import androidx.activity.OnBackPressedDispatcher import androidx.activity.OnBackPressedDispatcherOwner +import androidx.activity.result.ActivityResultRegistry +import androidx.activity.result.ActivityResultRegistryOwner +import androidx.activity.result.IntentSenderRequest +import androidx.activity.result.contract.ActivityResultContract +import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult +import androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult +import androidx.core.app.ActivityCompat +import androidx.core.app.ActivityOptionsCompat import androidx.core.graphics.ColorUtils import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat @@ -56,10 +69,79 @@ import java.util.stream.Stream import kotlin.math.roundToInt class LawnchairLauncher : QuickstepLauncher(), LifecycleOwner, - SavedStateRegistryOwner, OnBackPressedDispatcherOwner { + SavedStateRegistryOwner, ActivityResultRegistryOwner, OnBackPressedDispatcherOwner { private val lifecycleRegistry = LifecycleRegistry(this) private val savedStateRegistryController = SavedStateRegistryController.create(this) + private val activityResultRegistry = object : ActivityResultRegistry() { + override fun onLaunch( + requestCode: Int, + contract: ActivityResultContract, + input: I, + options: ActivityOptionsCompat? + ) { + val activity = this@LawnchairLauncher + + // Immediate result path + val synchronousResult = contract.getSynchronousResult(activity, input) + if (synchronousResult != null) { + Handler(Looper.getMainLooper()).post { + dispatchResult( + requestCode, + synchronousResult.value + ) + } + return + } + + // Start activity path + val intent = contract.createIntent(activity, input) + var optionsBundle: Bundle? = null + // If there are any extras, we should defensively set the classLoader + if (intent.extras != null && intent.extras!!.classLoader == null) { + intent.setExtrasClassLoader(activity.classLoader) + } + if (intent.hasExtra(StartActivityForResult.EXTRA_ACTIVITY_OPTIONS_BUNDLE)) { + optionsBundle = + intent.getBundleExtra(StartActivityForResult.EXTRA_ACTIVITY_OPTIONS_BUNDLE) + intent.removeExtra(StartActivityForResult.EXTRA_ACTIVITY_OPTIONS_BUNDLE) + } else if (options != null) { + optionsBundle = options.toBundle() + } + if (RequestMultiplePermissions.ACTION_REQUEST_PERMISSIONS == intent.action) { + // requestPermissions path + var permissions = + intent.getStringArrayExtra(RequestMultiplePermissions.EXTRA_PERMISSIONS) + if (permissions == null) { + permissions = arrayOfNulls(0) + } + ActivityCompat.requestPermissions(activity, permissions, requestCode) + } else if (StartIntentSenderForResult.ACTION_INTENT_SENDER_REQUEST == intent.action) { + val request: IntentSenderRequest = + intent.getParcelableExtra(StartIntentSenderForResult.EXTRA_INTENT_SENDER_REQUEST)!! + try { + // startIntentSenderForResult path + ActivityCompat.startIntentSenderForResult( + activity, request.intentSender, + requestCode, request.fillInIntent, request.flagsMask, + request.flagsValues, 0, optionsBundle + ) + } catch (e: IntentSender.SendIntentException) { + Handler(Looper.getMainLooper()).post { + dispatchResult( + requestCode, RESULT_CANCELED, + Intent() + .setAction(StartIntentSenderForResult.ACTION_INTENT_SENDER_REQUEST) + .putExtra(StartIntentSenderForResult.EXTRA_SEND_INTENT_EXCEPTION, e) + ) + } + } + } else { + // startActivityForResult path + ActivityCompat.startActivityForResult(activity, intent, requestCode, optionsBundle) + } + } + } private val _onBackPressedDispatcher = OnBackPressedDispatcher { super.onBackPressed() } @@ -209,6 +291,12 @@ class LawnchairLauncher : QuickstepLauncher(), LifecycleOwner, savedStateRegistryController.performSave(outState) } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + if (!activityResultRegistry.dispatchResult(requestCode, resultCode, data)) { + super.onActivityResult(requestCode, resultCode, data) + } + } + override fun getLifecycle(): Lifecycle { return lifecycleRegistry } @@ -217,6 +305,10 @@ class LawnchairLauncher : QuickstepLauncher(), LifecycleOwner, return savedStateRegistryController.savedStateRegistry } + override fun getActivityResultRegistry(): ActivityResultRegistry { + return activityResultRegistry + } + override fun getOnBackPressedDispatcher(): OnBackPressedDispatcher { return _onBackPressedDispatcher } diff --git a/lawnchair/src/app/lawnchair/override/CustomizeDialog.kt b/lawnchair/src/app/lawnchair/override/CustomizeDialog.kt index 86c3f4397d..9d4854783a 100644 --- a/lawnchair/src/app/lawnchair/override/CustomizeDialog.kt +++ b/lawnchair/src/app/lawnchair/override/CustomizeDialog.kt @@ -1,6 +1,9 @@ package app.lawnchair.override +import android.app.Activity import android.graphics.drawable.Drawable +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.Image import androidx.compose.foundation.clickable @@ -96,12 +99,18 @@ fun CustomizeDialog( fun CustomizeAppDialog( icon: Drawable, defaultTitle: String, - componentKey: ComponentKey + componentKey: ComponentKey, + onClose: () -> Unit ) { val prefs = preferenceManager() val context = LocalContext.current var title by remember { mutableStateOf("") } + val request = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { + if (it.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult + onClose() + } + DisposableEffect(key1 = null) { title = prefs.customAppName[componentKey] ?: defaultTitle onDispose { @@ -127,7 +136,7 @@ fun CustomizeAppDialog( launchSelectIcon = { if (prefs.enableIconSelection.get()) { val destination = "/${Routes.SELECT_ICON}/$componentKey/" - context.startActivity(PreferenceActivity.createIntent(context, destination)) + request.launch(PreferenceActivity.createIntent(context, destination)) } } ) { diff --git a/lawnchair/src/app/lawnchair/ui/popup/LawnchairShortcut.kt b/lawnchair/src/app/lawnchair/ui/popup/LawnchairShortcut.kt index ad5f4db816..83e4f7f74e 100644 --- a/lawnchair/src/app/lawnchair/ui/popup/LawnchairShortcut.kt +++ b/lawnchair/src/app/lawnchair/ui/popup/LawnchairShortcut.kt @@ -50,7 +50,8 @@ class LawnchairShortcut { CustomizeAppDialog( icon = icon, defaultTitle = defaultTitle, - componentKey = key + componentKey = key, + onClose = { close(true) } ) } } diff --git a/lawnchair/src/app/lawnchair/ui/preferences/SelectIconPreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/SelectIconPreference.kt index 37072e3f06..6159aedd63 100644 --- a/lawnchair/src/app/lawnchair/ui/preferences/SelectIconPreference.kt +++ b/lawnchair/src/app/lawnchair/ui/preferences/SelectIconPreference.kt @@ -62,7 +62,10 @@ fun SelectIconPreference(componentKey: ComponentKey) { OnResult { item -> scope.launch { repo.setOverride(componentKey, item) - (context as Activity).finish() + (context as Activity).let { + it.setResult(Activity.RESULT_OK) + it.finish() + } } } @@ -77,7 +80,10 @@ fun SelectIconPreference(componentKey: ComponentKey) { onClick = { scope.launch { repo.deleteOverride(componentKey) - (context as Activity).finish() + (context as Activity).let { + it.setResult(Activity.RESULT_OK) + it.finish() + } } } )