Distinguish between selected panel or structure

To pave the way, we add a SelectedItem that could contain a
StructureInfo or information for a Panel.

In particular, a Panel points to the ComponentName of the
ControlsProviderService (and not of the activity) for backwards
compatibility and migration. As we still need to match the SelectionInfo
that has the activity information, this is not an issue.

Also, add persistence for the panel using the same keys (and an extra
boolean) for better migration.

Test: atest com.android.systemui.controls
Test: atest DeviceControlsTile
Fixes: 258442632
Change-Id: I544f5cdcb4fdfe0488df05d686173ed3bb709b8e
This commit is contained in:
Fabian Kozynski
2022-11-10 15:48:00 -05:00
parent b0614930ea
commit 82587b1a42
9 changed files with 321 additions and 91 deletions

View File

@@ -24,6 +24,7 @@ import com.android.systemui.controls.ControlStatus
import com.android.systemui.util.UserAwareController import com.android.systemui.util.UserAwareController
import com.android.systemui.controls.management.ControlsFavoritingActivity import com.android.systemui.controls.management.ControlsFavoritingActivity
import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.controls.ui.SelectedItem
import java.util.function.Consumer import java.util.function.Consumer
/** /**
@@ -184,8 +185,8 @@ interface ControlsController : UserAwareController {
*/ */
fun countFavoritesForComponent(componentName: ComponentName): Int fun countFavoritesForComponent(componentName: ComponentName): Int
/** See [ControlsUiController.getPreferredStructure]. */ /** See [ControlsUiController.getPreferredSelectedItem]. */
fun getPreferredStructure(): StructureInfo fun getPreferredSelection(): SelectedItem
/** /**
* Interface for structure to pass data to [ControlsFavoritingActivity]. * Interface for structure to pass data to [ControlsFavoritingActivity].

View File

@@ -38,6 +38,7 @@ import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.controls.ui.SelectedItem
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager import com.android.systemui.dump.DumpManager
@@ -556,8 +557,8 @@ class ControlsControllerImpl @Inject constructor (
) )
} }
override fun getPreferredStructure(): StructureInfo { override fun getPreferredSelection(): SelectedItem {
return uiController.getPreferredStructure(getFavorites()) return uiController.getPreferredSelectedItem(getFavorites())
} }
override fun dump(pw: PrintWriter, args: Array<out String>) { override fun dump(pw: PrintWriter, args: Array<out String>) {

View File

@@ -31,4 +31,9 @@ data class StructureInfo(
val componentName: ComponentName, val componentName: ComponentName,
val structure: CharSequence, val structure: CharSequence,
val controls: List<ControlInfo> val controls: List<ControlInfo>
) ) {
companion object {
val EMPTY_COMPONENT = ComponentName("", "")
val EMPTY_STRUCTURE = StructureInfo(EMPTY_COMPONENT, "", mutableListOf())
}
}

View File

@@ -53,9 +53,43 @@ interface ControlsUiController {
) )
/** /**
* Returns the structure that is currently preferred by the user. * Returns the element that is currently preferred by the user.
* *
* This structure will be the one that appears when the user first opens the controls activity. * This element will be the one that appears when the user first opens the controls activity.
*/ */
fun getPreferredStructure(structures: List<StructureInfo>): StructureInfo fun getPreferredSelectedItem(structures: List<StructureInfo>): SelectedItem
}
sealed class SelectedItem {
abstract val name: CharSequence
abstract val hasControls: Boolean
abstract val componentName: ComponentName
/**
* Represents the currently selected item for a structure.
*/
data class StructureItem(val structure: StructureInfo) : SelectedItem() {
override val name: CharSequence = structure.structure
override val hasControls: Boolean = structure.controls.isNotEmpty()
override val componentName: ComponentName = structure.componentName
}
/**
* Represents the currently selected item for a service that provides a panel activity.
*
* The [componentName] is that of the service, as that is the expected identifier that should
* not change (to always provide proper migration).
*/
data class PanelItem(
val appName: CharSequence,
override val componentName:
ComponentName
) : SelectedItem() {
override val name: CharSequence = appName
override val hasControls: Boolean = true
}
companion object {
val EMPTY_SELECTION: SelectedItem = StructureItem(StructureInfo.EMPTY_STRUCTURE)
}
} }

View File

@@ -41,13 +41,14 @@ import android.widget.LinearLayout
import android.widget.ListPopupWindow import android.widget.ListPopupWindow
import android.widget.Space import android.widget.Space
import android.widget.TextView import android.widget.TextView
import androidx.annotation.VisibleForTesting
import com.android.systemui.R import com.android.systemui.R
import com.android.systemui.controls.ControlsMetricsLogger import com.android.systemui.controls.ControlsMetricsLogger
import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.CustomIconCache import com.android.systemui.controls.CustomIconCache
import com.android.systemui.controls.controller.ControlInfo
import com.android.systemui.controls.controller.ControlsController import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.controller.StructureInfo import com.android.systemui.controls.controller.StructureInfo
import com.android.systemui.controls.controller.StructureInfo.Companion.EMPTY_COMPONENT
import com.android.systemui.controls.management.ControlAdapter import com.android.systemui.controls.management.ControlAdapter
import com.android.systemui.controls.management.ControlsEditingActivity import com.android.systemui.controls.management.ControlsEditingActivity
import com.android.systemui.controls.management.ControlsFavoritingActivity import com.android.systemui.controls.management.ControlsFavoritingActivity
@@ -90,24 +91,17 @@ class ControlsUiControllerImpl @Inject constructor (
companion object { companion object {
private const val PREF_COMPONENT = "controls_component" private const val PREF_COMPONENT = "controls_component"
private const val PREF_STRUCTURE = "controls_structure" private const val PREF_STRUCTURE_OR_APP_NAME = "controls_structure"
private const val PREF_IS_PANEL = "controls_is_panel"
private const val FADE_IN_MILLIS = 200L private const val FADE_IN_MILLIS = 200L
private val EMPTY_COMPONENT = ComponentName("", "")
private val EMPTY_STRUCTURE = StructureInfo(
EMPTY_COMPONENT,
"",
mutableListOf<ControlInfo>()
)
} }
private var selectedStructure: StructureInfo = EMPTY_STRUCTURE private var selectedItem: SelectedItem = SelectedItem.EMPTY_SELECTION
private lateinit var allStructures: List<StructureInfo> private lateinit var allStructures: List<StructureInfo>
private val controlsById = mutableMapOf<ControlKey, ControlWithState>() private val controlsById = mutableMapOf<ControlKey, ControlWithState>()
private val controlViewsById = mutableMapOf<ControlKey, ControlViewHolder>() private val controlViewsById = mutableMapOf<ControlKey, ControlViewHolder>()
private lateinit var parent: ViewGroup private lateinit var parent: ViewGroup
private lateinit var lastItems: List<SelectionItem>
private var popup: ListPopupWindow? = null private var popup: ListPopupWindow? = null
private var hidden = true private var hidden = true
private lateinit var onDismiss: Runnable private lateinit var onDismiss: Runnable
@@ -128,10 +122,12 @@ class ControlsUiControllerImpl @Inject constructor (
private val onSeedingComplete = Consumer<Boolean> { private val onSeedingComplete = Consumer<Boolean> {
accepted -> accepted ->
if (accepted) { if (accepted) {
selectedStructure = controlsController.get().getFavorites().maxByOrNull { selectedItem = controlsController.get().getFavorites().maxByOrNull {
it.controls.size it.controls.size
} ?: EMPTY_STRUCTURE }?.let {
updatePreferences(selectedStructure) SelectedItem.StructureItem(it)
} ?: SelectedItem.EMPTY_SELECTION
updatePreferences(selectedItem)
} }
reload(parent) reload(parent)
} }
@@ -146,7 +142,15 @@ class ControlsUiControllerImpl @Inject constructor (
override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) { override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
val lastItems = serviceInfos.map { val lastItems = serviceInfos.map {
val uid = it.serviceInfo.applicationInfo.uid val uid = it.serviceInfo.applicationInfo.uid
SelectionItem(it.loadLabel(), "", it.loadIcon(), it.componentName, uid)
SelectionItem(
it.loadLabel(),
"",
it.loadIcon(),
it.componentName,
uid,
it.panelActivity
)
} }
uiExecutor.execute { uiExecutor.execute {
parent.removeAllViews() parent.removeAllViews()
@@ -160,11 +164,11 @@ class ControlsUiControllerImpl @Inject constructor (
override fun resolveActivity(): Class<*> { override fun resolveActivity(): Class<*> {
val allStructures = controlsController.get().getFavorites() val allStructures = controlsController.get().getFavorites()
val selectedStructure = getPreferredStructure(allStructures) val selected = getPreferredSelectedItem(allStructures)
return if (controlsController.get().addSeedingFavoritesCallback(onSeedingComplete)) { return if (controlsController.get().addSeedingFavoritesCallback(onSeedingComplete)) {
ControlsActivity::class.java ControlsActivity::class.java
} else if (selectedStructure.controls.isEmpty() && allStructures.size <= 1) { } else if (!selected.hasControls && allStructures.size <= 1) {
ControlsProviderSelectorActivity::class.java ControlsProviderSelectorActivity::class.java
} else { } else {
ControlsActivity::class.java ControlsActivity::class.java
@@ -186,21 +190,24 @@ class ControlsUiControllerImpl @Inject constructor (
controlActionCoordinator.activityContext = activityContext controlActionCoordinator.activityContext = activityContext
allStructures = controlsController.get().getFavorites() allStructures = controlsController.get().getFavorites()
selectedStructure = getPreferredStructure(allStructures) selectedItem = getPreferredSelectedItem(allStructures)
if (controlsController.get().addSeedingFavoritesCallback(onSeedingComplete)) { if (controlsController.get().addSeedingFavoritesCallback(onSeedingComplete)) {
listingCallback = createCallback(::showSeedingView) listingCallback = createCallback(::showSeedingView)
} else if (selectedStructure.controls.isEmpty() && allStructures.size <= 1) { } else if (!selectedItem.hasControls && allStructures.size <= 1) {
// only show initial view if there are really no favorites across any structure // only show initial view if there are really no favorites across any structure
listingCallback = createCallback(::showInitialSetupView) listingCallback = createCallback(::showInitialSetupView)
} else { } else {
selectedStructure.controls.map { val selected = selectedItem
ControlWithState(selectedStructure.componentName, it, null) if (selected is SelectedItem.StructureItem) {
selected.structure.controls.map {
ControlWithState(selected.structure.componentName, it, null)
}.associateByTo(controlsById) { }.associateByTo(controlsById) {
ControlKey(selectedStructure.componentName, it.ci.controlId) ControlKey(selected.structure.componentName, it.ci.controlId)
}
controlsController.get().subscribeToFavorites(selected.structure)
} }
listingCallback = createCallback(::showControlsView) listingCallback = createCallback(::showControlsView)
controlsController.get().subscribeToFavorites(selectedStructure)
} }
controlsListingController.get().addCallback(listingCallback) controlsListingController.get().addCallback(listingCallback)
@@ -297,7 +304,7 @@ class ControlsUiControllerImpl @Inject constructor (
} }
itemsWithStructure.sortWith(localeComparator) itemsWithStructure.sortWith(localeComparator)
val selectionItem = findSelectionItem(selectedStructure, itemsWithStructure) ?: items[0] val selectionItem = findSelectionItem(selectedItem, itemsWithStructure) ?: items[0]
controlsMetricsLogger.refreshBegin(selectionItem.uid, !keyguardStateController.isUnlocked()) controlsMetricsLogger.refreshBegin(selectionItem.uid, !keyguardStateController.isUnlocked())
@@ -307,6 +314,8 @@ class ControlsUiControllerImpl @Inject constructor (
} }
private fun createMenu() { private fun createMenu() {
if (selectedItem !is SelectedItem.StructureItem) return
val selectedStructure = (selectedItem as SelectedItem.StructureItem).structure
val items = arrayOf( val items = arrayOf(
context.resources.getString(R.string.controls_menu_add), context.resources.getString(R.string.controls_menu_add),
context.resources.getString(R.string.controls_menu_edit) context.resources.getString(R.string.controls_menu_edit)
@@ -399,6 +408,8 @@ class ControlsUiControllerImpl @Inject constructor (
} }
private fun createListView(selected: SelectionItem) { private fun createListView(selected: SelectionItem) {
if (selectedItem !is SelectedItem.StructureItem) return
val selectedStructure = (selectedItem as SelectedItem.StructureItem).structure
val inflater = LayoutInflater.from(context) val inflater = LayoutInflater.from(context)
inflater.inflate(R.layout.controls_with_favorites, parent, true) inflater.inflate(R.layout.controls_with_favorites, parent, true)
@@ -453,35 +464,44 @@ class ControlsUiControllerImpl @Inject constructor (
} }
} }
override fun getPreferredStructure(structures: List<StructureInfo>): StructureInfo { override fun getPreferredSelectedItem(structures: List<StructureInfo>): SelectedItem {
if (structures.isEmpty()) return EMPTY_STRUCTURE val sp = sharedPreferences
val component = sharedPreferences.getString(PREF_COMPONENT, null)?.let { val component = sp.getString(PREF_COMPONENT, null)?.let {
ComponentName.unflattenFromString(it) ComponentName.unflattenFromString(it)
} ?: EMPTY_COMPONENT } ?: EMPTY_COMPONENT
val structure = sharedPreferences.getString(PREF_STRUCTURE, "") val name = sp.getString(PREF_STRUCTURE_OR_APP_NAME, "")!!
val isPanel = sp.getBoolean(PREF_IS_PANEL, false)
return structures.firstOrNull { return if (isPanel) {
component == it.componentName && structure == it.structure SelectedItem.PanelItem(name, component)
} ?: structures.get(0) } else {
if (structures.isEmpty()) return SelectedItem.EMPTY_SELECTION
SelectedItem.StructureItem(structures.firstOrNull {
component == it.componentName && name == it.structure
} ?: structures.get(0))
}
} }
private fun updatePreferences(si: StructureInfo) { private fun updatePreferences(si: SelectedItem) {
if (si == EMPTY_STRUCTURE) return
sharedPreferences.edit() sharedPreferences.edit()
.putString(PREF_COMPONENT, si.componentName.flattenToString()) .putString(PREF_COMPONENT, si.componentName.flattenToString())
.putString(PREF_STRUCTURE, si.structure.toString()) .putString(PREF_STRUCTURE_OR_APP_NAME, si.name.toString())
.putBoolean(PREF_IS_PANEL, si is SelectedItem.PanelItem)
.commit() .commit()
} }
private fun switchAppOrStructure(item: SelectionItem) { private fun switchAppOrStructure(item: SelectionItem) {
val newSelection = allStructures.first { val newSelection = if (item.isPanel) {
SelectedItem.PanelItem(item.appName, item.componentName)
} else {
SelectedItem.StructureItem(allStructures.first {
it.structure == item.structure && it.componentName == item.componentName it.structure == item.structure && it.componentName == item.componentName
})
} }
if (newSelection != selectedStructure) { if (newSelection != selectedItem) {
selectedStructure = newSelection selectedItem = newSelection
updatePreferences(selectedStructure) updatePreferences(selectedItem)
reload(parent) reload(parent)
} }
} }
@@ -545,20 +565,37 @@ class ControlsUiControllerImpl @Inject constructor (
return row return row
} }
private fun findSelectionItem(si: StructureInfo, items: List<SelectionItem>): SelectionItem? = private fun findSelectionItem(si: SelectedItem, items: List<SelectionItem>): SelectionItem? =
items.firstOrNull { items.firstOrNull { it.matches(si) }
it.componentName == si.componentName && it.structure == si.structure
}
} }
private data class SelectionItem( @VisibleForTesting
internal data class SelectionItem(
val appName: CharSequence, val appName: CharSequence,
val structure: CharSequence, val structure: CharSequence,
val icon: Drawable, val icon: Drawable,
val componentName: ComponentName, val componentName: ComponentName,
val uid: Int val uid: Int,
val panelComponentName: ComponentName?
) { ) {
fun getTitle() = if (structure.isEmpty()) { appName } else { structure } fun getTitle() = if (structure.isEmpty()) { appName } else { structure }
val isPanel: Boolean = panelComponentName != null
fun matches(selectedItem: SelectedItem): Boolean {
if (componentName != selectedItem.componentName) {
// Not the same component so they are not the same.
return false
}
if (isPanel || selectedItem is SelectedItem.PanelItem) {
// As they have the same component, if [this.isPanel] then we may be migrating from
// device controls API into panel. Want this to match, even if the selectedItem is not
// a panel. We don't want to match on app name because that can change with locale.
return true
}
// Return true if we find a structure with the correct name
return structure == (selectedItem as SelectedItem.StructureItem).structure.structure
}
} }
private class ItemAdapter( private class ItemAdapter(

View File

@@ -32,6 +32,7 @@ import com.android.systemui.controls.dagger.ControlsComponent
import com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE import com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE
import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ui.ControlsUiController 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.Background
import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
@@ -125,14 +126,15 @@ class DeviceControlsTile @Inject constructor(
state.icon = icon state.icon = icon
if (controlsComponent.isEnabled() && hasControlsApps.get()) { if (controlsComponent.isEnabled() && hasControlsApps.get()) {
if (controlsComponent.getVisibility() == AVAILABLE) { if (controlsComponent.getVisibility() == AVAILABLE) {
val structureInfo = controlsComponent val selection = controlsComponent
.getControlsController().get().getPreferredStructure() .getControlsController().get().getPreferredSelection()
state.state = if (structureInfo.controls.isEmpty()) { state.state = if (selection is SelectedItem.StructureItem &&
selection.structure.controls.isEmpty()) {
Tile.STATE_INACTIVE Tile.STATE_INACTIVE
} else { } else {
Tile.STATE_ACTIVE Tile.STATE_ACTIVE
} }
val label = structureInfo.structure val label = selection.name
state.secondaryLabel = if (label == tileLabel) null else label state.secondaryLabel = if (label == tileLabel) null else label
} else { } else {
state.state = Tile.STATE_INACTIVE state.state = Tile.STATE_INACTIVE

View File

@@ -44,7 +44,6 @@ import org.mockito.Mock
import org.mockito.Mockito.anyInt import org.mockito.Mockito.anyInt
import org.mockito.Mockito.anyString import org.mockito.Mockito.anyString
import org.mockito.Mockito.mock import org.mockito.Mockito.mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
@@ -105,8 +104,8 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
@Test @Test
fun testGetPreferredStructure() { fun testGetPreferredStructure() {
val structureInfo = mock(StructureInfo::class.java) val structureInfo = mock(StructureInfo::class.java)
underTest.getPreferredStructure(listOf(structureInfo)) underTest.getPreferredSelectedItem(listOf(structureInfo))
verify(userFileManager, times(2)) verify(userFileManager)
.getSharedPreferences( .getSharedPreferences(
fileName = DeviceControlsControllerImpl.PREFS_CONTROLS_FILE, fileName = DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
mode = 0, mode = 0,
@@ -116,25 +115,30 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
@Test @Test
fun testGetPreferredStructure_differentUserId() { fun testGetPreferredStructure_differentUserId() {
val structureInfo = val selectedItems =
listOf( listOf(
StructureInfo(ComponentName.unflattenFromString("pkg/.cls1"), "a", ArrayList()), SelectedItem.StructureItem(
StructureInfo(ComponentName.unflattenFromString("pkg/.cls2"), "b", ArrayList()), StructureInfo(ComponentName.unflattenFromString("pkg/.cls1"), "a", ArrayList())
),
SelectedItem.StructureItem(
StructureInfo(ComponentName.unflattenFromString("pkg/.cls2"), "b", ArrayList())
),
) )
val structures = selectedItems.map { it.structure }
sharedPreferences sharedPreferences
.edit() .edit()
.putString("controls_component", structureInfo[0].componentName.flattenToString()) .putString("controls_component", selectedItems[0].componentName.flattenToString())
.putString("controls_structure", structureInfo[0].structure.toString()) .putString("controls_structure", selectedItems[0].name.toString())
.commit() .commit()
val differentSharedPreferences = FakeSharedPreferences() val differentSharedPreferences = FakeSharedPreferences()
differentSharedPreferences differentSharedPreferences
.edit() .edit()
.putString("controls_component", structureInfo[1].componentName.flattenToString()) .putString("controls_component", selectedItems[1].componentName.flattenToString())
.putString("controls_structure", structureInfo[1].structure.toString()) .putString("controls_structure", selectedItems[1].name.toString())
.commit() .commit()
val previousPreferredStructure = underTest.getPreferredStructure(structureInfo) val previousPreferredStructure = underTest.getPreferredSelectedItem(structures)
`when`( `when`(
userFileManager.getSharedPreferences( userFileManager.getSharedPreferences(
@@ -146,10 +150,25 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
.thenReturn(differentSharedPreferences) .thenReturn(differentSharedPreferences)
`when`(userTracker.userId).thenReturn(1) `when`(userTracker.userId).thenReturn(1)
val currentPreferredStructure = underTest.getPreferredStructure(structureInfo) val currentPreferredStructure = underTest.getPreferredSelectedItem(structures)
assertThat(previousPreferredStructure).isEqualTo(structureInfo[0]) assertThat(previousPreferredStructure).isEqualTo(selectedItems[0])
assertThat(currentPreferredStructure).isEqualTo(structureInfo[1]) assertThat(currentPreferredStructure).isEqualTo(selectedItems[1])
assertThat(currentPreferredStructure).isNotEqualTo(previousPreferredStructure) assertThat(currentPreferredStructure).isNotEqualTo(previousPreferredStructure)
} }
@Test
fun testGetPreferredPanel() {
val panel = SelectedItem.PanelItem("App name", ComponentName("pkg", "cls"))
sharedPreferences
.edit()
.putString("controls_component", panel.componentName.flattenToString())
.putString("controls_structure", panel.appName.toString())
.putBoolean("controls_is_panel", true)
.commit()
val selected = underTest.getPreferredSelectedItem(emptyList())
assertThat(selected).isEqualTo(panel)
}
} }

View File

@@ -0,0 +1,112 @@
package com.android.systemui.controls.ui
import android.content.ComponentName
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.controller.StructureInfo
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidTestingRunner::class)
class SelectionItemTest : SysuiTestCase() {
@Test
fun testMatchBadComponentName_false() {
val selectionItem =
SelectionItem(
appName = "app",
structure = "structure",
icon = mock(),
componentName = ComponentName("pkg", "cls"),
uid = 0,
panelComponentName = null
)
assertThat(
selectionItem.matches(
SelectedItem.StructureItem(
StructureInfo(ComponentName("", ""), "s", emptyList())
)
)
)
.isFalse()
assertThat(selectionItem.matches(SelectedItem.PanelItem("name", ComponentName("", ""))))
.isFalse()
}
@Test
fun testMatchSameComponentName_panelSelected_true() {
val componentName = ComponentName("pkg", "cls")
val selectionItem =
SelectionItem(
appName = "app",
structure = "structure",
icon = mock(),
componentName = componentName,
uid = 0,
panelComponentName = null
)
assertThat(selectionItem.matches(SelectedItem.PanelItem("name", componentName))).isTrue()
}
@Test
fun testMatchSameComponentName_panelSelection_true() {
val componentName = ComponentName("pkg", "cls")
val selectionItem =
SelectionItem(
appName = "app",
structure = "structure",
icon = mock(),
componentName = componentName,
uid = 0,
panelComponentName = ComponentName("pkg", "panel")
)
assertThat(selectionItem.matches(SelectedItem.PanelItem("name", componentName))).isTrue()
}
@Test
fun testMatchSameComponentSameStructure_true() {
val componentName = ComponentName("pkg", "cls")
val structureName = "structure"
val structureItem =
SelectedItem.StructureItem(StructureInfo(componentName, structureName, emptyList()))
val selectionItem =
SelectionItem(
appName = "app",
structure = structureName,
icon = mock(),
componentName = componentName,
uid = 0,
panelComponentName = null
)
assertThat(selectionItem.matches(structureItem)).isTrue()
}
@Test
fun testMatchSameComponentDifferentStructure_false() {
val componentName = ComponentName("pkg", "cls")
val structureName = "structure"
val structureItem =
SelectedItem.StructureItem(StructureInfo(componentName, structureName, emptyList()))
val selectionItem =
SelectionItem(
appName = "app",
structure = "other",
icon = mock(),
componentName = componentName,
uid = 0,
panelComponentName = null
)
assertThat(selectionItem.matches(structureItem)).isFalse()
}
}

View File

@@ -40,6 +40,7 @@ import com.android.systemui.controls.dagger.ControlsComponent
import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ui.ControlsActivity import com.android.systemui.controls.ui.ControlsActivity
import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.controls.ui.SelectedItem
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost import com.android.systemui.qs.QSHost
@@ -118,8 +119,9 @@ class DeviceControlsTileTest : SysuiTestCase() {
`when`(qsHost.context).thenReturn(spiedContext) `when`(qsHost.context).thenReturn(spiedContext)
`when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger)
`when`(controlsComponent.isEnabled()).thenReturn(true) `when`(controlsComponent.isEnabled()).thenReturn(true)
`when`(controlsController.getPreferredStructure()) `when`(controlsController.getPreferredSelection())
.thenReturn(StructureInfo(ComponentName("pkg", "cls"), "structure", listOf())) .thenReturn(SelectedItem.StructureItem(
StructureInfo(ComponentName("pkg", "cls"), "structure", listOf())))
secureSettings.putInt(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, 1) secureSettings.putInt(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, 1)
setupControlsComponent() setupControlsComponent()
@@ -226,12 +228,12 @@ class DeviceControlsTileTest : SysuiTestCase() {
capture(listingCallbackCaptor) capture(listingCallbackCaptor)
) )
`when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE) `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
`when`(controlsController.getPreferredStructure()).thenReturn( `when`(controlsController.getPreferredSelection()).thenReturn(
StructureInfo( SelectedItem.StructureItem(StructureInfo(
ComponentName("pkg", "cls"), ComponentName("pkg", "cls"),
"structure", "structure",
listOf(ControlInfo("id", "title", "subtitle", 1)) listOf(ControlInfo("id", "title", "subtitle", 1))
) ))
) )
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
@@ -247,8 +249,9 @@ class DeviceControlsTileTest : SysuiTestCase() {
capture(listingCallbackCaptor) capture(listingCallbackCaptor)
) )
`when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE) `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
`when`(controlsController.getPreferredStructure()) `when`(controlsController.getPreferredSelection())
.thenReturn(StructureInfo(ComponentName("pkg", "cls"), "structure", listOf())) .thenReturn(SelectedItem.StructureItem(
StructureInfo(ComponentName("pkg", "cls"), "structure", listOf())))
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
testableLooper.processAllMessages() testableLooper.processAllMessages()
@@ -256,6 +259,22 @@ class DeviceControlsTileTest : SysuiTestCase() {
assertThat(tile.state.state).isEqualTo(Tile.STATE_INACTIVE) assertThat(tile.state.state).isEqualTo(Tile.STATE_INACTIVE)
} }
@Test
fun testStateActiveIfPreferredIsPanel() {
verify(controlsListingController).observe(
any(LifecycleOwner::class.java),
capture(listingCallbackCaptor)
)
`when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
`when`(controlsController.getPreferredSelection())
.thenReturn(SelectedItem.PanelItem("appName", ComponentName("pkg", "cls")))
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
testableLooper.processAllMessages()
assertThat(tile.state.state).isEqualTo(Tile.STATE_ACTIVE)
}
@Test @Test
fun testStateInactiveIfLocked() { fun testStateInactiveIfLocked() {
verify(controlsListingController).observe( verify(controlsListingController).observe(
@@ -303,12 +322,12 @@ class DeviceControlsTileTest : SysuiTestCase() {
) )
`when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE) `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
`when`(controlsUiController.resolveActivity()).thenReturn(ControlsActivity::class.java) `when`(controlsUiController.resolveActivity()).thenReturn(ControlsActivity::class.java)
`when`(controlsController.getPreferredStructure()).thenReturn( `when`(controlsController.getPreferredSelection()).thenReturn(
StructureInfo( SelectedItem.StructureItem(StructureInfo(
ComponentName("pkg", "cls"), ComponentName("pkg", "cls"),
"structure", "structure",
listOf(ControlInfo("id", "title", "subtitle", 1)) listOf(ControlInfo("id", "title", "subtitle", 1))
) ))
) )
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
@@ -334,12 +353,12 @@ class DeviceControlsTileTest : SysuiTestCase() {
`when`(controlsComponent.getVisibility()) `when`(controlsComponent.getVisibility())
.thenReturn(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK) .thenReturn(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK)
`when`(controlsUiController.resolveActivity()).thenReturn(ControlsActivity::class.java) `when`(controlsUiController.resolveActivity()).thenReturn(ControlsActivity::class.java)
`when`(controlsController.getPreferredStructure()).thenReturn( `when`(controlsController.getPreferredSelection()).thenReturn(
StructureInfo( SelectedItem.StructureItem(StructureInfo(
ComponentName("pkg", "cls"), ComponentName("pkg", "cls"),
"structure", "structure",
listOf(ControlInfo("id", "title", "subtitle", 1)) listOf(ControlInfo("id", "title", "subtitle", 1))
) ))
) )
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))