diff options
| author | 2020-05-28 17:18:26 -0400 | |
|---|---|---|
| committer | 2020-05-29 08:43:28 -0400 | |
| commit | 5459e77da593f206d455b3d3503f73599bc1ff8c (patch) | |
| tree | 84c14fb144ab5683fdfa0ea55d634771db1988a9 | |
| parent | 1f7c8174f002771bbc093cf672c6ce60d7d46230 (diff) | |
Controls UI - Allow seeding for multiple apps
Allow up to 2 applications to seed controls into the space. Save the
seeding state of each component separately, to be able to reattempt to
seed at a later time on failure.
Fixes: 155083005
Test: atest ControlsControllerImplTest
Change-Id: I28bed9bb0b221a3e5c9b293ed9d3f85e86404a38
6 files changed, 125 insertions, 70 deletions
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 14075743ce34..00537ff0466d 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -540,10 +540,10 @@ <!-- Respect drawable/rounded.xml intrinsic size for multiple radius corner path customization --> <bool name="config_roundedCornerMultipleRadius">false</bool> - <!-- Controls can query a preferred application for limited number of suggested controls. - This config value should contain the package name of that preferred application. + <!-- Controls can query 2 preferred applications for limited number of suggested controls. + This config value should contain a list of package names of thoses preferred applications. --> - <string translatable="false" name="config_controlsPreferredPackage"></string> + <string-array translatable="false" name="config_controlsPreferredPackages" /> <!-- Max number of columns for quick controls area --> <integer name="controls_max_columns">2</integer> diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt index 8196a256731a..07319207d9ab 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt @@ -114,12 +114,12 @@ interface ControlsController : UserAwareController { /** * Send a request to seed favorites into the persisted XML file * - * @param componentName the component to seed controls from - * @param callback true if the favorites were persisted + * @param componentNames the list of components to seed controls from + * @param callback one [SeedResponse] per componentName */ - fun seedFavoritesForComponent( - componentName: ComponentName, - callback: Consumer<Boolean> + fun seedFavoritesForComponents( + componentNames: List<ComponentName>, + callback: Consumer<SeedResponse> ) /** @@ -235,3 +235,5 @@ fun createLoadDataObject( override val errorOnLoad = error } } + +data class SeedResponse(val packageName: String, val accepted: Boolean) diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt index dc727dfb36ea..fd9fda3662a3 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt @@ -362,29 +362,47 @@ class ControlsControllerImpl @Inject constructor ( return true } - override fun seedFavoritesForComponent( - componentName: ComponentName, - callback: Consumer<Boolean> + override fun seedFavoritesForComponents( + componentNames: List<ComponentName>, + callback: Consumer<SeedResponse> ) { - if (seedingInProgress) return + if (seedingInProgress || componentNames.isEmpty()) return - Log.i(TAG, "Beginning request to seed favorites for: $componentName") if (!confirmAvailability()) { if (userChanging) { // Try again later, userChanging should not last forever. If so, we have bigger // problems. This will return a runnable that allows to cancel the delayed version, // it will not be able to cancel the load if executor.executeDelayed( - { seedFavoritesForComponent(componentName, callback) }, + { seedFavoritesForComponents(componentNames, callback) }, USER_CHANGE_RETRY_DELAY, TimeUnit.MILLISECONDS ) } else { - callback.accept(false) + componentNames.forEach { + callback.accept(SeedResponse(it.packageName, false)) + } } return } seedingInProgress = true + startSeeding(componentNames, callback, false) + } + + private fun startSeeding( + remainingComponentNames: List<ComponentName>, + callback: Consumer<SeedResponse>, + didAnyFail: Boolean + ) { + if (remainingComponentNames.isEmpty()) { + endSeedingCall(!didAnyFail) + return + } + + val componentName = remainingComponentNames[0] + Log.d(TAG, "Beginning request to seed favorites for: $componentName") + + val remaining = remainingComponentNames.drop(1) bindingController.bindAndLoadSuggested( componentName, object : ControlsBindingController.LoadCallback { @@ -410,16 +428,16 @@ class ControlsControllerImpl @Inject constructor ( } persistenceWrapper.storeFavorites(Favorites.getAllStructures()) - callback.accept(true) - endSeedingCall(true) + callback.accept(SeedResponse(componentName.packageName, true)) + startSeeding(remaining, callback, didAnyFail) } } override fun error(message: String) { Log.e(TAG, "Unable to seed favorites: $message") executor.execute { - callback.accept(false) - endSeedingCall(false) + callback.accept(SeedResponse(componentName.packageName, false)) + startSeeding(remaining, callback, true) } } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index 606e94760946..35ebac5b1ed5 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -328,7 +328,7 @@ class ControlsUiControllerImpl @Inject constructor ( val userContext = context.createContextAsUser(userHandle, 0) val prefs = userContext.getSharedPreferences( "controls_prefs", Context.MODE_PRIVATE) - prefs.edit().putBoolean("ControlsSeedingCompleted", false).apply() + prefs.edit().remove("SeedingCompleted").apply() controlsController.get().resetFavorites() dialog.dismiss() context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 0f3a94b74342..bee5e69078cb 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -139,8 +139,11 @@ import com.android.systemui.util.RingerModeTracker; import com.android.systemui.util.leak.RotationUtils; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.concurrent.Executor; import javax.inject.Inject; @@ -180,8 +183,9 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency"; static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot"; - private static final String PREFS_CONTROLS_SEEDING_COMPLETED = "ControlsSeedingCompleted"; + private static final String PREFS_CONTROLS_SEEDING_COMPLETED = "SeedingCompleted"; private static final String PREFS_CONTROLS_FILE = "controls_prefs"; + private static final int SEEDING_MAX = 2; private final Context mContext; private final GlobalActionsManager mWindowManagerFuncs; @@ -409,47 +413,55 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, }); } + /** + * See if any available control service providers match one of the preferred components. If + * they do, and there are no current favorites for that component, query the preferred + * component for a limited number of suggested controls. + */ private void seedFavorites() { - if (!mControlsControllerOptional.isPresent()) return; - if (mControlsServiceInfos.isEmpty() - || mControlsControllerOptional.get().getFavorites().size() > 0) { + if (!mControlsControllerOptional.isPresent() + || mControlsServiceInfos.isEmpty()) { return; } - // Need to be user-specific with the context to make sure we read the correct prefs + String[] preferredControlsPackages = mContext.getResources() + .getStringArray(com.android.systemui.R.array.config_controlsPreferredPackages); + SharedPreferences prefs = mCurrentUserContextTracker.getCurrentUserContext() .getSharedPreferences(PREFS_CONTROLS_FILE, Context.MODE_PRIVATE); - if (prefs.getBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, false)) { - return; - } - - /* - * See if any service providers match the preferred component. If they do, - * and there are no current favorites, and we haven't successfully loaded favorites to - * date, query the preferred component for a limited number of suggested controls. - */ - String preferredControlsPackage = mContext.getResources() - .getString(com.android.systemui.R.string.config_controlsPreferredPackage); + Set<String> seededPackages = prefs.getStringSet(PREFS_CONTROLS_SEEDING_COMPLETED, + Collections.emptySet()); - ComponentName preferredComponent = null; + List<ComponentName> componentsToSeed = new ArrayList<>(); for (ControlsServiceInfo info : mControlsServiceInfos) { - if (info.componentName.getPackageName().equals(preferredControlsPackage)) { - preferredComponent = info.componentName; - break; + String pkg = info.componentName.getPackageName(); + if (seededPackages.contains(pkg) + || mControlsControllerOptional.get().countFavoritesForComponent( + info.componentName) > 0) { + continue; } - } - if (preferredComponent == null) { - Log.i(TAG, "Controls seeding: No preferred component has been set, will not seed"); - prefs.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, true).apply(); - return; + for (int i = 0; i < Math.min(SEEDING_MAX, preferredControlsPackages.length); i++) { + if (pkg.equals(preferredControlsPackages[i])) { + componentsToSeed.add(info.componentName); + break; + } + } } - mControlsControllerOptional.get().seedFavoritesForComponent( - preferredComponent, - (accepted) -> { - Log.i(TAG, "Controls seeded: " + accepted); - prefs.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, accepted).apply(); + if (componentsToSeed.isEmpty()) return; + + mControlsControllerOptional.get().seedFavoritesForComponents( + componentsToSeed, + (response) -> { + Log.d(TAG, "Controls seeded: " + response); + Set<String> completedPkgs = prefs.getStringSet(PREFS_CONTROLS_SEEDING_COMPLETED, + new HashSet<String>()); + if (response.getAccepted()) { + completedPkgs.add(response.getPackageName()); + prefs.edit().putStringSet(PREFS_CONTROLS_SEEDING_COMPLETED, + completedPkgs).apply(); + } }); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt index 05e676db9913..45262c7788f1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt @@ -89,6 +89,9 @@ class ControlsControllerImplTest : SysuiTestCase() { @Captor private lateinit var controlLoadCallbackCaptor: ArgumentCaptor<ControlsBindingController.LoadCallback> + @Captor + private lateinit var controlLoadCallbackCaptor2: + ArgumentCaptor<ControlsBindingController.LoadCallback> @Captor private lateinit var broadcastReceiverCaptor: ArgumentCaptor<BroadcastReceiver> @@ -797,43 +800,63 @@ class ControlsControllerImplTest : SysuiTestCase() { } @Test - fun testSeedFavoritesForComponentWithLimit() { - var succeeded = false + fun testSeedFavoritesForComponentsWithLimit() { + var responses = mutableListOf<SeedResponse>() - val controls = mutableListOf<Control>() + val controls1 = mutableListOf<Control>() for (i in 1..10) { - controls.add(statelessBuilderFromInfo(ControlInfo("id$i", TEST_CONTROL_TITLE, + controls1.add(statelessBuilderFromInfo(ControlInfo("id1:$i", TEST_CONTROL_TITLE, TEST_CONTROL_SUBTITLE, TEST_DEVICE_TYPE), "testStructure").build()) } - controller.seedFavoritesForComponent(TEST_COMPONENT, Consumer { accepted -> - succeeded = accepted + val controls2 = mutableListOf<Control>() + for (i in 1..3) { + controls2.add(statelessBuilderFromInfo(ControlInfo("id2:$i", TEST_CONTROL_TITLE, + TEST_CONTROL_SUBTITLE, TEST_DEVICE_TYPE), "testStructure2").build()) + } + controller.seedFavoritesForComponents(listOf(TEST_COMPONENT, TEST_COMPONENT_2), Consumer { + resp -> responses.add(resp) }) verify(bindingController).bindAndLoadSuggested(eq(TEST_COMPONENT), capture(controlLoadCallbackCaptor)) + controlLoadCallbackCaptor.value.accept(controls1) + delayableExecutor.runAllReady() - controlLoadCallbackCaptor.value.accept(controls) - + verify(bindingController).bindAndLoadSuggested(eq(TEST_COMPONENT_2), + capture(controlLoadCallbackCaptor2)) + controlLoadCallbackCaptor2.value.accept(controls2) delayableExecutor.runAllReady() + // COMPONENT 1 val structureInfo = controller.getFavoritesForComponent(TEST_COMPONENT)[0] assertEquals(structureInfo.controls.size, ControlsControllerImpl.SUGGESTED_CONTROLS_PER_STRUCTURE) var i = 1 structureInfo.controls.forEach { - assertEquals(it.controlId, "id$i") + assertEquals(it.controlId, "id1:$i") + i++ + } + assertEquals(SeedResponse(TEST_COMPONENT.packageName, true), responses[0]) + + // COMPONENT 2 + val structureInfo2 = controller.getFavoritesForComponent(TEST_COMPONENT_2)[0] + assertEquals(structureInfo2.controls.size, 3) + + i = 1 + structureInfo2.controls.forEach { + assertEquals(it.controlId, "id2:$i") i++ } - assertTrue(succeeded) + assertEquals(SeedResponse(TEST_COMPONENT.packageName, true), responses[1]) } @Test - fun testSeedFavoritesForComponent_error() { - var succeeded = false + fun testSeedFavoritesForComponents_error() { + var response: SeedResponse? = null - controller.seedFavoritesForComponent(TEST_COMPONENT, Consumer { accepted -> - succeeded = accepted + controller.seedFavoritesForComponents(listOf(TEST_COMPONENT), Consumer { resp -> + response = resp }) verify(bindingController).bindAndLoadSuggested(eq(TEST_COMPONENT), @@ -844,18 +867,18 @@ class ControlsControllerImplTest : SysuiTestCase() { delayableExecutor.runAllReady() assertEquals(listOf<StructureInfo>(), controller.getFavoritesForComponent(TEST_COMPONENT)) - assertFalse(succeeded) + assertEquals(SeedResponse(TEST_COMPONENT.packageName, false), response) } @Test - fun testSeedFavoritesForComponent_inProgressCallback() { - var succeeded = false + fun testSeedFavoritesForComponents_inProgressCallback() { + var response: SeedResponse? = null var seeded = false val control = statelessBuilderFromInfo(TEST_CONTROL_INFO, TEST_STRUCTURE_INFO.structure) .build() - controller.seedFavoritesForComponent(TEST_COMPONENT, Consumer { accepted -> - succeeded = accepted + controller.seedFavoritesForComponents(listOf(TEST_COMPONENT), Consumer { resp -> + response = resp }) verify(bindingController).bindAndLoadSuggested(eq(TEST_COMPONENT), @@ -870,7 +893,7 @@ class ControlsControllerImplTest : SysuiTestCase() { assertEquals(listOf(TEST_STRUCTURE_INFO), controller.getFavoritesForComponent(TEST_COMPONENT)) - assertTrue(succeeded) + assertEquals(SeedResponse(TEST_COMPONENT.packageName, true), response) assertTrue(seeded) } |