diff options
| author | 2023-09-05 17:27:01 +0100 | |
|---|---|---|
| committer | 2023-09-25 11:27:19 +0000 | |
| commit | 70eef43e2e8d051b742c62afd1afa38e3dfefb77 (patch) | |
| tree | 7cc5085999e799ba7ac9fdb09def1b4bb9ee16a3 | |
| parent | 6324143df3de569a847338f19c4e6329477391d4 (diff) | |
Fix TaskView usage in DetailsDialog
We've done some changes to how we deal with the TaskView in
PanelTaskViewController to address issues with the Home Panel. This CL
migrates those changes to DetailsDialog, which to improves TaskView behaviour and fixes the issue.
Test: manual: open Device Controls, tap on a camera control, long tap outside of
the TaskView.
Test: atest DetailDialogTest
Fixes: 282144424
Change-Id: If583934773a6a8e728475aa0eb4a0b54563a89e3
3 files changed, 64 insertions, 72 deletions
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 9b93522b2d5f..e8a84449566d 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt @@ -18,26 +18,25 @@ package com.android.systemui.controls.ui import android.app.Activity import android.app.ActivityOptions -import android.app.ActivityTaskManager -import android.app.ActivityTaskManager.INVALID_TASK_ID import android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED import android.app.Dialog import android.app.PendingIntent import android.content.ComponentName import android.content.Context import android.content.Intent -import android.graphics.Rect import android.view.View import android.view.ViewGroup import android.view.WindowInsets import android.view.WindowInsets.Type import android.view.WindowManager import android.widget.ImageView +import androidx.annotation.VisibleForTesting import com.android.internal.policy.ScreenDecorationsUtils import com.android.systemui.res.R import com.android.systemui.broadcast.BroadcastSender import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.util.boundsOnScreen import com.android.wm.shell.taskview.TaskView /** @@ -65,8 +64,8 @@ class DetailDialog( private const val EXTRA_USE_PANEL = "controls.DISPLAY_IN_PANEL" } - var detailTaskId = INVALID_TASK_ID private lateinit var taskViewContainer: View + private lateinit var controlDetailRoot: View private val taskWidthPercentWidth = activityContext.resources.getFloat( R.dimen.controls_task_view_width_percentage ) @@ -79,12 +78,7 @@ class DetailDialog( addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) } - fun removeDetailTask() { - if (detailTaskId == INVALID_TASK_ID) return - ActivityTaskManager.getInstance().removeTask(detailTaskId) - detailTaskId = INVALID_TASK_ID - } - + @VisibleForTesting val stateCallback = object : TaskView.Listener { override fun onInitialized() { taskViewContainer.apply { @@ -98,33 +92,29 @@ class DetailDialog( activityContext, 0 /* enterResId */, 0 /* exitResId */ - ).setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED) - options.isPendingIntentBackgroundActivityLaunchAllowedByPermission = true + ).apply { + pendingIntentBackgroundActivityStartMode = MODE_BACKGROUND_ACTIVITY_START_ALLOWED + isPendingIntentBackgroundActivityLaunchAllowedByPermission = true + taskAlwaysOnTop = true + } taskView.startActivity( pendingIntent, fillInIntent, options, - getTaskViewBounds() + taskView.boundsOnScreen, ) } override fun onTaskRemovalStarted(taskId: Int) { - detailTaskId = INVALID_TASK_ID - dismiss() + taskView.release() } override fun onTaskCreated(taskId: Int, name: ComponentName?) { - detailTaskId = taskId requireViewById<ViewGroup>(R.id.controls_activity_view).apply { setAlpha(1f) } } - - override fun onReleased() { - removeDetailTask() - } - override fun onBackPressedOnTaskRoot(taskId: Int) { dismiss() } @@ -138,6 +128,9 @@ class DetailDialog( setContentView(R.layout.controls_detail_dialog) taskViewContainer = requireViewById<ViewGroup>(R.id.control_task_view_container) + controlDetailRoot = requireViewById<View>(R.id.control_detail_root).apply { + setOnClickListener { _: View -> dismiss() } + } requireViewById<ViewGroup>(R.id.controls_activity_view).apply { addView(taskView) @@ -147,13 +140,9 @@ class DetailDialog( requireViewById<ImageView>(R.id.control_detail_close).apply { setOnClickListener { _: View -> dismiss() } } - requireViewById<View>(R.id.control_detail_root).apply { - setOnClickListener { _: View -> dismiss() } - } requireViewById<ImageView>(R.id.control_detail_open_in_app).apply { setOnClickListener { v: View -> - removeDetailTask() dismiss() val action = ActivityStarter.OnDismissAction { @@ -201,26 +190,9 @@ class DetailDialog( taskView.setListener(cvh.uiExecutor, stateCallback) } - fun getTaskViewBounds(): Rect { - val wm = checkNotNull(context.getSystemService(WindowManager::class.java)) - val windowMetrics = wm.getCurrentWindowMetrics() - val rect = windowMetrics.bounds - val metricInsets = windowMetrics.windowInsets - val insets = metricInsets.getInsetsIgnoringVisibility(Type.systemBars() - or Type.displayCutout()) - val headerHeight = context.resources.getDimensionPixelSize( - R.dimen.controls_detail_dialog_header_height) - - val finalRect = Rect(rect.left - insets.left /* left */, - rect.top + insets.top + headerHeight /* top */, - rect.right - insets.right /* right */, - rect.bottom - insets.bottom /* bottom */) - return finalRect - } - override fun dismiss() { if (!isShowing()) return - taskView.release() + taskView.removeTask() val isActivityFinishing = (activityContext as? Activity)?.let { it.isFinishing || it.isDestroyed } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt index 1b0d03276415..848c78644659 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt @@ -18,7 +18,6 @@ package com.android.systemui.controls.ui import android.app.ActivityOptions -import android.app.ActivityTaskManager.INVALID_TASK_ID import android.app.PendingIntent import android.content.ComponentName import android.content.Context @@ -45,8 +44,6 @@ class PanelTaskViewController( taskView.alpha = 0f } - private var detailTaskId = INVALID_TASK_ID - private val fillInIntent = Intent().apply { // Apply flags to make behaviour match documentLaunchMode=always. @@ -57,7 +54,6 @@ class PanelTaskViewController( private val stateCallback = object : TaskView.Listener { override fun onInitialized() { - val options = ActivityOptions.makeCustomAnimation( activityContext, @@ -88,12 +84,10 @@ class PanelTaskViewController( } override fun onTaskRemovalStarted(taskId: Int) { - detailTaskId = INVALID_TASK_ID release() } override fun onTaskCreated(taskId: Int, name: ComponentName?) { - detailTaskId = taskId taskView.alpha = 1f } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt index 54142590b453..677108cab291 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt @@ -18,10 +18,13 @@ package com.android.systemui.controls.ui import android.app.ActivityOptions import android.app.PendingIntent +import android.content.Context import android.testing.AndroidTestingRunner import android.testing.TestableLooper +import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.activity.EmptyTestActivity import com.android.systemui.broadcast.BroadcastSender import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.policy.KeyguardStateController @@ -30,11 +33,13 @@ import com.android.systemui.util.mockito.capture import com.android.wm.shell.taskview.TaskView import com.google.common.truth.Truth.assertThat import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito.any +import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -43,31 +48,31 @@ import org.mockito.MockitoAnnotations @TestableLooper.RunWithLooper class DetailDialogTest : SysuiTestCase() { - @Mock - private lateinit var taskView: TaskView - @Mock - private lateinit var broadcastSender: BroadcastSender - @Mock - private lateinit var controlViewHolder: ControlViewHolder - @Mock - private lateinit var pendingIntent: PendingIntent - @Mock - private lateinit var keyguardStateController: KeyguardStateController - @Mock - private lateinit var activityStarter: ActivityStarter + @Rule + @JvmField + val activityRule: ActivityScenarioRule<EmptyTestActivity> = + ActivityScenarioRule(EmptyTestActivity::class.java) + + @Mock private lateinit var taskView: TaskView + @Mock private lateinit var broadcastSender: BroadcastSender + @Mock private lateinit var controlViewHolder: ControlViewHolder + @Mock private lateinit var pendingIntent: PendingIntent + @Mock private lateinit var keyguardStateController: KeyguardStateController + @Mock private lateinit var activityStarter: ActivityStarter + + private lateinit var underTest: DetailDialog @Before fun setUp() { MockitoAnnotations.initMocks(this) + + underTest = createDialog(pendingIntent) } @Test fun testPendingIntentIsUnModified() { - // GIVEN the dialog is created with a PendingIntent - val dialog = createDialog(pendingIntent) - // WHEN the TaskView is initialized - dialog.stateCallback.onInitialized() + underTest.stateCallback.onInitialized() // THEN the PendingIntent used to call startActivity is unmodified by systemui verify(taskView).startActivity(eq(pendingIntent), any(), any(), any()) @@ -75,11 +80,8 @@ class DetailDialogTest : SysuiTestCase() { @Test fun testActivityOptionsAllowBal() { - // GIVEN the dialog is created with a PendingIntent - val dialog = createDialog(pendingIntent) - // WHEN the TaskView is initialized - dialog.stateCallback.onInitialized() + underTest.stateCallback.onInitialized() val optionsCaptor = argumentCaptor<ActivityOptions>() @@ -90,17 +92,41 @@ class DetailDialogTest : SysuiTestCase() { .isEqualTo(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED) assertThat(optionsCaptor.value.isPendingIntentBackgroundActivityLaunchAllowedByPermission) .isTrue() + assertThat(optionsCaptor.value.taskAlwaysOnTop).isTrue() + } + + @Test + fun testDismissRemovesTheTask() { + activityRule.scenario.onActivity { + underTest = createDialog(pendingIntent, it) + underTest.show() + + underTest.dismiss() + + verify(taskView).removeTask() + verify(taskView, never()).release() + } + } + + @Test + fun testTaskRemovalReleasesTaskView() { + underTest.stateCallback.onTaskRemovalStarted(0) + + verify(taskView).release() } - private fun createDialog(pendingIntent: PendingIntent): DetailDialog { + private fun createDialog( + pendingIntent: PendingIntent, + context: Context = mContext, + ): DetailDialog { return DetailDialog( - mContext, + context, broadcastSender, taskView, pendingIntent, controlViewHolder, keyguardStateController, - activityStarter + activityStarter, ) } } |