diff options
20 files changed, 255 insertions, 257 deletions
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index e847ac8ef5e7..e0097df62078 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -751,6 +751,17 @@ android:visibleToInstantApps="true"> </activity> + <activity android:name=".controls.ui.ControlsActivity" + android:label="@string/quick_controls_title" + android:theme="@style/Theme.ControlsActivity" + android:excludeFromRecents="true" + android:showWhenLocked="true" + android:showForAllUsers="true" + android:launchMode="singleInstance" + android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden" + android:visibleToInstantApps="true"> + </activity> + <receiver android:name=".controls.management.ControlsRequestReceiver" android:exported="true"> <intent-filter> diff --git a/packages/SystemUI/res/drawable/controls_dialog_bg.xml b/packages/SystemUI/res/drawable/controls_dialog_bg.xml deleted file mode 100644 index 1ccb176b8689..000000000000 --- a/packages/SystemUI/res/drawable/controls_dialog_bg.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2021 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - <solid android:color="?android:attr/colorBackground" /> - <corners android:radius="@dimen/notification_corner_radius" /> -</shape> diff --git a/packages/SystemUI/res/layout/controls_detail_dialog.xml b/packages/SystemUI/res/layout/controls_detail_dialog.xml index ee5315ad782f..28fc86372092 100644 --- a/packages/SystemUI/res/layout/controls_detail_dialog.xml +++ b/packages/SystemUI/res/layout/controls_detail_dialog.xml @@ -20,8 +20,8 @@ android:id="@+id/control_detail_root" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginTop="@dimen/controls_activity_view_top_offset" - android:orientation="vertical"> + android:orientation="vertical" + android:background="@android:color/black"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" @@ -30,7 +30,7 @@ <ImageView android:id="@+id/control_detail_close" android:contentDescription="@string/accessibility_desc_close" - android:src="@drawable/ic_close" + android:src="@drawable/ic_arrow_back" android:background="?android:attr/selectableItemBackgroundBorderless" android:tint="@color/control_primary_text" android:layout_width="48dp" @@ -56,7 +56,6 @@ android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" - android:background="@android:color/black" android:orientation="vertical" /> </LinearLayout> diff --git a/packages/SystemUI/res/layout/controls_in_dialog.xml b/packages/SystemUI/res/layout/controls_fullscreen.xml index 983999f9a5f8..1b2d2e2e9c89 100644 --- a/packages/SystemUI/res/layout/controls_in_dialog.xml +++ b/packages/SystemUI/res/layout/controls_fullscreen.xml @@ -20,11 +20,8 @@ android:id="@+id/control_detail_root" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginVertical="@dimen/controls_activity_view_top_offset" - android:layout_marginHorizontal="@dimen/controls_activity_view_side_offset" - android:padding="8dp" android:orientation="vertical" - android:background="@drawable/controls_dialog_bg"> + android:background="@android:color/black"> <com.android.systemui.globalactions.MinHeightScrollView android:layout_width="match_parent" diff --git a/packages/SystemUI/res/layout/controls_with_favorites.xml b/packages/SystemUI/res/layout/controls_with_favorites.xml index b060afdc18e3..9d011482d011 100644 --- a/packages/SystemUI/res/layout/controls_with_favorites.xml +++ b/packages/SystemUI/res/layout/controls_with_favorites.xml @@ -25,8 +25,21 @@ <!-- make sure the header stays centered in the layout by adding a spacer --> <Space + android:id="@+id/controls_spacer" android:layout_width="@dimen/controls_header_menu_size" - android:layout_height="1dp" /> + android:layout_height="1dp" + android:visibility="gone" /> + + <ImageView + android:id="@+id/controls_close" + android:contentDescription="@string/accessibility_desc_close" + android:src="@drawable/ic_close" + android:background="?android:attr/selectableItemBackgroundBorderless" + android:tint="@color/control_primary_text" + android:layout_width="@dimen/controls_header_menu_size" + android:layout_height="@dimen/controls_header_menu_size" + android:padding="12dp" + android:visibility="gone" /> <!-- need to keep this outer view in order to have a correctly sized anchor for the dropdown menu, as well as dropdown background in the right place --> <LinearLayout diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 3c48548cc0fe..fb885cb3fdbe 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -649,6 +649,16 @@ <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item> </style> + <style name="Theme.ControlsActivity" parent="@android:style/Theme.DeviceDefault.NoActionBar"> + <item name="android:windowActivityTransitions">true</item> + <item name="android:windowContentTransitions">false</item> + <item name="android:windowIsTranslucent">false</item> + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:windowAnimationStyle">@null</item> + <item name="android:statusBarColor">@*android:color/transparent</item> + <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item> + </style> + <style name="Theme.CreateUser" parent="@style/Theme.SystemUI"> <item name="android:windowIsTranslucent">true</item> <item name="android:windowBackground">#33000000</item> @@ -660,30 +670,12 @@ <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> </style> - <style name="Theme.SystemUI.Dialog.Control.DetailPanel" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar"> - <item name="android:windowAnimationStyle">@style/Animation.Bottomsheet</item> - <item name="android:windowFullscreen">true</item> - <item name="android:windowIsFloating">false</item> - <item name="android:windowBackground">@null</item> - <item name="android:backgroundDimEnabled">true</item> - </style> - - <style name="Animation.Bottomsheet"> - <item name="android:windowEnterAnimation">@anim/bottomsheet_in</item> - <item name="android:windowExitAnimation">@anim/bottomsheet_out</item> - </style> - - <style name="Theme.SystemUI.Dialog.Control.LockScreen" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar"> - <item name="android:windowAnimationStyle">@style/Animation.ControlDialog</item> - <item name="android:windowFullscreen">true</item> + <style name="Theme.SystemUI.Dialog.Control.DetailPanel" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar"> + <item name="android:windowFullscreen">false</item> <item name="android:windowIsFloating">false</item> - <item name="android:windowBackground">@null</item> - <item name="android:backgroundDimEnabled">true</item> - </style> - - <style name="Animation.ControlDialog"> - <item name="android:windowEnterAnimation">@*android:anim/dialog_enter</item> - <item name="android:windowExitAnimation">@*android:anim/dialog_exit</item> + <item name="android:windowBackground">@android:color/black</item> + <item name="android:backgroundDimEnabled">false</item> + <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item> </style> <style name="Control" /> diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt index fbdeb30d3911..ed625de9dce8 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt @@ -31,6 +31,7 @@ import com.android.systemui.controls.management.ControlsProviderSelectorActivity import com.android.systemui.controls.management.ControlsRequestDialog import com.android.systemui.controls.ui.ControlActionCoordinator import com.android.systemui.controls.ui.ControlActionCoordinatorImpl +import com.android.systemui.controls.ui.ControlsActivity import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.controls.ui.ControlsUiControllerImpl import com.android.systemui.dagger.SysUISingleton @@ -113,4 +114,9 @@ abstract class ControlsModule { abstract fun provideControlsRequestDialog( activity: ControlsRequestDialog ): Activity + + @Binds + @IntoMap + @ClassKey(ControlsActivity::class) + abstract fun provideControlsActivity(activity: ControlsActivity): Activity } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt index fc89783018bc..7dd1d28170b2 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt @@ -32,7 +32,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.controls.CustomIconCache import com.android.systemui.controls.controller.ControlsControllerImpl import com.android.systemui.controls.controller.StructureInfo -import com.android.systemui.controls.ui.ControlsDialog +import com.android.systemui.controls.ui.ControlsActivity import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.globalactions.GlobalActionsComponent import com.android.systemui.settings.CurrentUserTracker @@ -112,7 +112,11 @@ class ControlsEditingActivity @Inject constructor( if (backToGlobalActions) { globalActionsComponent.handleShowGlobalActionsMenu() } else { - ControlsDialog(applicationContext, broadcastDispatcher).show(uiController) + val i = Intent().apply { + component = ComponentName(applicationContext, ControlsActivity::class.java) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + } + startActivity(i) } animateExitAndFinish() } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt index 2d647a907b17..309901443393 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt @@ -40,7 +40,7 @@ import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.TooltipManager import com.android.systemui.controls.controller.ControlsControllerImpl import com.android.systemui.controls.controller.StructureInfo -import com.android.systemui.controls.ui.ControlsDialog +import com.android.systemui.controls.ui.ControlsActivity import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.globalactions.GlobalActionsComponent @@ -352,7 +352,11 @@ class ControlsFavoritingActivity @Inject constructor( if (backToGlobalActions) { globalActionsComponent.handleShowGlobalActionsMenu() } else { - ControlsDialog(applicationContext, broadcastDispatcher).show(uiController) + val i = Intent().apply { + component = ComponentName(applicationContext, ControlsActivity::class.java) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + } + startActivity(i) } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt index d5e41d031eac..fa1c41f01e6c 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt @@ -32,7 +32,7 @@ import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver import com.android.systemui.R import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.controls.controller.ControlsController -import com.android.systemui.controls.ui.ControlsDialog +import com.android.systemui.controls.ui.ControlsActivity import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main @@ -116,7 +116,11 @@ class ControlsProviderSelectorActivity @Inject constructor( if (backToGlobalActions) { globalActionsComponent.handleShowGlobalActionsMenu() } else { - ControlsDialog(applicationContext, broadcastDispatcher).show(uiController) + val i = Intent().apply { + component = ComponentName(applicationContext, ControlsActivity::class.java) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + } + startActivity(i) } animateExitAndFinish() } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt index d06568a7caf9..0db15e83fc93 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt @@ -16,6 +16,7 @@ package com.android.systemui.controls.ui +import android.content.Context import android.service.controls.Control /** @@ -24,8 +25,8 @@ import android.service.controls.Control */ interface ControlActionCoordinator { - // Handle actions launched from GlobalActionsDialog or ControlDialog - var startedFromGlobalActions: Boolean + // If launched from an Activity, continue within this stack + var activityContext: Context? /** * Close any dialogs which may have been open diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt index 6b300f4e07e4..58a5981845c7 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt @@ -18,6 +18,7 @@ package com.android.systemui.controls.ui import android.annotation.MainThread import android.app.Dialog +import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.pm.PackageManager @@ -60,7 +61,7 @@ class ControlActionCoordinatorImpl @Inject constructor( private var pendingAction: Action? = null private var actionsInProgress = mutableSetOf<String>() - override var startedFromGlobalActions: Boolean = true + override var activityContext: Context? = null companion object { private const val RESPONSE_TIMEOUT_IN_MILLIS = 3000L @@ -83,7 +84,7 @@ class ControlActionCoordinatorImpl @Inject constructor( bouncerOrRun(createAction(cvh.cws.ci.controlId, { cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK) if (cvh.usePanel()) { - showDialog(cvh, control.getAppIntent().getIntent()) + showDetail(cvh, control.getAppIntent().getIntent()) } else { cvh.action(CommandAction(templateId)) } @@ -109,7 +110,7 @@ class ControlActionCoordinatorImpl @Inject constructor( // Long press snould only be called when there is valid control state, otherwise ignore cvh.cws.control?.let { cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) - showDialog(cvh, it.getAppIntent().getIntent()) + showDetail(cvh, it.getAppIntent().getIntent()) } }, false /* blockable */)) } @@ -151,10 +152,16 @@ class ControlActionCoordinatorImpl @Inject constructor( activityStarter.dismissKeyguardThenExecute({ Log.d(ControlsUiController.TAG, "Device unlocked, invoking controls action") if (closeDialog) { - if (startedFromGlobalActions) { + activityContext?.let { + val i = Intent().apply { + component = ComponentName(context, ControlsActivity::class.java) + addFlags( + Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + putExtra(ControlsUiController.BACK_TO_GLOBAL_ACTIONS, false) + } + it.startActivity(i) + } ?: run { globalActionsComponent.handleShowGlobalActionsMenu() - } else { - ControlsDialog(context, broadcastDispatcher).show(lazyUiController.get()) } } else { action.invoke() @@ -170,9 +177,9 @@ class ControlActionCoordinatorImpl @Inject constructor( bgExecutor.execute { vibrator.vibrate(effect) } } - private fun showDialog(cvh: ControlViewHolder, intent: Intent) { + private fun showDetail(cvh: ControlViewHolder, intent: Intent) { bgExecutor.execute { - val activities: List<ResolveInfo> = cvh.context.packageManager.queryIntentActivities( + val activities: List<ResolveInfo> = context.packageManager.queryIntentActivities( intent, PackageManager.MATCH_DEFAULT_ONLY ) @@ -180,8 +187,8 @@ class ControlActionCoordinatorImpl @Inject constructor( uiExecutor.execute { // make sure the intent is valid before attempting to open the dialog if (activities.isNotEmpty() && taskViewFactory.isPresent) { - taskViewFactory.get().create(cvh.context, uiExecutor, { - dialog = DetailDialog(cvh, it, intent).also { + taskViewFactory.get().create(context, uiExecutor, { + dialog = DetailDialog(activityContext, it, intent, cvh).also { it.setOnDismissListener { _ -> dialog = null } it.show() } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt new file mode 100644 index 000000000000..a35b792ac7f1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.controls.ui + +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import android.view.WindowInsets +import android.view.WindowInsets.Type + +import com.android.systemui.R +import com.android.systemui.controls.management.ControlsAnimations +import com.android.systemui.util.LifecycleActivity +import javax.inject.Inject + +/** + * Displays Device Controls inside an activity + */ +class ControlsActivity @Inject constructor( + private val uiController: ControlsUiController +) : LifecycleActivity() { + + private lateinit var parent: ViewGroup + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContentView(R.layout.controls_fullscreen) + + requireViewById<ViewGroup>(R.id.control_detail_root).apply { + setOnApplyWindowInsetsListener { + v: View, insets: WindowInsets -> + v.apply { + val l = getPaddingLeft() + val t = getPaddingTop() + val r = getPaddingRight() + setPadding(l, t, r, insets.getInsets(Type.systemBars()).bottom) + } + + WindowInsets.CONSUMED + } + } + } + + override fun onStart() { + super.onStart() + + parent = requireViewById<ViewGroup>(R.id.global_actions_controls) + parent.alpha = 0f + uiController.show(parent, { animateExitAndFinish() }, this) + } + + override fun onResume() { + super.onResume() + + ControlsAnimations.enterAnimation(parent).start() + } + + override fun onBackPressed() { + animateExitAndFinish() + } + + override fun onStop() { + super.onStop() + + uiController.hide() + } + + private fun animateExitAndFinish() { + ControlsAnimations.exitAnimation(parent, { finish() }).start() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialog.kt deleted file mode 100644 index 537334aeb2f7..000000000000 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialog.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.controls.ui - -import android.app.Dialog -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter -import android.view.View -import android.view.ViewGroup -import android.view.WindowManager - -import com.android.systemui.Interpolators -import com.android.systemui.R -import com.android.systemui.broadcast.BroadcastDispatcher -import javax.inject.Inject - -/** - * Show the controls space inside a dialog, as from the lock screen. - */ -class ControlsDialog @Inject constructor( - thisContext: Context, - val broadcastDispatcher: BroadcastDispatcher -) : Dialog(thisContext, R.style.Theme_SystemUI_Dialog_Control_LockScreen) { - - private val receiver = object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - val action = intent.getAction() - if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { - dismiss() - } - } - } - - init { - window.setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) - window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM - or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED) - - setContentView(R.layout.controls_in_dialog) - - requireViewById<ViewGroup>(R.id.control_detail_root).apply { - setOnClickListener { dismiss() } - (getParent() as View).setOnClickListener { dismiss() } - } - } - - fun show( - controller: ControlsUiController - ): ControlsDialog { - super.show() - - val vg = requireViewById<ViewGroup>(com.android.systemui.R.id.global_actions_controls) - vg.alpha = 0f - controller.show(vg, { dismiss() }, false /* startedFromGlobalActions */) - - vg.animate() - .alpha(1f) - .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN) - .setDuration(300) - - val filter = IntentFilter() - filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) - broadcastDispatcher.registerReceiver(receiver, filter) - - return this - } - - override fun dismiss() { - broadcastDispatcher.unregisterReceiver(receiver) - - if (!isShowing()) return - - super.dismiss() - } -} diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt index 20bdf609357e..f86948ee8957 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt @@ -17,6 +17,7 @@ package com.android.systemui.controls.ui import android.content.ComponentName +import android.content.Context import android.service.controls.Control import android.service.controls.actions.ControlAction import android.view.ViewGroup @@ -30,7 +31,7 @@ interface ControlsUiController { public const val BACK_TO_GLOBAL_ACTIONS = "back_to_global_actions" } - fun show(parent: ViewGroup, onDismiss: Runnable, startedFromGlobalActions: Boolean) + fun show(parent: ViewGroup, onDismiss: Runnable, activityContext: Context?) fun hide() /** diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index c94d85aa58c4..0f7f48ff951a 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -148,7 +148,7 @@ class ControlsUiControllerImpl @Inject constructor ( override fun show( parent: ViewGroup, onDismiss: Runnable, - startedFromGlobalActions: Boolean + activityContext: Context? ) { Log.d(ControlsUiController.TAG, "show()") this.parent = parent @@ -156,7 +156,7 @@ class ControlsUiControllerImpl @Inject constructor ( hidden = false retainCache = false - controlActionCoordinator.startedFromGlobalActions = startedFromGlobalActions + controlActionCoordinator.activityContext = activityContext allStructures = controlsController.get().getFavorites() selectedStructure = loadPreference(allStructures) @@ -193,7 +193,7 @@ class ControlsUiControllerImpl @Inject constructor ( controlViewsById.clear() controlsById.clear() - show(parent, onDismiss, controlActionCoordinator.startedFromGlobalActions) + show(parent, onDismiss, controlActionCoordinator.activityContext) val showAnim = ObjectAnimator.ofFloat(parent, "alpha", 0.0f, 1.0f) showAnim.setInterpolator(DecelerateInterpolator(1.0f)) showAnim.setDuration(FADE_IN_MILLIS) @@ -268,7 +268,7 @@ class ControlsUiControllerImpl @Inject constructor ( intent.putExtra(ControlsUiController.EXTRA_ANIMATE, true) intent.putExtra( ControlsUiController.BACK_TO_GLOBAL_ACTIONS, - controlActionCoordinator.startedFromGlobalActions + controlActionCoordinator.activityContext == null ) onDismiss.run() @@ -392,6 +392,17 @@ class ControlsUiControllerImpl @Inject constructor ( val inflater = LayoutInflater.from(context) inflater.inflate(R.layout.controls_with_favorites, parent, true) + if (controlActionCoordinator.activityContext == null) { + parent.requireViewById<View>(R.id.controls_spacer).apply { + visibility = View.VISIBLE + } + } else { + parent.requireViewById<ImageView>(R.id.controls_close).apply { + setOnClickListener { _: View -> onDismiss.run() } + visibility = View.VISIBLE + } + } + val maxColumns = findMaxColumns() val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup @@ -502,6 +513,8 @@ class ControlsUiControllerImpl @Inject constructor ( override fun hide() { hidden = true + controlActionCoordinator.activityContext = null + closeDialogs(true) controlsController.get().unsubscribe() diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt index 020694d89fce..9c788df362de 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt @@ -22,8 +22,8 @@ import android.app.ActivityTaskManager.INVALID_TASK_ID import android.app.Dialog import android.app.PendingIntent import android.content.ComponentName +import android.content.Context import android.content.Intent -import android.provider.Settings import android.view.View import android.view.ViewGroup import android.view.WindowInsets @@ -35,18 +35,20 @@ import com.android.systemui.R import com.android.wm.shell.TaskView /** - * A dialog that provides an {@link ActivityView}, allowing the application to provide + * A dialog that provides an {@link TaskView}, allowing the application to provide * additional information and actions pertaining to a {@link android.service.controls.Control}. * The activity being launched is specified by {@link android.service.controls.Control#getAppIntent}. */ class DetailDialog( - val cvh: ControlViewHolder, - val activityView: TaskView, - val intent: Intent -) : Dialog(cvh.context, R.style.Theme_SystemUI_Dialog_Control_DetailPanel) { - + val activityContext: Context?, + val taskView: TaskView, + val intent: Intent, + val cvh: ControlViewHolder +) : Dialog( + activityContext ?: cvh.context, + R.style.Theme_SystemUI_Dialog_Control_DetailPanel +) { companion object { - private const val PANEL_TOP_OFFSET = "systemui.controls_panel_top_offset" /* * Indicate to the activity that it is being rendered in a bottomsheet, and they * should optimize the layout for a smaller space. @@ -71,10 +73,19 @@ class DetailDialog( launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT) launchIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) - activityView.startActivity( - PendingIntent.getActivity(context, 0, launchIntent, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE), - null, ActivityOptions.makeBasic()) + val options = activityContext?.let { + ActivityOptions.makeCustomAnimation( + it, + 0 /* enterResId */, + 0 /* exitResId */ + ) + } ?: ActivityOptions.makeBasic() + taskView.startActivity( + PendingIntent.getActivity(context, 0, launchIntent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE), + null, + options + ) } override fun onTaskRemovalStarted(taskId: Int) { @@ -92,7 +103,10 @@ class DetailDialog( } init { - window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY) + if (activityContext == null) { + window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY) + } + // To pass touches to the task inside TaskView. window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL) window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY) @@ -100,7 +114,7 @@ class DetailDialog( setContentView(R.layout.controls_detail_dialog) requireViewById<ViewGroup>(R.id.controls_activity_view).apply { - addView(activityView) + addView(taskView) } requireViewById<ImageView>(R.id.control_detail_close).apply { @@ -120,48 +134,34 @@ class DetailDialog( // consume all insets to achieve slide under effect window.getDecorView().setOnApplyWindowInsetsListener { - _: View, insets: WindowInsets -> - activityView.apply { + v: View, insets: WindowInsets -> + taskView.apply { val l = getPaddingLeft() val t = getPaddingTop() val r = getPaddingRight() setPadding(l, t, r, insets.getInsets(Type.systemBars()).bottom) } - WindowInsets.CONSUMED - } - - requireViewById<ViewGroup>(R.id.control_detail_root).apply { - // use flag only temporarily for testing - val resolver = cvh.context.contentResolver - val defaultOffsetInPx = cvh.context.resources - .getDimensionPixelSize(R.dimen.controls_activity_view_top_offset) - val offsetInPx = Settings.Secure.getInt(resolver, PANEL_TOP_OFFSET, defaultOffsetInPx) - - val lp = getLayoutParams() as ViewGroup.MarginLayoutParams - lp.topMargin = offsetInPx - setLayoutParams(lp) + val l = v.getPaddingLeft() + val b = v.getPaddingBottom() + val r = v.getPaddingRight() + v.setPadding(l, insets.getInsets(Type.systemBars()).top, r, b) - setOnClickListener { dismiss() } - (getParent() as View).setOnClickListener { dismiss() } + WindowInsets.CONSUMED } if (ScreenDecorationsUtils.supportsRoundedCornersOnWindows(context.getResources())) { val cornerRadius = context.resources .getDimensionPixelSize(R.dimen.controls_activity_view_corner_radius) - activityView.setCornerRadius(cornerRadius.toFloat()) + taskView.setCornerRadius(cornerRadius.toFloat()) } - } - - override fun show() { - activityView.setListener(cvh.uiExecutor, stateCallback) - super.show() + taskView.setListener(cvh.uiExecutor, stateCallback) } override fun dismiss() { if (!isShowing()) return - activityView.release() + taskView.release() super.dismiss() } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 1f67276bfbae..461a7303c184 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -2220,7 +2220,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private void showControls(ControlsUiController controller) { mControlsUiController = controller; mControlsUiController.show(mControlsView, this::dismissForControlsActivity, - true /* startedFromGlobalActions */); + null /* activityContext */); } private boolean isWalletViewAvailable() { @@ -2449,7 +2449,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, }); if (mControlsUiController != null) { mControlsUiController.show(mControlsView, this::dismissForControlsActivity, - true /* startedFromGlobalActions */); + null /* activityContext */); } mBackgroundDrawable.setAlpha(0); @@ -2625,7 +2625,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mGlobalActionsLayout.updateList(); if (mControlsUiController != null) { mControlsUiController.show(mControlsView, this::dismissForControlsActivity, - true /* startedFromGlobalActions */); + null /* activityContext */); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt index 3b9f5dc8ea03..257d6a7abda1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt @@ -16,6 +16,7 @@ package com.android.systemui.qs.tiles +import android.content.ComponentName import android.content.Intent import android.os.Handler import android.os.Looper @@ -27,7 +28,8 @@ import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.dagger.ControlsComponent import com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE import com.android.systemui.controls.management.ControlsListingController -import com.android.systemui.controls.ui.ControlsDialog +import com.android.systemui.controls.ui.ControlsActivity +import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.ActivityStarter @@ -40,7 +42,6 @@ import com.android.systemui.statusbar.FeatureFlags import com.android.systemui.util.settings.GlobalSettings import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject -import javax.inject.Provider class DeviceControlsTile @Inject constructor( host: QSHost, @@ -52,7 +53,6 @@ class DeviceControlsTile @Inject constructor( qsLogger: QSLogger, private val controlsComponent: ControlsComponent, private val featureFlags: FeatureFlags, - private val dialogProvider: Provider<ControlsDialog>, globalSettings: GlobalSettings ) : QSTileImpl<QSTile.State>( host, @@ -72,7 +72,6 @@ class DeviceControlsTile @Inject constructor( private var hasControlsApps = AtomicBoolean(false) private val intent = Intent(Settings.ACTION_DEVICE_CONTROLS_SETTINGS) - private var controlsDialog: ControlsDialog? = null private val icon = ResourceIcon.get(R.drawable.ic_device_light) private val listingCallback = object : ControlsListingController.ControlsListingCallback { @@ -102,27 +101,19 @@ class DeviceControlsTile @Inject constructor( } override fun handleDestroy() { - dismissDialog() super.handleDestroy() } - private fun createDialog() { - if (controlsDialog?.isShowing != true) { - controlsDialog = dialogProvider.get() - } - } - - private fun dismissDialog() { - controlsDialog?.dismiss()?.also { - controlsDialog = null - } - } - override fun handleClick() { if (state.state == Tile.STATE_ACTIVE) { mUiHandler.post { - createDialog() - controlsDialog?.show(controlsComponent.getControlsUiController().get()) + mHost.collapsePanels() + val i = Intent().apply { + component = ComponentName(mContext, ControlsActivity::class.java) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + putExtra(ControlsUiController.BACK_TO_GLOBAL_ACTIONS, false) + } + mContext.startActivity(i) } } } @@ -133,9 +124,6 @@ class DeviceControlsTile @Inject constructor( state.contentDescription = state.label state.icon = icon if (controlsComponent.isEnabled() && hasControlsApps.get()) { - if (controlsDialog == null) { - mUiHandler.post(this::createDialog) - } if (controlsComponent.getVisibility() == AVAILABLE) { state.state = Tile.STATE_ACTIVE state.secondaryLabel = "" @@ -146,7 +134,6 @@ class DeviceControlsTile @Inject constructor( state.stateDescription = state.secondaryLabel } else { state.state = Tile.STATE_UNAVAILABLE - dismissDialog() } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt index ccd9548b269f..9363b24817e6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt @@ -17,6 +17,8 @@ package com.android.systemui.qs.tiles import android.os.Handler +import android.content.Context +import android.content.Intent import android.provider.Settings import android.service.quicksettings.Tile import android.testing.AndroidTestingRunner @@ -30,7 +32,6 @@ import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.controller.ControlsController import com.android.systemui.controls.dagger.ControlsComponent import com.android.systemui.controls.management.ControlsListingController -import com.android.systemui.controls.ui.ControlsDialog import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -50,7 +51,9 @@ import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.`when` +import org.mockito.Mockito.doNothing import org.mockito.Mockito.never +import org.mockito.Mockito.spy import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import java.util.Optional @@ -80,8 +83,6 @@ class DeviceControlsTileTest : SysuiTestCase() { private lateinit var controlsController: ControlsController @Mock private lateinit var featureFlags: FeatureFlags - @Mock - private lateinit var controlsDialog: ControlsDialog private lateinit var globalSettings: GlobalSettings @Mock private lateinit var serviceInfo: ControlsServiceInfo @@ -95,6 +96,7 @@ class DeviceControlsTileTest : SysuiTestCase() { private lateinit var tile: DeviceControlsTile private lateinit var secureSettings: SecureSettings + private lateinit var spiedContext: Context private var featureEnabled = true @Before @@ -103,7 +105,9 @@ class DeviceControlsTileTest : SysuiTestCase() { testableLooper = TestableLooper.get(this) secureSettings = FakeSettings() - `when`(qsHost.context).thenReturn(mContext) + spiedContext = spy(mContext) + doNothing().`when`(spiedContext).startActivity(any(Intent::class.java)) + `when`(qsHost.context).thenReturn(spiedContext) `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) `when`(controlsController.available).thenReturn(true) `when`(controlsComponent.isEnabled()).thenReturn(true) @@ -276,7 +280,7 @@ class DeviceControlsTileTest : SysuiTestCase() { tile.click() testableLooper.processAllMessages() - verify(controlsDialog, never()).show(any(ControlsUiController::class.java)) + verify(spiedContext, never()).startActivity(any(Intent::class.java)) } @Test @@ -293,7 +297,7 @@ class DeviceControlsTileTest : SysuiTestCase() { tile.click() testableLooper.processAllMessages() - verify(controlsDialog).show(controlsUiController) + verify(spiedContext).startActivity(any(Intent::class.java)) } @Test @@ -311,25 +315,7 @@ class DeviceControlsTileTest : SysuiTestCase() { tile.click() testableLooper.processAllMessages() - verify(controlsDialog, never()).show(any(ControlsUiController::class.java)) - } - - @Test - fun testDialogDismissedOnDestroy() { - verify(controlsListingController).observe( - any(LifecycleOwner::class.java), - capture(listingCallbackCaptor) - ) - - listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) - testableLooper.processAllMessages() - - tile.click() - testableLooper.processAllMessages() - - tile.destroy() - testableLooper.processAllMessages() - verify(controlsDialog).dismiss() + verify(spiedContext, never()).startActivity(any(Intent::class.java)) } private fun createTile(): DeviceControlsTile { @@ -343,7 +329,6 @@ class DeviceControlsTileTest : SysuiTestCase() { qsLogger, controlsComponent, featureFlags, - { controlsDialog }, globalSettings ) } |