Add new add flow for panels
This adds a flow for adding panels that will query consent from the user. Note that this needs Flags.APP_PANELS_ALL_APPS_ALLOWED for those panels to show in the first place. Test: manual, trigger dialog Test: atest com.android.systemui.controls Bug: 265180342 Change-Id: I5a0c382f98595daffbd7e4dfe1e52adb43b2f1c5
This commit is contained in:
@@ -2238,6 +2238,14 @@
|
||||
<!-- Removed control in management screen [CHAR LIMIT=20] -->
|
||||
<string name="controls_removed">Removed</string>
|
||||
|
||||
<!-- Title for the dialog presented to the user to authorize this app to display a Device
|
||||
controls panel (embedded activity) instead of controls rendered by SystemUI [CHAR LIMIT=30] -->
|
||||
<string name="controls_panel_authorization_title">Add <xliff:g id="appName" example="My app">%s</xliff:g>?</string>
|
||||
|
||||
<!-- Shows in a dialog presented to the user to authorize this app to display a Device controls
|
||||
panel (embedded activity) instead of controls rendered by SystemUI [CHAR LIMIT=NONE] -->
|
||||
<string name="controls_panel_authorization">When you add <xliff:g id="appName" example="My app">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here.</string>
|
||||
|
||||
<!-- a11y state description for a control that is currently favorited [CHAR LIMIT=NONE] -->
|
||||
<string name="accessibility_control_favorite">Favorited</string>
|
||||
<!-- a11y state description for a control that is currently favorited with its position [CHAR LIMIT=NONE] -->
|
||||
@@ -2387,6 +2395,8 @@
|
||||
<string name="controls_menu_add">Add controls</string>
|
||||
<!-- Controls menu, edit [CHAR_LIMIT=30] -->
|
||||
<string name="controls_menu_edit">Edit controls</string>
|
||||
<!-- Controls menu, add another app [CHAR LIMIT=30] -->
|
||||
<string name="controls_menu_add_another_app">Add app</string>
|
||||
|
||||
<!-- Title for the media output dialog with media related devices [CHAR LIMIT=50] -->
|
||||
<string name="media_output_dialog_add_output">Add outputs</string>
|
||||
|
||||
@@ -188,6 +188,8 @@ interface ControlsController : UserAwareController {
|
||||
/** See [ControlsUiController.getPreferredSelectedItem]. */
|
||||
fun getPreferredSelection(): SelectedItem
|
||||
|
||||
fun setPreferredSelection(selectedItem: SelectedItem)
|
||||
|
||||
/**
|
||||
* Bind to a service that provides a Device Controls panel (embedded activity). This will allow
|
||||
* the app to remain "warm", and reduce latency.
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.android.systemui.backup.BackupHelper
|
||||
import com.android.systemui.controls.ControlStatus
|
||||
import com.android.systemui.controls.ControlsServiceInfo
|
||||
import com.android.systemui.controls.management.ControlsListingController
|
||||
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
|
||||
import com.android.systemui.controls.ui.ControlsUiController
|
||||
import com.android.systemui.controls.ui.SelectedItem
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
@@ -61,6 +62,7 @@ class ControlsControllerImpl @Inject constructor (
|
||||
private val listingController: ControlsListingController,
|
||||
private val userFileManager: UserFileManager,
|
||||
private val userTracker: UserTracker,
|
||||
private val authorizedPanelsRepository: AuthorizedPanelsRepository,
|
||||
optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
|
||||
dumpManager: DumpManager,
|
||||
) : Dumpable, ControlsController {
|
||||
@@ -249,6 +251,11 @@ class ControlsControllerImpl @Inject constructor (
|
||||
private fun resetFavorites() {
|
||||
Favorites.clear()
|
||||
Favorites.load(persistenceWrapper.readFavorites())
|
||||
// After loading favorites, add the package names of any apps with favorites to the list
|
||||
// of authorized panels. That way, if the user has previously favorited controls for an app,
|
||||
// that panel will be authorized.
|
||||
authorizedPanelsRepository.addAuthorizedPanels(
|
||||
Favorites.getAllStructures().map { it.componentName.packageName }.toSet())
|
||||
}
|
||||
|
||||
private fun confirmAvailability(): Boolean {
|
||||
@@ -489,6 +496,7 @@ class ControlsControllerImpl @Inject constructor (
|
||||
if (!confirmAvailability()) return
|
||||
executor.execute {
|
||||
if (Favorites.addFavorite(componentName, structureName, controlInfo)) {
|
||||
authorizedPanelsRepository.addAuthorizedPanels(setOf(componentName.packageName))
|
||||
persistenceWrapper.storeFavorites(Favorites.getAllStructures())
|
||||
}
|
||||
}
|
||||
@@ -555,6 +563,10 @@ class ControlsControllerImpl @Inject constructor (
|
||||
return uiController.getPreferredSelectedItem(getFavorites())
|
||||
}
|
||||
|
||||
override fun setPreferredSelection(selectedItem: SelectedItem) {
|
||||
uiController.updatePreferences(selectedItem)
|
||||
}
|
||||
|
||||
override fun dump(pw: PrintWriter, args: Array<out String>) {
|
||||
pw.println("ControlsController state:")
|
||||
pw.println(" Changing users: $userChanging")
|
||||
|
||||
@@ -45,14 +45,15 @@ import java.util.concurrent.Executor
|
||||
* @param onAppSelected a callback to indicate that an app has been selected in the list.
|
||||
*/
|
||||
class AppAdapter(
|
||||
backgroundExecutor: Executor,
|
||||
uiExecutor: Executor,
|
||||
lifecycle: Lifecycle,
|
||||
controlsListingController: ControlsListingController,
|
||||
private val layoutInflater: LayoutInflater,
|
||||
private val onAppSelected: (ComponentName?) -> Unit = {},
|
||||
private val favoritesRenderer: FavoritesRenderer,
|
||||
private val resources: Resources
|
||||
backgroundExecutor: Executor,
|
||||
uiExecutor: Executor,
|
||||
lifecycle: Lifecycle,
|
||||
controlsListingController: ControlsListingController,
|
||||
private val layoutInflater: LayoutInflater,
|
||||
private val onAppSelected: (ControlsServiceInfo) -> Unit = {},
|
||||
private val favoritesRenderer: FavoritesRenderer,
|
||||
private val resources: Resources,
|
||||
private val authorizedPanels: Set<String> = emptySet(),
|
||||
) : RecyclerView.Adapter<AppAdapter.Holder>() {
|
||||
|
||||
private var listOfServices = emptyList<ControlsServiceInfo>()
|
||||
@@ -64,8 +65,10 @@ class AppAdapter(
|
||||
val localeComparator = compareBy<ControlsServiceInfo, CharSequence>(collator) {
|
||||
it.loadLabel() ?: ""
|
||||
}
|
||||
listOfServices = serviceInfos.filter { it.panelActivity == null }
|
||||
.sortedWith(localeComparator)
|
||||
// No panel or the panel is not authorized
|
||||
listOfServices = serviceInfos.filter {
|
||||
it.panelActivity == null || it.panelActivity?.packageName !in authorizedPanels
|
||||
}.sortedWith(localeComparator)
|
||||
uiExecutor.execute(::notifyDataSetChanged)
|
||||
}
|
||||
}
|
||||
@@ -86,8 +89,8 @@ class AppAdapter(
|
||||
|
||||
override fun onBindViewHolder(holder: Holder, index: Int) {
|
||||
holder.bindData(listOfServices[index])
|
||||
holder.itemView.setOnClickListener {
|
||||
onAppSelected(ComponentName.unflattenFromString(listOfServices[index].key))
|
||||
holder.view.setOnClickListener {
|
||||
onAppSelected(listOfServices[index])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +98,8 @@ class AppAdapter(
|
||||
* Holder for binding views in the [RecyclerView]-
|
||||
*/
|
||||
class Holder(view: View, val favRenderer: FavoritesRenderer) : RecyclerView.ViewHolder(view) {
|
||||
val view: View = itemView
|
||||
|
||||
private val icon: ImageView = itemView.requireViewById(com.android.internal.R.id.icon)
|
||||
private val title: TextView = itemView.requireViewById(com.android.internal.R.id.title)
|
||||
private val favorites: TextView = itemView.requireViewById(R.id.favorites)
|
||||
@@ -106,7 +111,11 @@ class AppAdapter(
|
||||
fun bindData(data: ControlsServiceInfo) {
|
||||
icon.setImageDrawable(data.loadIcon())
|
||||
title.text = data.loadLabel()
|
||||
val text = favRenderer.renderFavoritesForComponent(data.componentName)
|
||||
val text = if (data.panelActivity == null) {
|
||||
favRenderer.renderFavoritesForComponent(data.componentName)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
favorites.text = text
|
||||
favorites.visibility = if (text == null) View.GONE else View.VISIBLE
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.systemui.controls.management
|
||||
|
||||
import android.app.ActivityOptions
|
||||
import android.app.Dialog
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@@ -31,12 +32,15 @@ import android.widget.TextView
|
||||
import android.window.OnBackInvokedCallback
|
||||
import android.window.OnBackInvokedDispatcher
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.controls.ControlsServiceInfo
|
||||
import com.android.systemui.controls.controller.ControlsController
|
||||
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
|
||||
import com.android.systemui.controls.ui.ControlsActivity
|
||||
import com.android.systemui.controls.ui.ControlsUiController
|
||||
import com.android.systemui.controls.ui.SelectedItem
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.settings.UserTracker
|
||||
@@ -52,7 +56,8 @@ open class ControlsProviderSelectorActivity @Inject constructor(
|
||||
private val listingController: ControlsListingController,
|
||||
private val controlsController: ControlsController,
|
||||
private val userTracker: UserTracker,
|
||||
private val uiController: ControlsUiController
|
||||
private val authorizedPanelsRepository: AuthorizedPanelsRepository,
|
||||
private val panelConfirmationDialogFactory: PanelConfirmationDialogFactory
|
||||
) : ComponentActivity() {
|
||||
|
||||
companion object {
|
||||
@@ -72,6 +77,7 @@ open class ControlsProviderSelectorActivity @Inject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
private var dialog: Dialog? = null
|
||||
|
||||
private val mOnBackInvokedCallback = OnBackInvokedCallback {
|
||||
if (DEBUG) {
|
||||
@@ -138,9 +144,11 @@ open class ControlsProviderSelectorActivity @Inject constructor(
|
||||
lifecycle,
|
||||
listingController,
|
||||
LayoutInflater.from(this),
|
||||
::launchFavoritingActivity,
|
||||
::onAppSelected,
|
||||
FavoritesRenderer(resources, controlsController::countFavoritesForComponent),
|
||||
resources).apply {
|
||||
resources,
|
||||
authorizedPanelsRepository.getAuthorizedPanels()
|
||||
).apply {
|
||||
registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
||||
var hasAnimated = false
|
||||
override fun onChanged() {
|
||||
@@ -167,13 +175,35 @@ open class ControlsProviderSelectorActivity @Inject constructor(
|
||||
Log.d(TAG, "Unregistered onBackInvokedCallback")
|
||||
}
|
||||
onBackInvokedDispatcher.unregisterOnBackInvokedCallback(mOnBackInvokedCallback)
|
||||
dialog?.cancel()
|
||||
}
|
||||
|
||||
fun onAppSelected(serviceInfo: ControlsServiceInfo) {
|
||||
dialog?.cancel()
|
||||
if (serviceInfo.panelActivity == null) {
|
||||
launchFavoritingActivity(serviceInfo.componentName)
|
||||
} else {
|
||||
val appName = serviceInfo.loadLabel() ?: ""
|
||||
dialog = panelConfirmationDialogFactory.createConfirmationDialog(this, appName) { ok ->
|
||||
if (ok) {
|
||||
authorizedPanelsRepository.addAuthorizedPanels(
|
||||
setOf(serviceInfo.componentName.packageName)
|
||||
)
|
||||
animateExitAndFinish()
|
||||
val selected = SelectedItem.PanelItem(appName, componentName)
|
||||
controlsController.setPreferredSelection(selected)
|
||||
openControlsOrigin()
|
||||
}
|
||||
dialog = null
|
||||
}.also { it.show() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the [ControlsFavoritingActivity] for the specified component.
|
||||
* @param component a component name for a [ControlsProviderService]
|
||||
*/
|
||||
fun launchFavoritingActivity(component: ComponentName?) {
|
||||
private fun launchFavoritingActivity(component: ComponentName?) {
|
||||
executor.execute {
|
||||
component?.let {
|
||||
val intent = Intent(applicationContext, ControlsFavoritingActivity::class.java)
|
||||
@@ -194,7 +224,15 @@ open class ControlsProviderSelectorActivity @Inject constructor(
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun animateExitAndFinish() {
|
||||
private fun openControlsOrigin() {
|
||||
startActivity(
|
||||
Intent(applicationContext, ControlsActivity::class.java),
|
||||
ActivityOptions.makeSceneTransitionAnimation(this).toBundle()
|
||||
)
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal open fun animateExitAndFinish() {
|
||||
val rootView = requireViewById<ViewGroup>(R.id.controls_management_root)
|
||||
ControlsAnimations.exitAnimation(
|
||||
rootView,
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.management
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.statusbar.phone.SystemUIDialog
|
||||
import java.util.function.Consumer
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Factory to create dialogs for consenting to show app panels for specific apps.
|
||||
*
|
||||
* [internalDialogFactory] is for facilitating testing.
|
||||
*/
|
||||
class PanelConfirmationDialogFactory(
|
||||
private val internalDialogFactory: (Context) -> SystemUIDialog
|
||||
) {
|
||||
@Inject constructor() : this({ SystemUIDialog(it) })
|
||||
|
||||
/**
|
||||
* Creates a dialog to show to the user. [response] will be true if an only if the user responds
|
||||
* affirmatively.
|
||||
*/
|
||||
fun createConfirmationDialog(
|
||||
context: Context,
|
||||
appName: CharSequence,
|
||||
response: Consumer<Boolean>
|
||||
): Dialog {
|
||||
val listener =
|
||||
DialogInterface.OnClickListener { _, which ->
|
||||
response.accept(which == DialogInterface.BUTTON_POSITIVE)
|
||||
}
|
||||
return internalDialogFactory(context).apply {
|
||||
setTitle(this.context.getString(R.string.controls_panel_authorization_title, appName))
|
||||
setMessage(this.context.getString(R.string.controls_panel_authorization, appName))
|
||||
setCanceledOnTouchOutside(true)
|
||||
setOnCancelListener { response.accept(false) }
|
||||
setPositiveButton(R.string.controls_dialog_ok, listener)
|
||||
setNeutralButton(R.string.cancel, listener)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,15 @@
|
||||
|
||||
package com.android.systemui.controls.panels
|
||||
|
||||
/**
|
||||
* Repository for keeping track of which packages the panel has authorized to show control panels
|
||||
* (embedded activity).
|
||||
*/
|
||||
interface AuthorizedPanelsRepository {
|
||||
|
||||
/** A set of package names that the user has previously authorized to show panels. */
|
||||
fun getAuthorizedPanels(): Set<String>
|
||||
|
||||
/** Adds [packageNames] to the set of packages that the user has authorized to show panels. */
|
||||
fun addAuthorizedPanels(packageNames: Set<String>)
|
||||
}
|
||||
|
||||
@@ -58,6 +58,8 @@ interface ControlsUiController {
|
||||
* This element will be the one that appears when the user first opens the controls activity.
|
||||
*/
|
||||
fun getPreferredSelectedItem(structures: List<StructureInfo>): SelectedItem
|
||||
|
||||
fun updatePreferences(selectedItem: SelectedItem)
|
||||
}
|
||||
|
||||
sealed class SelectedItem {
|
||||
|
||||
@@ -60,10 +60,13 @@ import com.android.systemui.controls.management.ControlsEditingActivity
|
||||
import com.android.systemui.controls.management.ControlsFavoritingActivity
|
||||
import com.android.systemui.controls.management.ControlsListingController
|
||||
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
|
||||
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.globalactions.GlobalActionsPopupMenu
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.settings.UserFileManager
|
||||
@@ -99,6 +102,8 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
private val userTracker: UserTracker,
|
||||
private val taskViewFactory: Optional<TaskViewFactory>,
|
||||
private val controlsSettingsRepository: ControlsSettingsRepository,
|
||||
private val authorizedPanelsRepository: AuthorizedPanelsRepository,
|
||||
private val featureFlags: FeatureFlags,
|
||||
dumpManager: DumpManager
|
||||
) : ControlsUiController, Dumpable {
|
||||
|
||||
@@ -160,6 +165,7 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
): ControlsListingController.ControlsListingCallback {
|
||||
return object : ControlsListingController.ControlsListingCallback {
|
||||
override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
|
||||
val authorizedPanels = authorizedPanelsRepository.getAuthorizedPanels()
|
||||
val lastItems = serviceInfos.map {
|
||||
val uid = it.serviceInfo.applicationInfo.uid
|
||||
|
||||
@@ -169,7 +175,11 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
it.loadIcon(),
|
||||
it.componentName,
|
||||
uid,
|
||||
it.panelActivity
|
||||
if (it.componentName.packageName in authorizedPanels) {
|
||||
it.panelActivity
|
||||
} else {
|
||||
null
|
||||
}
|
||||
)
|
||||
}
|
||||
uiExecutor.execute {
|
||||
@@ -417,14 +427,20 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
val isPanel = selectedItem is SelectedItem.PanelItem
|
||||
val selectedStructure = (selectedItem as? SelectedItem.StructureItem)?.structure
|
||||
?: EMPTY_STRUCTURE
|
||||
val newFlows = featureFlags.isEnabled(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS)
|
||||
val addControlsId = if (newFlows || isPanel) {
|
||||
R.string.controls_menu_add_another_app
|
||||
} else {
|
||||
R.string.controls_menu_add
|
||||
}
|
||||
|
||||
val items = if (isPanel) {
|
||||
arrayOf(
|
||||
context.resources.getString(R.string.controls_menu_add),
|
||||
context.resources.getString(addControlsId),
|
||||
)
|
||||
} else {
|
||||
arrayOf(
|
||||
context.resources.getString(R.string.controls_menu_add),
|
||||
context.resources.getString(addControlsId),
|
||||
context.resources.getString(R.string.controls_menu_edit)
|
||||
)
|
||||
}
|
||||
@@ -449,7 +465,7 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
when (pos) {
|
||||
// 0: Add Control
|
||||
0 -> {
|
||||
if (isPanel) {
|
||||
if (isPanel || newFlows) {
|
||||
startProviderSelectorActivity()
|
||||
} else {
|
||||
startFavoritingActivity(selectedStructure)
|
||||
@@ -610,11 +626,11 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePreferences(si: SelectedItem) {
|
||||
override fun updatePreferences(selectedItem: SelectedItem) {
|
||||
sharedPreferences.edit()
|
||||
.putString(PREF_COMPONENT, si.componentName.flattenToString())
|
||||
.putString(PREF_STRUCTURE_OR_APP_NAME, si.name.toString())
|
||||
.putBoolean(PREF_IS_PANEL, si is SelectedItem.PanelItem)
|
||||
.putString(PREF_COMPONENT, selectedItem.componentName.flattenToString())
|
||||
.putString(PREF_STRUCTURE_OR_APP_NAME, selectedItem.name.toString())
|
||||
.putBoolean(PREF_IS_PANEL, selectedItem is SelectedItem.PanelItem)
|
||||
.commit()
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.android.systemui.backup.BackupHelper
|
||||
import com.android.systemui.controls.ControlStatus
|
||||
import com.android.systemui.controls.ControlsServiceInfo
|
||||
import com.android.systemui.controls.management.ControlsListingController
|
||||
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
|
||||
import com.android.systemui.controls.ui.ControlsUiController
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.settings.UserFileManager
|
||||
@@ -66,6 +67,7 @@ import org.mockito.Mockito.times
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.verifyNoMoreInteractions
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.clearInvocations
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@SmallTest
|
||||
@@ -88,6 +90,8 @@ class ControlsControllerImplTest : SysuiTestCase() {
|
||||
private lateinit var userTracker: UserTracker
|
||||
@Mock
|
||||
private lateinit var userFileManager: UserFileManager
|
||||
@Mock
|
||||
private lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository
|
||||
|
||||
@Captor
|
||||
private lateinit var structureInfoCaptor: ArgumentCaptor<StructureInfo>
|
||||
@@ -168,6 +172,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
|
||||
listingController,
|
||||
userFileManager,
|
||||
userTracker,
|
||||
authorizedPanelsRepository,
|
||||
Optional.of(persistenceWrapper),
|
||||
mock(DumpManager::class.java)
|
||||
)
|
||||
@@ -224,12 +229,33 @@ class ControlsControllerImplTest : SysuiTestCase() {
|
||||
listingController,
|
||||
userFileManager,
|
||||
userTracker,
|
||||
authorizedPanelsRepository,
|
||||
Optional.of(persistenceWrapper),
|
||||
mock(DumpManager::class.java)
|
||||
)
|
||||
assertEquals(listOf(TEST_STRUCTURE_INFO), controller_other.getFavorites())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddAuthorizedPackagesFromSavedFavoritesOnStart() {
|
||||
clearInvocations(authorizedPanelsRepository)
|
||||
`when`(persistenceWrapper.readFavorites()).thenReturn(listOf(TEST_STRUCTURE_INFO))
|
||||
ControlsControllerImpl(
|
||||
mContext,
|
||||
delayableExecutor,
|
||||
uiController,
|
||||
bindingController,
|
||||
listingController,
|
||||
userFileManager,
|
||||
userTracker,
|
||||
authorizedPanelsRepository,
|
||||
Optional.of(persistenceWrapper),
|
||||
mock(DumpManager::class.java)
|
||||
)
|
||||
verify(authorizedPanelsRepository)
|
||||
.addAuthorizedPanels(setOf(TEST_STRUCTURE_INFO.componentName.packageName))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnActionResponse() {
|
||||
controller.onActionResponse(TEST_COMPONENT, TEST_CONTROL_ID, ControlAction.RESPONSE_OK)
|
||||
|
||||
@@ -21,12 +21,15 @@ import android.content.res.Resources
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.controls.ControlsServiceInfo
|
||||
import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.android.systemui.util.mockito.capture
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
@@ -36,8 +39,10 @@ import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.clearInvocations
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
import java.text.Collator
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@@ -49,25 +54,18 @@ class AppAdapterTest : SysuiTestCase() {
|
||||
@Mock lateinit var lifecycle: Lifecycle
|
||||
@Mock lateinit var controlsListingController: ControlsListingController
|
||||
@Mock lateinit var layoutInflater: LayoutInflater
|
||||
@Mock lateinit var onAppSelected: (ComponentName?) -> Unit
|
||||
@Mock lateinit var onAppSelected: (ControlsServiceInfo) -> Unit
|
||||
@Mock lateinit var favoritesRenderer: FavoritesRenderer
|
||||
val resources: Resources = context.resources
|
||||
lateinit var adapter: AppAdapter
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
adapter = AppAdapter(backgroundExecutor,
|
||||
uiExecutor,
|
||||
lifecycle,
|
||||
controlsListingController,
|
||||
layoutInflater,
|
||||
onAppSelected,
|
||||
favoritesRenderer,
|
||||
resources)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnServicesUpdated_nullLoadLabel() {
|
||||
adapter = createAdapterWithAuthorizedPanels(emptySet())
|
||||
val captor = ArgumentCaptor
|
||||
.forClass(ControlsListingController.ControlsListingCallback::class.java)
|
||||
val controlsServiceInfo = mock<ControlsServiceInfo>()
|
||||
@@ -76,14 +74,14 @@ class AppAdapterTest : SysuiTestCase() {
|
||||
verify(controlsListingController).observe(any(Lifecycle::class.java), captor.capture())
|
||||
|
||||
captor.value.onServicesUpdated(serviceInfo)
|
||||
backgroundExecutor.runAllReady()
|
||||
uiExecutor.runAllReady()
|
||||
FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor)
|
||||
|
||||
assertThat(adapter.itemCount).isEqualTo(serviceInfo.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnServicesUpdatedDoesntHavePanels() {
|
||||
fun testOnServicesUpdated_showsNotAuthorizedPanels() {
|
||||
adapter = createAdapterWithAuthorizedPanels(emptySet())
|
||||
val captor = ArgumentCaptor
|
||||
.forClass(ControlsListingController.ControlsListingCallback::class.java)
|
||||
val serviceInfo = listOf(
|
||||
@@ -93,20 +91,88 @@ class AppAdapterTest : SysuiTestCase() {
|
||||
verify(controlsListingController).observe(any(Lifecycle::class.java), captor.capture())
|
||||
|
||||
captor.value.onServicesUpdated(serviceInfo)
|
||||
backgroundExecutor.runAllReady()
|
||||
uiExecutor.runAllReady()
|
||||
FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor)
|
||||
|
||||
assertThat(adapter.itemCount).isEqualTo(2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnServicesUpdated_doesntShowAuthorizedPanels() {
|
||||
adapter = createAdapterWithAuthorizedPanels(setOf(TEST_PACKAGE))
|
||||
|
||||
val captor = ArgumentCaptor
|
||||
.forClass(ControlsListingController.ControlsListingCallback::class.java)
|
||||
val serviceInfo = listOf(
|
||||
ControlsServiceInfo("no panel", null),
|
||||
ControlsServiceInfo("panel", ComponentName(TEST_PACKAGE, "cls"))
|
||||
)
|
||||
verify(controlsListingController).observe(any(Lifecycle::class.java), captor.capture())
|
||||
|
||||
captor.value.onServicesUpdated(serviceInfo)
|
||||
FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor)
|
||||
|
||||
assertThat(adapter.itemCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
fun ControlsServiceInfo(
|
||||
label: CharSequence,
|
||||
panelComponentName: ComponentName? = null
|
||||
): ControlsServiceInfo {
|
||||
return mock {
|
||||
`when`(this.loadLabel()).thenReturn(label)
|
||||
`when`(this.panelActivity).thenReturn(panelComponentName)
|
||||
`when`(this.loadIcon()).thenReturn(mock())
|
||||
@Test
|
||||
fun testOnBindSetsClickListenerToCallOnAppSelected() {
|
||||
adapter = createAdapterWithAuthorizedPanels(emptySet())
|
||||
|
||||
val captor = ArgumentCaptor
|
||||
.forClass(ControlsListingController.ControlsListingCallback::class.java)
|
||||
val serviceInfo = listOf(
|
||||
ControlsServiceInfo("no panel", null),
|
||||
ControlsServiceInfo("panel", ComponentName(TEST_PACKAGE, "cls"))
|
||||
)
|
||||
verify(controlsListingController).observe(any(Lifecycle::class.java), captor.capture())
|
||||
|
||||
captor.value.onServicesUpdated(serviceInfo)
|
||||
FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor)
|
||||
|
||||
val sorted = serviceInfo.sortedWith(
|
||||
compareBy(Collator.getInstance(resources.configuration.locales[0])) {
|
||||
it.loadLabel() ?: ""
|
||||
})
|
||||
|
||||
sorted.forEachIndexed { index, info ->
|
||||
val fakeView: View = mock()
|
||||
val fakeHolder: AppAdapter.Holder = mock()
|
||||
`when`(fakeHolder.view).thenReturn(fakeView)
|
||||
|
||||
clearInvocations(onAppSelected)
|
||||
adapter.onBindViewHolder(fakeHolder, index)
|
||||
val listenerCaptor: ArgumentCaptor<View.OnClickListener> = argumentCaptor()
|
||||
verify(fakeView).setOnClickListener(capture(listenerCaptor))
|
||||
listenerCaptor.value.onClick(fakeView)
|
||||
|
||||
verify(onAppSelected).invoke(info)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createAdapterWithAuthorizedPanels(packages: Set<String>): AppAdapter {
|
||||
return AppAdapter(backgroundExecutor,
|
||||
uiExecutor,
|
||||
lifecycle,
|
||||
controlsListingController,
|
||||
layoutInflater,
|
||||
onAppSelected,
|
||||
favoritesRenderer,
|
||||
resources,
|
||||
packages)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun ControlsServiceInfo(
|
||||
label: CharSequence,
|
||||
panelComponentName: ComponentName? = null
|
||||
): ControlsServiceInfo {
|
||||
return mock {
|
||||
`when`(loadLabel()).thenReturn(label)
|
||||
`when`(panelActivity).thenReturn(panelComponentName)
|
||||
`when`(loadIcon()).thenReturn(mock())
|
||||
}
|
||||
}
|
||||
|
||||
private const val TEST_PACKAGE = "package"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,13 @@
|
||||
|
||||
package com.android.systemui.controls.management
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.ServiceInfo
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import android.window.OnBackInvokedCallback
|
||||
@@ -25,14 +31,23 @@ import androidx.test.filters.SmallTest
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import androidx.test.runner.intercepting.SingleActivityFactory
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.controls.ControlsServiceInfo
|
||||
import com.android.systemui.controls.controller.ControlsController
|
||||
import com.android.systemui.controls.ui.ControlsUiController
|
||||
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.settings.UserTracker
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.android.systemui.util.mockito.capture
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.google.common.util.concurrent.MoreExecutors
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.function.Consumer
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
@@ -41,7 +56,11 @@ import org.mockito.ArgumentCaptor
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.doReturn
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.verifyNoMoreInteractions
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@SmallTest
|
||||
@@ -58,9 +77,10 @@ class ControlsProviderSelectorActivityTest : SysuiTestCase() {
|
||||
|
||||
@Mock lateinit var userTracker: UserTracker
|
||||
|
||||
@Mock lateinit var uiController: ControlsUiController
|
||||
@Mock lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository
|
||||
|
||||
@Mock lateinit var dialogFactory: PanelConfirmationDialogFactory
|
||||
|
||||
private lateinit var controlsProviderSelectorActivity: ControlsProviderSelectorActivity_Factory
|
||||
private var latch: CountDownLatch = CountDownLatch(1)
|
||||
|
||||
@Mock private lateinit var mockDispatcher: OnBackInvokedDispatcher
|
||||
@@ -81,7 +101,8 @@ class ControlsProviderSelectorActivityTest : SysuiTestCase() {
|
||||
listingController,
|
||||
controlsController,
|
||||
userTracker,
|
||||
uiController,
|
||||
authorizedPanelsRepository,
|
||||
dialogFactory,
|
||||
mockDispatcher,
|
||||
latch
|
||||
)
|
||||
@@ -113,13 +134,99 @@ class ControlsProviderSelectorActivityTest : SysuiTestCase() {
|
||||
verify(mockDispatcher).unregisterOnBackInvokedCallback(captureCallback.value)
|
||||
}
|
||||
|
||||
public class TestableControlsProviderSelectorActivity(
|
||||
@Test
|
||||
fun testOnAppSelectedForNonPanelStartsFavoritingActivity() {
|
||||
val info = ControlsServiceInfo(ComponentName("test_pkg", "service"), "", null)
|
||||
activityRule.activity.onAppSelected(info)
|
||||
|
||||
verifyNoMoreInteractions(dialogFactory)
|
||||
|
||||
assertThat(activityRule.activity.lastStartedActivity?.component?.className)
|
||||
.isEqualTo(ControlsFavoritingActivity::class.java.name)
|
||||
|
||||
assertThat(activityRule.activity.triedToFinish).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnAppSelectedForPanelTriggersDialog() {
|
||||
val label = "label"
|
||||
val info =
|
||||
ControlsServiceInfo(
|
||||
ComponentName("test_pkg", "service"),
|
||||
label,
|
||||
ComponentName("test_pkg", "activity")
|
||||
)
|
||||
|
||||
val dialog: Dialog = mock()
|
||||
whenever(dialogFactory.createConfirmationDialog(any(), any(), any())).thenReturn(dialog)
|
||||
|
||||
activityRule.activity.onAppSelected(info)
|
||||
verify(dialogFactory).createConfirmationDialog(any(), eq(label), any())
|
||||
verify(dialog).show()
|
||||
|
||||
assertThat(activityRule.activity.triedToFinish).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogAcceptAddsPackage() {
|
||||
val label = "label"
|
||||
val info =
|
||||
ControlsServiceInfo(
|
||||
ComponentName("test_pkg", "service"),
|
||||
label,
|
||||
ComponentName("test_pkg", "activity")
|
||||
)
|
||||
|
||||
val dialog: Dialog = mock()
|
||||
whenever(dialogFactory.createConfirmationDialog(any(), any(), any())).thenReturn(dialog)
|
||||
|
||||
activityRule.activity.onAppSelected(info)
|
||||
|
||||
val captor: ArgumentCaptor<Consumer<Boolean>> = argumentCaptor()
|
||||
verify(dialogFactory).createConfirmationDialog(any(), any(), capture(captor))
|
||||
|
||||
captor.value.accept(true)
|
||||
|
||||
val setCaptor: ArgumentCaptor<Set<String>> = argumentCaptor()
|
||||
verify(authorizedPanelsRepository).addAuthorizedPanels(capture(setCaptor))
|
||||
assertThat(setCaptor.value).containsExactly(info.componentName.packageName)
|
||||
|
||||
assertThat(activityRule.activity.triedToFinish).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dialogCancelDoesntAddPackage() {
|
||||
val label = "label"
|
||||
val info =
|
||||
ControlsServiceInfo(
|
||||
ComponentName("test_pkg", "service"),
|
||||
label,
|
||||
ComponentName("test_pkg", "activity")
|
||||
)
|
||||
|
||||
val dialog: Dialog = mock()
|
||||
whenever(dialogFactory.createConfirmationDialog(any(), any(), any())).thenReturn(dialog)
|
||||
|
||||
activityRule.activity.onAppSelected(info)
|
||||
|
||||
val captor: ArgumentCaptor<Consumer<Boolean>> = argumentCaptor()
|
||||
verify(dialogFactory).createConfirmationDialog(any(), any(), capture(captor))
|
||||
|
||||
captor.value.accept(false)
|
||||
|
||||
verify(authorizedPanelsRepository, never()).addAuthorizedPanels(any())
|
||||
|
||||
assertThat(activityRule.activity.triedToFinish).isFalse()
|
||||
}
|
||||
|
||||
class TestableControlsProviderSelectorActivity(
|
||||
executor: Executor,
|
||||
backExecutor: Executor,
|
||||
listingController: ControlsListingController,
|
||||
controlsController: ControlsController,
|
||||
userTracker: UserTracker,
|
||||
uiController: ControlsUiController,
|
||||
authorizedPanelsRepository: AuthorizedPanelsRepository,
|
||||
dialogFactory: PanelConfirmationDialogFactory,
|
||||
private val mockDispatcher: OnBackInvokedDispatcher,
|
||||
private val latch: CountDownLatch
|
||||
) :
|
||||
@@ -129,16 +236,50 @@ class ControlsProviderSelectorActivityTest : SysuiTestCase() {
|
||||
listingController,
|
||||
controlsController,
|
||||
userTracker,
|
||||
uiController
|
||||
authorizedPanelsRepository,
|
||||
dialogFactory
|
||||
) {
|
||||
|
||||
var lastStartedActivity: Intent? = null
|
||||
var triedToFinish = false
|
||||
|
||||
override fun getOnBackInvokedDispatcher(): OnBackInvokedDispatcher {
|
||||
return mockDispatcher
|
||||
}
|
||||
|
||||
override fun startActivity(intent: Intent?, options: Bundle?) {
|
||||
lastStartedActivity = intent
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
// ensures that test runner thread does not proceed until ui thread is done
|
||||
latch.countDown()
|
||||
}
|
||||
|
||||
override fun animateExitAndFinish() {
|
||||
// Activity should only be finished from the rule.
|
||||
triedToFinish = true
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun ControlsServiceInfo(
|
||||
componentName: ComponentName,
|
||||
label: CharSequence,
|
||||
panelComponentName: ComponentName? = null
|
||||
): ControlsServiceInfo {
|
||||
val serviceInfo =
|
||||
ServiceInfo().apply {
|
||||
applicationInfo = ApplicationInfo()
|
||||
packageName = componentName.packageName
|
||||
name = componentName.className
|
||||
}
|
||||
return Mockito.spy(ControlsServiceInfo(mock(), serviceInfo)).apply {
|
||||
doReturn(label).`when`(this).loadLabel()
|
||||
doReturn(mock<Drawable>()).`when`(this).loadIcon()
|
||||
doReturn(panelComponentName).`when`(this).panelActivity
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.management
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.phone.SystemUIDialog
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.android.systemui.util.mockito.capture
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when`
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
class PanelConfirmationDialogFactoryTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun testDialogHasCorrectInfo() {
|
||||
val mockDialog: SystemUIDialog = mock() { `when`(context).thenReturn(mContext) }
|
||||
val factory = PanelConfirmationDialogFactory { mockDialog }
|
||||
val appName = "appName"
|
||||
|
||||
factory.createConfirmationDialog(context, appName) {}
|
||||
|
||||
verify(mockDialog).setCanceledOnTouchOutside(true)
|
||||
verify(mockDialog)
|
||||
.setTitle(context.getString(R.string.controls_panel_authorization_title, appName))
|
||||
verify(mockDialog)
|
||||
.setMessage(context.getString(R.string.controls_panel_authorization, appName))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDialogPositiveButton() {
|
||||
val mockDialog: SystemUIDialog = mock() { `when`(context).thenReturn(mContext) }
|
||||
val factory = PanelConfirmationDialogFactory { mockDialog }
|
||||
|
||||
var response: Boolean? = null
|
||||
|
||||
factory.createConfirmationDialog(context, "") { response = it }
|
||||
|
||||
val captor: ArgumentCaptor<DialogInterface.OnClickListener> = argumentCaptor()
|
||||
verify(mockDialog).setPositiveButton(eq(R.string.controls_dialog_ok), capture(captor))
|
||||
|
||||
captor.value.onClick(mockDialog, DialogInterface.BUTTON_POSITIVE)
|
||||
|
||||
assertThat(response).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDialogNeutralButton() {
|
||||
val mockDialog: SystemUIDialog = mock() { `when`(context).thenReturn(mContext) }
|
||||
val factory = PanelConfirmationDialogFactory { mockDialog }
|
||||
|
||||
var response: Boolean? = null
|
||||
|
||||
factory.createConfirmationDialog(context, "") { response = it }
|
||||
|
||||
val captor: ArgumentCaptor<DialogInterface.OnClickListener> = argumentCaptor()
|
||||
verify(mockDialog).setNeutralButton(eq(R.string.cancel), capture(captor))
|
||||
|
||||
captor.value.onClick(mockDialog, DialogInterface.BUTTON_NEUTRAL)
|
||||
|
||||
assertThat(response).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDialogCancel() {
|
||||
val mockDialog: SystemUIDialog = mock() { `when`(context).thenReturn(mContext) }
|
||||
val factory = PanelConfirmationDialogFactory { mockDialog }
|
||||
|
||||
var response: Boolean? = null
|
||||
|
||||
factory.createConfirmationDialog(context, "") { response = it }
|
||||
|
||||
val captor: ArgumentCaptor<DialogInterface.OnCancelListener> = argumentCaptor()
|
||||
verify(mockDialog).setOnCancelListener(capture(captor))
|
||||
|
||||
captor.value.onCancel(mockDialog)
|
||||
|
||||
assertThat(response).isFalse()
|
||||
}
|
||||
}
|
||||
@@ -39,8 +39,10 @@ import com.android.systemui.controls.controller.ControlsController
|
||||
import com.android.systemui.controls.controller.StructureInfo
|
||||
import com.android.systemui.controls.management.ControlsListingController
|
||||
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
|
||||
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
|
||||
import com.android.systemui.controls.settings.FakeControlsSettingsRepository
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.settings.UserFileManager
|
||||
import com.android.systemui.settings.UserTracker
|
||||
@@ -91,6 +93,8 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
|
||||
@Mock lateinit var userTracker: UserTracker
|
||||
@Mock lateinit var taskViewFactory: TaskViewFactory
|
||||
@Mock lateinit var dumpManager: DumpManager
|
||||
@Mock lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository
|
||||
@Mock lateinit var featureFlags: FeatureFlags
|
||||
val sharedPreferences = FakeSharedPreferences()
|
||||
lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
|
||||
|
||||
@@ -132,6 +136,8 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
|
||||
userTracker,
|
||||
Optional.of(taskViewFactory),
|
||||
controlsSettingsRepository,
|
||||
authorizedPanelsRepository,
|
||||
featureFlags,
|
||||
dumpManager
|
||||
)
|
||||
`when`(
|
||||
@@ -240,7 +246,9 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun testPanelCallsTaskViewFactoryCreate() {
|
||||
mockLayoutInflater()
|
||||
val panel = SelectedItem.PanelItem("App name", ComponentName("pkg", "cls"))
|
||||
val packageName = "pkg"
|
||||
`when`(authorizedPanelsRepository.getAuthorizedPanels()).thenReturn(setOf(packageName))
|
||||
val panel = SelectedItem.PanelItem("App name", ComponentName(packageName, "cls"))
|
||||
val serviceInfo = setUpPanel(panel)
|
||||
|
||||
underTest.show(parent, {}, context)
|
||||
@@ -258,9 +266,11 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun testPanelControllerStartActivityWithCorrectArguments() {
|
||||
mockLayoutInflater()
|
||||
val packageName = "pkg"
|
||||
`when`(authorizedPanelsRepository.getAuthorizedPanels()).thenReturn(setOf(packageName))
|
||||
controlsSettingsRepository.setAllowActionOnTrivialControlsInLockscreen(true)
|
||||
|
||||
val panel = SelectedItem.PanelItem("App name", ComponentName("pkg", "cls"))
|
||||
val panel = SelectedItem.PanelItem("App name", ComponentName(packageName, "cls"))
|
||||
val serviceInfo = setUpPanel(panel)
|
||||
|
||||
underTest.show(parent, {}, context)
|
||||
@@ -290,9 +300,11 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun testPendingIntentExtrasAreModified() {
|
||||
mockLayoutInflater()
|
||||
val packageName = "pkg"
|
||||
`when`(authorizedPanelsRepository.getAuthorizedPanels()).thenReturn(setOf(packageName))
|
||||
controlsSettingsRepository.setAllowActionOnTrivialControlsInLockscreen(true)
|
||||
|
||||
val panel = SelectedItem.PanelItem("App name", ComponentName("pkg", "cls"))
|
||||
val panel = SelectedItem.PanelItem("App name", ComponentName(packageName, "cls"))
|
||||
val serviceInfo = setUpPanel(panel)
|
||||
|
||||
underTest.show(parent, {}, context)
|
||||
|
||||
Reference in New Issue
Block a user