Merge "[DO NOT MERGE] Controls - Do not recreate intent" into rvc-dev
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
package com.android.systemui.controls.ui
|
package com.android.systemui.controls.ui
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
@@ -74,7 +75,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
|
|||||||
bouncerOrRun(Action(cvh.cws.ci.controlId, {
|
bouncerOrRun(Action(cvh.cws.ci.controlId, {
|
||||||
cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
|
cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
|
||||||
if (cvh.usePanel()) {
|
if (cvh.usePanel()) {
|
||||||
showDialog(cvh, control.getAppIntent().getIntent())
|
showDetail(cvh, control.getAppIntent())
|
||||||
} else {
|
} else {
|
||||||
cvh.action(CommandAction(templateId))
|
cvh.action(CommandAction(templateId))
|
||||||
}
|
}
|
||||||
@@ -100,7 +101,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
|
|||||||
// Long press snould only be called when there is valid control state, otherwise ignore
|
// Long press snould only be called when there is valid control state, otherwise ignore
|
||||||
cvh.cws.control?.let {
|
cvh.cws.control?.let {
|
||||||
cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||||
showDialog(cvh, it.getAppIntent().getIntent())
|
showDetail(cvh, it.getAppIntent())
|
||||||
}
|
}
|
||||||
}, false /* blockable */))
|
}, false /* blockable */))
|
||||||
}
|
}
|
||||||
@@ -155,17 +156,17 @@ class ControlActionCoordinatorImpl @Inject constructor(
|
|||||||
bgExecutor.execute { vibrator.vibrate(effect) }
|
bgExecutor.execute { vibrator.vibrate(effect) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showDialog(cvh: ControlViewHolder, intent: Intent) {
|
private fun showDetail(cvh: ControlViewHolder, pendingIntent: PendingIntent) {
|
||||||
bgExecutor.execute {
|
bgExecutor.execute {
|
||||||
val activities: List<ResolveInfo> = cvh.context.packageManager.queryIntentActivities(
|
val activities: List<ResolveInfo> = context.packageManager.queryIntentActivities(
|
||||||
intent,
|
pendingIntent.getIntent(),
|
||||||
PackageManager.MATCH_DEFAULT_ONLY
|
PackageManager.MATCH_DEFAULT_ONLY
|
||||||
)
|
)
|
||||||
|
|
||||||
uiExecutor.execute {
|
uiExecutor.execute {
|
||||||
// make sure the intent is valid before attempting to open the dialog
|
// make sure the intent is valid before attempting to open the dialog
|
||||||
if (activities.isNotEmpty()) {
|
if (activities.isNotEmpty()) {
|
||||||
dialog = DetailDialog(cvh, intent).also {
|
dialog = DetailDialog(cvh, pendingIntent).also {
|
||||||
it.setOnDismissListener { _ -> dialog = null }
|
it.setOnDismissListener { _ -> dialog = null }
|
||||||
it.show()
|
it.show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,11 @@
|
|||||||
|
|
||||||
package com.android.systemui.controls.ui
|
package com.android.systemui.controls.ui
|
||||||
|
|
||||||
|
import android.app.ActivityOptions
|
||||||
import android.app.ActivityView
|
import android.app.ActivityView
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
|
import android.content.ComponentName
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -37,9 +40,8 @@ import com.android.systemui.R
|
|||||||
*/
|
*/
|
||||||
class DetailDialog(
|
class DetailDialog(
|
||||||
val cvh: ControlViewHolder,
|
val cvh: ControlViewHolder,
|
||||||
val intent: Intent
|
val pendingIntent: PendingIntent
|
||||||
) : Dialog(cvh.context, R.style.Theme_SystemUI_Dialog_Control_DetailPanel) {
|
) : Dialog(cvh.context, R.style.Theme_SystemUI_Dialog_Control_DetailPanel) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val PANEL_TOP_OFFSET = "systemui.controls_panel_top_offset"
|
private const val PANEL_TOP_OFFSET = "systemui.controls_panel_top_offset"
|
||||||
/*
|
/*
|
||||||
@@ -49,18 +51,19 @@ class DetailDialog(
|
|||||||
private const val EXTRA_USE_PANEL = "controls.DISPLAY_IN_PANEL"
|
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)
|
var activityView = ActivityView(context, null, 0, false)
|
||||||
|
|
||||||
val stateCallback: ActivityView.StateCallback = object : ActivityView.StateCallback() {
|
val stateCallback: ActivityView.StateCallback = object : ActivityView.StateCallback() {
|
||||||
override fun onActivityViewReady(view: ActivityView) {
|
override fun onActivityViewReady(view: ActivityView) {
|
||||||
val launchIntent = Intent(intent)
|
view.startActivity(pendingIntent, fillInIntent, ActivityOptions.makeBasic())
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityViewDestroyed(view: ActivityView) {}
|
override fun onActivityViewDestroyed(view: ActivityView) {}
|
||||||
@@ -68,6 +71,12 @@ class DetailDialog(
|
|||||||
override fun onTaskRemovalStarted(taskId: Int) {
|
override fun onTaskRemovalStarted(taskId: Int) {
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onTaskCreated(taskId: Int, name: ComponentName?) {
|
||||||
|
requireViewById<ViewGroup>(R.id.controls_activity_view).apply {
|
||||||
|
setAlpha(1f)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -76,6 +85,7 @@ class DetailDialog(
|
|||||||
|
|
||||||
requireViewById<ViewGroup>(R.id.controls_activity_view).apply {
|
requireViewById<ViewGroup>(R.id.controls_activity_view).apply {
|
||||||
addView(activityView)
|
addView(activityView)
|
||||||
|
setAlpha(0f)
|
||||||
}
|
}
|
||||||
|
|
||||||
requireViewById<ImageView>(R.id.control_detail_close).apply {
|
requireViewById<ImageView>(R.id.control_detail_close).apply {
|
||||||
@@ -86,7 +96,7 @@ class DetailDialog(
|
|||||||
setOnClickListener { v: View ->
|
setOnClickListener { v: View ->
|
||||||
dismiss()
|
dismiss()
|
||||||
context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
|
context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
|
||||||
v.context.startActivity(intent)
|
pendingIntent.send()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user