Merge "Added core startable" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
063b05fe0a
@@ -28,12 +28,13 @@ import android.content.pm.ResolveInfo
|
|||||||
import android.content.pm.ServiceInfo
|
import android.content.pm.ServiceInfo
|
||||||
import android.os.UserHandle
|
import android.os.UserHandle
|
||||||
import android.service.controls.ControlsProviderService
|
import android.service.controls.ControlsProviderService
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
import androidx.annotation.WorkerThread
|
import androidx.annotation.WorkerThread
|
||||||
import com.android.settingslib.applications.DefaultAppInfo
|
import com.android.settingslib.applications.DefaultAppInfo
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import java.util.Objects
|
import java.util.Objects
|
||||||
|
|
||||||
class ControlsServiceInfo(
|
open class ControlsServiceInfo(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
val serviceInfo: ServiceInfo
|
val serviceInfo: ServiceInfo
|
||||||
) : DefaultAppInfo(
|
) : DefaultAppInfo(
|
||||||
@@ -64,7 +65,7 @@ class ControlsServiceInfo(
|
|||||||
* [R.array.config_controlsPreferredPackages] can declare activities for use as a panel.
|
* [R.array.config_controlsPreferredPackages] can declare activities for use as a panel.
|
||||||
*/
|
*/
|
||||||
var panelActivity: ComponentName? = null
|
var panelActivity: ComponentName? = null
|
||||||
private set
|
protected set
|
||||||
|
|
||||||
private var resolved: Boolean = false
|
private var resolved: Boolean = false
|
||||||
|
|
||||||
|
|||||||
@@ -121,16 +121,13 @@ class ControlsControllerImpl @Inject constructor (
|
|||||||
userChanging = false
|
userChanging = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private val userTrackerCallback = object : UserTracker.Callback {
|
override fun changeUser(newUser: UserHandle) {
|
||||||
override fun onUserChanged(newUser: Int, userContext: Context) {
|
userChanging = true
|
||||||
userChanging = true
|
if (currentUser == newUser) {
|
||||||
val newUserHandle = UserHandle.of(newUser)
|
userChanging = false
|
||||||
if (currentUser == newUserHandle) {
|
return
|
||||||
userChanging = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setValuesForUser(newUserHandle)
|
|
||||||
}
|
}
|
||||||
|
setValuesForUser(newUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -231,7 +228,6 @@ class ControlsControllerImpl @Inject constructor (
|
|||||||
dumpManager.registerDumpable(javaClass.name, this)
|
dumpManager.registerDumpable(javaClass.name, this)
|
||||||
resetFavorites()
|
resetFavorites()
|
||||||
userChanging = false
|
userChanging = false
|
||||||
userTracker.addCallback(userTrackerCallback, executor)
|
|
||||||
context.registerReceiver(
|
context.registerReceiver(
|
||||||
restoreFinishedReceiver,
|
restoreFinishedReceiver,
|
||||||
IntentFilter(BackupHelper.ACTION_RESTORE_FINISHED),
|
IntentFilter(BackupHelper.ACTION_RESTORE_FINISHED),
|
||||||
@@ -243,7 +239,6 @@ class ControlsControllerImpl @Inject constructor (
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun destroy() {
|
fun destroy() {
|
||||||
userTracker.removeCallback(userTrackerCallback)
|
|
||||||
context.unregisterReceiver(restoreFinishedReceiver)
|
context.unregisterReceiver(restoreFinishedReceiver)
|
||||||
listingController.removeCallback(listingCallback)
|
listingController.removeCallback(listingCallback)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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.dagger
|
||||||
|
|
||||||
|
import com.android.systemui.CoreStartable
|
||||||
|
import com.android.systemui.controls.start.ControlsStartable
|
||||||
|
import dagger.Binds
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.multibindings.ClassKey
|
||||||
|
import dagger.multibindings.IntoMap
|
||||||
|
|
||||||
|
@Module
|
||||||
|
abstract class StartControlsStartableModule {
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ClassKey(ControlsStartable::class)
|
||||||
|
abstract fun bindFeature(impl: ControlsStartable): CoreStartable
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* 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.start
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.os.UserHandle
|
||||||
|
import com.android.systemui.CoreStartable
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.controls.controller.ControlsController
|
||||||
|
import com.android.systemui.controls.dagger.ControlsComponent
|
||||||
|
import com.android.systemui.controls.management.ControlsListingController
|
||||||
|
import com.android.systemui.controls.ui.SelectedItem
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.dagger.qualifiers.Background
|
||||||
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
|
import com.android.systemui.settings.UserTracker
|
||||||
|
import java.util.concurrent.Executor
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Started with SystemUI to perform early operations for device controls subsystem (only if enabled)
|
||||||
|
*
|
||||||
|
* In particular, it will perform the following:
|
||||||
|
* * If there is no preferred selection for provider and at least one of the preferred packages
|
||||||
|
* provides a panel, it will select the first one that does.
|
||||||
|
* * If the preferred selection provides a panel, it will bind to that service (to reduce latency on
|
||||||
|
* displaying the panel).
|
||||||
|
*
|
||||||
|
* It will also perform those operations on user change.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class ControlsStartable
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
@Main private val resources: Resources,
|
||||||
|
@Background private val executor: Executor,
|
||||||
|
private val controlsComponent: ControlsComponent,
|
||||||
|
private val userTracker: UserTracker
|
||||||
|
) : CoreStartable {
|
||||||
|
|
||||||
|
// These two controllers can only be accessed after `start` method once we've checked if the
|
||||||
|
// feature is enabled
|
||||||
|
private val controlsController: ControlsController
|
||||||
|
get() = controlsComponent.getControlsController().get()
|
||||||
|
|
||||||
|
private val controlsListingController: ControlsListingController
|
||||||
|
get() = controlsComponent.getControlsListingController().get()
|
||||||
|
|
||||||
|
private val userTrackerCallback =
|
||||||
|
object : UserTracker.Callback {
|
||||||
|
override fun onUserChanged(newUser: Int, userContext: Context) {
|
||||||
|
controlsController.changeUser(UserHandle.of(newUser))
|
||||||
|
startForUser()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun start() {
|
||||||
|
if (!controlsComponent.isEnabled()) {
|
||||||
|
// Controls is disabled, we don't need this anymore
|
||||||
|
return
|
||||||
|
}
|
||||||
|
startForUser()
|
||||||
|
userTracker.addCallback(userTrackerCallback, executor)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startForUser() {
|
||||||
|
selectDefaultPanelIfNecessary()
|
||||||
|
bindToPanel()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun selectDefaultPanelIfNecessary() {
|
||||||
|
val currentSelection = controlsController.getPreferredSelection()
|
||||||
|
if (currentSelection == SelectedItem.EMPTY_SELECTION) {
|
||||||
|
val availableServices = controlsListingController.getCurrentServices()
|
||||||
|
val panels = availableServices.filter { it.panelActivity != null }
|
||||||
|
resources
|
||||||
|
.getStringArray(R.array.config_controlsPreferredPackages)
|
||||||
|
// Looking for the first element in the string array such that there is one package
|
||||||
|
// that has a panel. It will return null if there are no packages in the array,
|
||||||
|
// or if no packages in the array have a panel associated with it.
|
||||||
|
.firstNotNullOfOrNull { name ->
|
||||||
|
panels.firstOrNull { it.componentName.packageName == name }
|
||||||
|
}
|
||||||
|
?.let { info ->
|
||||||
|
controlsController.setPreferredSelection(
|
||||||
|
SelectedItem.PanelItem(info.loadLabel(), info.componentName)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindToPanel() {
|
||||||
|
val currentSelection = controlsController.getPreferredSelection()
|
||||||
|
val panels =
|
||||||
|
controlsListingController.getCurrentServices().filter { it.panelActivity != null }
|
||||||
|
if (
|
||||||
|
currentSelection is SelectedItem.PanelItem &&
|
||||||
|
panels.firstOrNull { it.componentName == currentSelection.componentName } != null
|
||||||
|
) {
|
||||||
|
controlsController.bindComponentForPanel(currentSelection.componentName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ import com.android.systemui.accessibility.SystemActions
|
|||||||
import com.android.systemui.accessibility.WindowMagnification
|
import com.android.systemui.accessibility.WindowMagnification
|
||||||
import com.android.systemui.biometrics.AuthController
|
import com.android.systemui.biometrics.AuthController
|
||||||
import com.android.systemui.clipboardoverlay.ClipboardListener
|
import com.android.systemui.clipboardoverlay.ClipboardListener
|
||||||
|
import com.android.systemui.controls.dagger.StartControlsStartableModule
|
||||||
import com.android.systemui.dagger.qualifiers.PerUser
|
import com.android.systemui.dagger.qualifiers.PerUser
|
||||||
import com.android.systemui.dreams.DreamMonitor
|
import com.android.systemui.dreams.DreamMonitor
|
||||||
import com.android.systemui.globalactions.GlobalActionsComponent
|
import com.android.systemui.globalactions.GlobalActionsComponent
|
||||||
@@ -65,7 +66,10 @@ import dagger.multibindings.IntoMap
|
|||||||
/**
|
/**
|
||||||
* Collection of {@link CoreStartable}s that should be run on AOSP.
|
* Collection of {@link CoreStartable}s that should be run on AOSP.
|
||||||
*/
|
*/
|
||||||
@Module(includes = [MultiUserUtilsModule::class])
|
@Module(includes = [
|
||||||
|
MultiUserUtilsModule::class,
|
||||||
|
StartControlsStartableModule::class
|
||||||
|
])
|
||||||
abstract class SystemUICoreStartableModule {
|
abstract class SystemUICoreStartableModule {
|
||||||
/** Inject into AuthController. */
|
/** Inject into AuthController. */
|
||||||
@Binds
|
@Binds
|
||||||
|
|||||||
@@ -103,8 +103,6 @@ class ControlsControllerImplTest : SysuiTestCase() {
|
|||||||
private lateinit var controlLoadCallbackCaptor2:
|
private lateinit var controlLoadCallbackCaptor2:
|
||||||
ArgumentCaptor<ControlsBindingController.LoadCallback>
|
ArgumentCaptor<ControlsBindingController.LoadCallback>
|
||||||
|
|
||||||
@Captor
|
|
||||||
private lateinit var userTrackerCallbackCaptor: ArgumentCaptor<UserTracker.Callback>
|
|
||||||
@Captor
|
@Captor
|
||||||
private lateinit var listingCallbackCaptor:
|
private lateinit var listingCallbackCaptor:
|
||||||
ArgumentCaptor<ControlsListingController.ControlsListingCallback>
|
ArgumentCaptor<ControlsListingController.ControlsListingCallback>
|
||||||
@@ -178,10 +176,6 @@ class ControlsControllerImplTest : SysuiTestCase() {
|
|||||||
)
|
)
|
||||||
controller.auxiliaryPersistenceWrapper = auxiliaryPersistenceWrapper
|
controller.auxiliaryPersistenceWrapper = auxiliaryPersistenceWrapper
|
||||||
|
|
||||||
verify(userTracker).addCallback(
|
|
||||||
capture(userTrackerCallbackCaptor), any()
|
|
||||||
)
|
|
||||||
|
|
||||||
verify(listingController).addCallback(capture(listingCallbackCaptor))
|
verify(listingController).addCallback(capture(listingCallbackCaptor))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,7 +533,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
|
|||||||
|
|
||||||
reset(persistenceWrapper)
|
reset(persistenceWrapper)
|
||||||
|
|
||||||
userTrackerCallbackCaptor.value.onUserChanged(otherUser, mContext)
|
controller.changeUser(UserHandle.of(otherUser))
|
||||||
|
|
||||||
verify(persistenceWrapper).changeFileAndBackupManager(any(), any())
|
verify(persistenceWrapper).changeFileAndBackupManager(any(), any())
|
||||||
verify(persistenceWrapper).readFavorites()
|
verify(persistenceWrapper).readFavorites()
|
||||||
|
|||||||
@@ -0,0 +1,281 @@
|
|||||||
|
/*
|
||||||
|
* 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.start
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.ApplicationInfo
|
||||||
|
import android.content.pm.ServiceInfo
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.controls.ControlsServiceInfo
|
||||||
|
import com.android.systemui.controls.controller.ControlsController
|
||||||
|
import com.android.systemui.controls.dagger.ControlsComponent
|
||||||
|
import com.android.systemui.controls.management.ControlsListingController
|
||||||
|
import com.android.systemui.controls.ui.SelectedItem
|
||||||
|
import com.android.systemui.settings.UserTracker
|
||||||
|
import com.android.systemui.util.concurrency.FakeExecutor
|
||||||
|
import com.android.systemui.util.mockito.any
|
||||||
|
import com.android.systemui.util.mockito.mock
|
||||||
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
|
import java.util.Optional
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.never
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.Mockito.verifyZeroInteractions
|
||||||
|
import org.mockito.Mockito.`when`
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class ControlsStartableTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock private lateinit var controlsController: ControlsController
|
||||||
|
@Mock private lateinit var controlsListingController: ControlsListingController
|
||||||
|
@Mock private lateinit var userTracker: UserTracker
|
||||||
|
|
||||||
|
private lateinit var fakeExecutor: FakeExecutor
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
context.orCreateTestableResources.addOverride(
|
||||||
|
R.array.config_controlsPreferredPackages,
|
||||||
|
arrayOf<String>()
|
||||||
|
)
|
||||||
|
|
||||||
|
fakeExecutor = FakeExecutor(FakeSystemClock())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDisabledNothingIsCalled() {
|
||||||
|
createStartable(enabled = false).start()
|
||||||
|
|
||||||
|
verifyZeroInteractions(controlsController, controlsListingController, userTracker)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNoPreferredPackagesNoDefaultSelected_noNewSelection() {
|
||||||
|
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
|
||||||
|
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
|
||||||
|
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
|
||||||
|
|
||||||
|
createStartable(enabled = true).start()
|
||||||
|
|
||||||
|
verify(controlsController, never()).setPreferredSelection(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPreferredPackagesNotInstalled_noNewSelection() {
|
||||||
|
context.orCreateTestableResources.addOverride(
|
||||||
|
R.array.config_controlsPreferredPackages,
|
||||||
|
arrayOf(TEST_PACKAGE_PANEL)
|
||||||
|
)
|
||||||
|
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
|
||||||
|
`when`(controlsListingController.getCurrentServices()).thenReturn(emptyList())
|
||||||
|
|
||||||
|
createStartable(enabled = true).start()
|
||||||
|
|
||||||
|
verify(controlsController, never()).setPreferredSelection(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPreferredPackageNotPanel_noNewSelection() {
|
||||||
|
context.orCreateTestableResources.addOverride(
|
||||||
|
R.array.config_controlsPreferredPackages,
|
||||||
|
arrayOf(TEST_PACKAGE_PANEL)
|
||||||
|
)
|
||||||
|
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
|
||||||
|
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT, "not panel", hasPanel = false))
|
||||||
|
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
|
||||||
|
|
||||||
|
createStartable(enabled = true).start()
|
||||||
|
|
||||||
|
verify(controlsController, never()).setPreferredSelection(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testExistingSelection_noNewSelection() {
|
||||||
|
context.orCreateTestableResources.addOverride(
|
||||||
|
R.array.config_controlsPreferredPackages,
|
||||||
|
arrayOf(TEST_PACKAGE_PANEL)
|
||||||
|
)
|
||||||
|
`when`(controlsController.getPreferredSelection())
|
||||||
|
.thenReturn(mock<SelectedItem.PanelItem>())
|
||||||
|
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
|
||||||
|
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
|
||||||
|
|
||||||
|
createStartable(enabled = true).start()
|
||||||
|
|
||||||
|
verify(controlsController, never()).setPreferredSelection(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPanelAdded() {
|
||||||
|
context.orCreateTestableResources.addOverride(
|
||||||
|
R.array.config_controlsPreferredPackages,
|
||||||
|
arrayOf(TEST_PACKAGE_PANEL)
|
||||||
|
)
|
||||||
|
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
|
||||||
|
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
|
||||||
|
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
|
||||||
|
|
||||||
|
createStartable(enabled = true).start()
|
||||||
|
|
||||||
|
verify(controlsController).setPreferredSelection(listings[0].toPanelItem())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMultiplePreferredOnlyOnePanel_panelAdded() {
|
||||||
|
context.orCreateTestableResources.addOverride(
|
||||||
|
R.array.config_controlsPreferredPackages,
|
||||||
|
arrayOf("other_package", TEST_PACKAGE_PANEL)
|
||||||
|
)
|
||||||
|
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
|
||||||
|
val listings =
|
||||||
|
listOf(
|
||||||
|
ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true),
|
||||||
|
ControlsServiceInfo(ComponentName("other_package", "cls"), "non panel", false)
|
||||||
|
)
|
||||||
|
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
|
||||||
|
|
||||||
|
createStartable(enabled = true).start()
|
||||||
|
|
||||||
|
verify(controlsController).setPreferredSelection(listings[0].toPanelItem())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMultiplePreferredMultiplePanels_firstPreferredAdded() {
|
||||||
|
context.orCreateTestableResources.addOverride(
|
||||||
|
R.array.config_controlsPreferredPackages,
|
||||||
|
arrayOf(TEST_PACKAGE_PANEL, "other_package")
|
||||||
|
)
|
||||||
|
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
|
||||||
|
val listings =
|
||||||
|
listOf(
|
||||||
|
ControlsServiceInfo(ComponentName("other_package", "cls"), "panel", true),
|
||||||
|
ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true)
|
||||||
|
)
|
||||||
|
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
|
||||||
|
|
||||||
|
createStartable(enabled = true).start()
|
||||||
|
|
||||||
|
verify(controlsController).setPreferredSelection(listings[1].toPanelItem())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPreferredSelectionIsPanel_bindOnStart() {
|
||||||
|
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
|
||||||
|
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
|
||||||
|
`when`(controlsController.getPreferredSelection()).thenReturn(listings[0].toPanelItem())
|
||||||
|
|
||||||
|
createStartable(enabled = true).start()
|
||||||
|
|
||||||
|
verify(controlsController).bindComponentForPanel(TEST_COMPONENT_PANEL)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPreferredSelectionPanel_listingNoPanel_notBind() {
|
||||||
|
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = false))
|
||||||
|
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
|
||||||
|
`when`(controlsController.getPreferredSelection())
|
||||||
|
.thenReturn(SelectedItem.PanelItem("panel", TEST_COMPONENT_PANEL))
|
||||||
|
|
||||||
|
createStartable(enabled = true).start()
|
||||||
|
|
||||||
|
verify(controlsController, never()).bindComponentForPanel(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNotPanelSelection_noBind() {
|
||||||
|
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = false))
|
||||||
|
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
|
||||||
|
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
|
||||||
|
|
||||||
|
createStartable(enabled = true).start()
|
||||||
|
|
||||||
|
verify(controlsController, never()).bindComponentForPanel(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createStartable(enabled: Boolean): ControlsStartable {
|
||||||
|
val component: ControlsComponent =
|
||||||
|
mock() {
|
||||||
|
`when`(isEnabled()).thenReturn(enabled)
|
||||||
|
if (enabled) {
|
||||||
|
`when`(getControlsController()).thenReturn(Optional.of(controlsController))
|
||||||
|
`when`(getControlsListingController())
|
||||||
|
.thenReturn(Optional.of(controlsListingController))
|
||||||
|
} else {
|
||||||
|
`when`(getControlsController()).thenReturn(Optional.empty())
|
||||||
|
`when`(getControlsListingController()).thenReturn(Optional.empty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ControlsStartable(context.resources, fakeExecutor, component, userTracker)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ControlsServiceInfo(
|
||||||
|
componentName: ComponentName,
|
||||||
|
label: CharSequence,
|
||||||
|
hasPanel: Boolean
|
||||||
|
): ControlsServiceInfo {
|
||||||
|
val serviceInfo =
|
||||||
|
ServiceInfo().apply {
|
||||||
|
applicationInfo = ApplicationInfo()
|
||||||
|
packageName = componentName.packageName
|
||||||
|
name = componentName.className
|
||||||
|
}
|
||||||
|
return FakeControlsServiceInfo(context, serviceInfo, label, hasPanel)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FakeControlsServiceInfo(
|
||||||
|
context: Context,
|
||||||
|
serviceInfo: ServiceInfo,
|
||||||
|
private val label: CharSequence,
|
||||||
|
hasPanel: Boolean
|
||||||
|
) : ControlsServiceInfo(context, serviceInfo) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (hasPanel) {
|
||||||
|
panelActivity = serviceInfo.componentName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadLabel(): CharSequence {
|
||||||
|
return label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private fun ControlsServiceInfo.toPanelItem(): SelectedItem.PanelItem {
|
||||||
|
if (panelActivity == null) {
|
||||||
|
throw IllegalArgumentException("$this is not a panel")
|
||||||
|
}
|
||||||
|
return SelectedItem.PanelItem(loadLabel(), componentName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val TEST_PACKAGE = "pkg"
|
||||||
|
private val TEST_COMPONENT = ComponentName(TEST_PACKAGE, "service")
|
||||||
|
private const val TEST_PACKAGE_PANEL = "pkg.panel"
|
||||||
|
private val TEST_COMPONENT_PANEL = ComponentName(TEST_PACKAGE_PANEL, "service")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user