Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5459e77d authored by Matt Pietal's avatar Matt Pietal
Browse files

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
parent 1f7c8174
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -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>
+7 −5
Original line number Diff line number Diff line
@@ -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)
+29 −11
Original line number Diff line number Diff line
@@ -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)
                    }
                }
            }
+1 −1
Original line number Diff line number Diff line
@@ -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))
+42 −30
Original line number Diff line number Diff line
@@ -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;
            String pkg = info.componentName.getPackageName();
            if (seededPackages.contains(pkg)
                    || mControlsControllerOptional.get().countFavoritesForComponent(
                            info.componentName) > 0) {
                continue;
            }

            for (int i = 0; i < Math.min(SEEDING_MAX, preferredControlsPackages.length); i++) {
                if (pkg.equals(preferredControlsPackages[i])) {
                    componentsToSeed.add(info.componentName);
                    break;
                }
            }

        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;
        }

        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();
                    }
                });
    }

Loading