summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Matt Pietal <mpietal@google.com> 2020-05-28 17:18:26 -0400
committer Matt Pietal <mpietal@google.com> 2020-05-29 08:43:28 -0400
commit5459e77da593f206d455b3d3503f73599bc1ff8c (patch)
tree84c14fb144ab5683fdfa0ea55d634771db1988a9
parent1f7c8174f002771bbc093cf672c6ce60d7d46230 (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
-rw-r--r--packages/SystemUI/res/values/config.xml6
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt40
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java72
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt63
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)
}