Bind panels with lower priority flags
When showing a panel in device controls, bind to it (but with lower priority flags). That way, the application is kept in memory and results in shorter latency when relaunching the panel with the TaskView. Use BIND_NOT_PERCEPTIBLE so it will be at lower priority from SystemUI. However, don't use WAIVE_PRIORITY, as by itself, it will kill the app once the Task is finished in the device controls panel. Test: manual Test: atest com.android.systemui.controls Fixes: 263790347 Change-Id: Ia99ade528bfdbfe2f67ecfe78f687f18df8b6cfd
This commit is contained in:
@@ -51,12 +51,21 @@ interface ControlsBindingController : UserAwareController {
|
||||
fun bindAndLoadSuggested(component: ComponentName, callback: LoadCallback)
|
||||
|
||||
/**
|
||||
* Request to bind to the given service.
|
||||
* Request to bind to the given service. This should only be used for services using the full
|
||||
* [ControlsProviderService] API, where SystemUI renders the devices' UI.
|
||||
*
|
||||
* @param component The [ComponentName] of the service to bind
|
||||
*/
|
||||
fun bindService(component: ComponentName)
|
||||
|
||||
/**
|
||||
* Bind to a service that provides a Device Controls panel (embedded activity). This will allow
|
||||
* the app to remain "warm", and reduce latency.
|
||||
*
|
||||
* @param component The [ComponentName] of the [ControlsProviderService] to bind.
|
||||
*/
|
||||
fun bindServiceForPanel(component: ComponentName)
|
||||
|
||||
/**
|
||||
* Send a subscribe message to retrieve status of a set of controls.
|
||||
*
|
||||
|
||||
@@ -170,6 +170,10 @@ open class ControlsBindingControllerImpl @Inject constructor(
|
||||
retrieveLifecycleManager(component).bindService()
|
||||
}
|
||||
|
||||
override fun bindServiceForPanel(component: ComponentName) {
|
||||
retrieveLifecycleManager(component).bindServiceForPanel()
|
||||
}
|
||||
|
||||
override fun changeUser(newUser: UserHandle) {
|
||||
if (newUser == currentUser) return
|
||||
|
||||
|
||||
@@ -188,6 +188,14 @@ interface ControlsController : UserAwareController {
|
||||
/** See [ControlsUiController.getPreferredSelectedItem]. */
|
||||
fun getPreferredSelection(): SelectedItem
|
||||
|
||||
/**
|
||||
* Bind to a service that provides a Device Controls panel (embedded activity). This will allow
|
||||
* the app to remain "warm", and reduce latency.
|
||||
*
|
||||
* @param component The [ComponentName] of the [ControlsProviderService] to bind.
|
||||
*/
|
||||
fun bindComponentForPanel(componentName: ComponentName)
|
||||
|
||||
/**
|
||||
* Interface for structure to pass data to [ControlsFavoritingActivity].
|
||||
*/
|
||||
|
||||
@@ -477,6 +477,10 @@ class ControlsControllerImpl @Inject constructor (
|
||||
bindingController.unsubscribe()
|
||||
}
|
||||
|
||||
override fun bindComponentForPanel(componentName: ComponentName) {
|
||||
bindingController.bindServiceForPanel(componentName)
|
||||
}
|
||||
|
||||
override fun addFavorite(
|
||||
componentName: ComponentName,
|
||||
structureName: CharSequence,
|
||||
|
||||
@@ -78,6 +78,10 @@ class ControlsProviderLifecycleManager(
|
||||
private const val DEBUG = true
|
||||
private val BIND_FLAGS = Context.BIND_AUTO_CREATE or Context.BIND_FOREGROUND_SERVICE or
|
||||
Context.BIND_NOT_PERCEPTIBLE
|
||||
// Use BIND_NOT_PERCEPTIBLE so it will be at lower priority from SystemUI.
|
||||
// However, don't use WAIVE_PRIORITY, as by itself, it will kill the app
|
||||
// once the Task is finished in the device controls panel.
|
||||
private val BIND_FLAGS_PANEL = Context.BIND_AUTO_CREATE or Context.BIND_NOT_PERCEPTIBLE
|
||||
}
|
||||
|
||||
private val intent = Intent().apply {
|
||||
@@ -87,18 +91,19 @@ class ControlsProviderLifecycleManager(
|
||||
})
|
||||
}
|
||||
|
||||
private fun bindService(bind: Boolean) {
|
||||
private fun bindService(bind: Boolean, forPanel: Boolean = false) {
|
||||
executor.execute {
|
||||
requiresBound = bind
|
||||
if (bind) {
|
||||
if (bindTryCount != MAX_BIND_RETRIES) {
|
||||
if (bindTryCount != MAX_BIND_RETRIES && wrapper == null) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Binding service $intent")
|
||||
}
|
||||
bindTryCount++
|
||||
try {
|
||||
val flags = if (forPanel) BIND_FLAGS_PANEL else BIND_FLAGS
|
||||
val bound = context
|
||||
.bindServiceAsUser(intent, serviceConnection, BIND_FLAGS, user)
|
||||
.bindServiceAsUser(intent, serviceConnection, flags, user)
|
||||
if (!bound) {
|
||||
context.unbindService(serviceConnection)
|
||||
}
|
||||
@@ -279,6 +284,10 @@ class ControlsProviderLifecycleManager(
|
||||
bindService(true)
|
||||
}
|
||||
|
||||
fun bindServiceForPanel() {
|
||||
bindService(bind = true, forPanel = true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Request unbind from the service.
|
||||
*/
|
||||
|
||||
@@ -232,6 +232,8 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
ControlKey(selected.structure.componentName, it.ci.controlId)
|
||||
}
|
||||
controlsController.get().subscribeToFavorites(selected.structure)
|
||||
} else {
|
||||
controlsController.get().bindComponentForPanel(selected.componentName)
|
||||
}
|
||||
listingCallback = createCallback(::showControlsView)
|
||||
}
|
||||
|
||||
@@ -268,6 +268,14 @@ class ControlsBindingControllerImplTest : SysuiTestCase() {
|
||||
verify(providers[0]).bindService()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBindServiceForPanel() {
|
||||
controller.bindServiceForPanel(TEST_COMPONENT_NAME_1)
|
||||
executor.runAllReady()
|
||||
|
||||
verify(providers[0]).bindServiceForPanel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSubscribe() {
|
||||
val controlInfo1 = ControlInfo("id_1", "", "", DeviceTypes.TYPE_UNKNOWN)
|
||||
|
||||
@@ -919,6 +919,12 @@ class ControlsControllerImplTest : SysuiTestCase() {
|
||||
.getFile(ControlsFavoritePersistenceWrapper.FILE_NAME, context.user.identifier)
|
||||
assertThat(userStructure.file).isNotNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBindForPanel() {
|
||||
controller.bindComponentForPanel(TEST_COMPONENT)
|
||||
verify(bindingController).bindServiceForPanel(TEST_COMPONENT)
|
||||
}
|
||||
}
|
||||
|
||||
private class DidRunRunnable() : Runnable {
|
||||
|
||||
@@ -104,6 +104,22 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() {
|
||||
assertTrue(context.isBound(componentName))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBindForPanel() {
|
||||
manager.bindServiceForPanel()
|
||||
executor.runAllReady()
|
||||
assertTrue(context.isBound(componentName))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnbindPanelIsUnbound() {
|
||||
manager.bindServiceForPanel()
|
||||
executor.runAllReady()
|
||||
manager.unbindService()
|
||||
executor.runAllReady()
|
||||
assertFalse(context.isBound(componentName))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNullBinding() {
|
||||
val mockContext = mock(Context::class.java)
|
||||
|
||||
@@ -228,6 +228,15 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
|
||||
verify(controlsController, never()).refreshStatus(any(), any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPanelBindsForPanel() {
|
||||
val panel = SelectedItem.PanelItem("App name", ComponentName("pkg", "cls"))
|
||||
setUpPanel(panel)
|
||||
|
||||
underTest.show(parent, {}, context)
|
||||
verify(controlsController).bindComponentForPanel(panel.componentName)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPanelCallsTaskViewFactoryCreate() {
|
||||
mockLayoutInflater()
|
||||
|
||||
Reference in New Issue
Block a user