[DO NOT MERGE] Controls - Do not recreate intent am: d7b16dd2a5
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16012418
Change-Id: I7d17da929ecd548c21c0d088557ff20209952efe
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 22d6b6b..055c2c2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -17,6 +17,7 @@
package com.android.systemui.controls.ui
import android.app.Dialog
+import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
@@ -74,7 +75,7 @@
bouncerOrRun(Action(cvh.cws.ci.controlId, {
cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
if (cvh.usePanel()) {
- showDialog(cvh, control.getAppIntent().getIntent())
+ showDetail(cvh, control.getAppIntent())
} else {
cvh.action(CommandAction(templateId))
}
@@ -100,7 +101,7 @@
// 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())
}
}, false /* blockable */))
}
@@ -155,17 +156,17 @@
bgExecutor.execute { vibrator.vibrate(effect) }
}
- private fun showDialog(cvh: ControlViewHolder, intent: Intent) {
+ private fun showDetail(cvh: ControlViewHolder, pendingIntent: PendingIntent) {
bgExecutor.execute {
- val activities: List<ResolveInfo> = cvh.context.packageManager.queryIntentActivities(
- intent,
+ val activities: List<ResolveInfo> = context.packageManager.queryIntentActivities(
+ pendingIntent.getIntent(),
PackageManager.MATCH_DEFAULT_ONLY
)
uiExecutor.execute {
// make sure the intent is valid before attempting to open the dialog
if (activities.isNotEmpty()) {
- dialog = DetailDialog(cvh, intent).also {
+ dialog = DetailDialog(cvh, pendingIntent).also {
it.setOnDismissListener { _ -> dialog = null }
it.show()
}
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 9ec1452..a7f7eb7 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -16,8 +16,11 @@
package com.android.systemui.controls.ui
+import android.app.ActivityOptions
import android.app.ActivityView
+import android.app.PendingIntent
import android.app.Dialog
+import android.content.ComponentName
import android.content.Intent
import android.provider.Settings
import android.view.View
@@ -37,9 +40,8 @@
*/
class DetailDialog(
val cvh: ControlViewHolder,
- val intent: Intent
+ val pendingIntent: PendingIntent
) : Dialog(cvh.context, R.style.Theme_SystemUI_Dialog_Control_DetailPanel) {
-
companion object {
private const val PANEL_TOP_OFFSET = "systemui.controls_panel_top_offset"
/*
@@ -49,18 +51,19 @@
private const val EXTRA_USE_PANEL = "controls.DISPLAY_IN_PANEL"
}
+ private val fillInIntent = Intent().apply {
+ putExtra(EXTRA_USE_PANEL, true)
+
+ // Apply flags to make behaviour match documentLaunchMode=always.
+ addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
+ addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
+ }
+
var activityView = ActivityView(context, null, 0, false)
val stateCallback: ActivityView.StateCallback = object : ActivityView.StateCallback() {
override fun onActivityViewReady(view: ActivityView) {
- val launchIntent = Intent(intent)
- launchIntent.putExtra(EXTRA_USE_PANEL, true)
-
- // Apply flags to make behaviour match documentLaunchMode=always.
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
-
- view.startActivity(launchIntent)
+ view.startActivity(pendingIntent, fillInIntent, ActivityOptions.makeBasic())
}
override fun onActivityViewDestroyed(view: ActivityView) {}
@@ -68,6 +71,12 @@
override fun onTaskRemovalStarted(taskId: Int) {
dismiss()
}
+
+ override fun onTaskCreated(taskId: Int, name: ComponentName?) {
+ requireViewById<ViewGroup>(R.id.controls_activity_view).apply {
+ setAlpha(1f)
+ }
+ }
}
init {
@@ -76,6 +85,7 @@
requireViewById<ViewGroup>(R.id.controls_activity_view).apply {
addView(activityView)
+ setAlpha(0f)
}
requireViewById<ImageView>(R.id.control_detail_close).apply {
@@ -86,7 +96,7 @@
setOnClickListener { v: View ->
dismiss()
context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
- v.context.startActivity(intent)
+ pendingIntent.send()
}
}
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
new file mode 100644
index 0000000..0ad03d2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.ActivityView
+import android.app.PendingIntent
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.capture
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class DetailDialogTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var activityView: ActivityView
+ @Mock
+ private lateinit var controlViewHolder: ControlViewHolder
+ @Mock
+ private lateinit var pendingIntent: PendingIntent
+ @Captor
+ private lateinit var viewCaptor: ArgumentCaptor<ActivityView>
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun testPendingIntentIsUnModified() {
+ // GIVEN the dialog is created with a PendingIntent
+ val dialog = createDialog(pendingIntent)
+
+ // WHEN the ActivityView is initialized
+ dialog.stateCallback.onActivityViewReady(capture(viewCaptor))
+
+ // THEN the PendingIntent used to call startActivity is unmodified by systemui
+ verify(viewCaptor.value).startActivity(eq(pendingIntent), any(), any())
+ }
+
+ private fun createDialog(pendingIntent: PendingIntent): DetailDialog {
+ return DetailDialog(
+ controlViewHolder,
+ pendingIntent
+ )
+ }
+}