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

Commit facf213b authored by Winson Chung's avatar Winson Chung
Browse files

Defer applying gestural nav until the device is provisioned and user is setup

- When SystemUI detects that the device is not provisioned (first boot) or
  the user is not setup (multiuser), we revert to 3button until both
  states are true (usually after setup wizard).  This only happens when
  the default navigation mode of the device is gestural.

Bug: 130185871
Test: Setup a new device and ensure the nav mode is 3 button during SUW

Change-Id: Ia243aa9ebd4a1198b2e06020367625936d1d3f3d
parent 43f311e9
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ import com.android.systemui.util.NotificationChannels;
 */
public class PipNotification {
    private static final String TAG = "PipNotification";
    private static final String NOTIFICATION_TAG = PipNotification.class.getName();
    private static final String NOTIFICATION_TAG = PipNotification.class.getSimpleName();
    private static final boolean DEBUG = PipManager.DEBUG;

    private static final String ACTION_MENU = "PipNotification.menu";
+1 −1
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ import javax.inject.Singleton;
@Singleton
public class NavigationBarController implements Callbacks {

    private static final String TAG = NavigationBarController.class.getName();
    private static final String TAG = NavigationBarController.class.getSimpleName();

    private final Context mContext;
    private final Handler mHandler;
+149 −17
Original line number Diff line number Diff line
@@ -17,8 +17,10 @@
package com.android.systemui.statusbar.phone;

import static android.content.Intent.ACTION_OVERLAY_CHANGED;
import static android.content.Intent.ACTION_USER_SWITCHED;
import static android.os.UserHandle.USER_CURRENT;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;

import android.content.BroadcastReceiver;
import android.content.Context;
@@ -28,16 +30,21 @@ import android.content.om.IOverlayManager;
import android.content.pm.PackageManager;
import android.content.res.ApkAssets;
import android.os.PatternMatcher;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.Log;
import android.util.SparseBooleanArray;

import com.android.systemui.Dumpable;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;

import javax.inject.Inject;
import javax.inject.Singleton;
@@ -48,7 +55,7 @@ import javax.inject.Singleton;
@Singleton
public class NavigationModeController implements Dumpable {

    private static final String TAG = NavigationModeController.class.getName();
    private static final String TAG = NavigationModeController.class.getSimpleName();
    private static final boolean DEBUG = true;

    public interface ModeChangedListener {
@@ -57,6 +64,10 @@ public class NavigationModeController implements Dumpable {

    private final Context mContext;
    private final IOverlayManager mOverlayManager;
    private final DeviceProvisionedController mDeviceProvisionedController;
    private final UiOffloadThread mUiOffloadThread;

    private SparseBooleanArray mRestoreGesturalNavBarMode = new SparseBooleanArray();

    private int mMode = NAV_BAR_MODE_3BUTTON;
    private ArrayList<ModeChangedListener> mListeners = new ArrayList<>();
@@ -64,36 +75,90 @@ public class NavigationModeController implements Dumpable {
    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            context = getCurrentUserContext();
            int mode = getCurrentInteractionMode(context);
            mMode = mode;
            if (intent.getAction().equals(ACTION_OVERLAY_CHANGED)) {
                if (DEBUG) {
                Log.e(TAG, "ACTION_OVERLAY_CHANGED: mode=" + mMode
                        + " contextUser=" + context.getUserId());
                dumpAssetPaths(context);
                    Log.d(TAG, "ACTION_OVERLAY_CHANGED");
                }
                updateCurrentInteractionMode(true /* notify */);
            }
        }
    };

            for (int i = 0; i < mListeners.size(); i++) {
                mListeners.get(i).onNavigationModeChanged(mode);
    private final DeviceProvisionedController.DeviceProvisionedListener mDeviceProvisionedCallback =
            new DeviceProvisionedController.DeviceProvisionedListener() {
                @Override
                public void onDeviceProvisionedChanged() {
                    if (DEBUG) {
                        Log.d(TAG, "onDeviceProvisionedChanged: "
                                + mDeviceProvisionedController.isDeviceProvisioned());
                    }
                    // Once the device has been provisioned, check if we can restore gestural nav
                    restoreGesturalNavOverlayIfNecessary();
                }

                @Override
                public void onUserSetupChanged() {
                    if (DEBUG) {
                        Log.d(TAG, "onUserSetupChanged: "
                                + mDeviceProvisionedController.isCurrentUserSetup());
                    }
                    // Once the user has been setup, check if we can restore gestural nav
                    restoreGesturalNavOverlayIfNecessary();
                }

                @Override
                public void onUserSwitched() {
                    if (DEBUG) {
                        Log.d(TAG, "onUserSwitched: "
                                + ActivityManagerWrapper.getInstance().getCurrentUserId());
                    }

                    // Update the nav mode for the current user
                    updateCurrentInteractionMode(true /* notify */);

                    // When switching users, defer enabling the gestural nav overlay until the user
                    // is all set up
                    deferGesturalNavOverlayIfNecessary();
                }
            };

    @Inject
    public NavigationModeController(Context context) {
    public NavigationModeController(Context context,
            DeviceProvisionedController deviceProvisionedController,
            UiOffloadThread uiOffloadThread) {
        mContext = context;
        mOverlayManager = IOverlayManager.Stub.asInterface(
                ServiceManager.getService(Context.OVERLAY_SERVICE));
        mUiOffloadThread = uiOffloadThread;
        mDeviceProvisionedController = deviceProvisionedController;
        mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);

        IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
        overlayFilter.addDataScheme("package");
        overlayFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL);
        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, overlayFilter, null, null);

        IntentFilter userFilter = new IntentFilter(ACTION_USER_SWITCHED);
        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, userFilter, null, null);
        updateCurrentInteractionMode(false /* notify */);

        // Check if we need to defer enabling gestural nav
        deferGesturalNavOverlayIfNecessary();
    }

    public void updateCurrentInteractionMode(boolean notify) {
        Context context = getCurrentUserContext();
        int mode = getCurrentInteractionMode(context);
        mMode = mode;
        if (DEBUG) {
            Log.e(TAG, "updateCurrentInteractionMode: mode=" + mMode
                    + " contextUser=" + context.getUserId());
            dumpAssetPaths(context);
        }

        mMode = getCurrentInteractionMode(getCurrentUserContext());
        if (notify) {
            for (int i = 0; i < mListeners.size(); i++) {
                mListeners.get(i).onNavigationModeChanged(mode);
            }
        }
    }

    public int addListener(ModeChangedListener listener) {
@@ -129,10 +194,77 @@ public class NavigationModeController implements Dumpable {
        }
    }

    private void deferGesturalNavOverlayIfNecessary() {
        final int userId = mDeviceProvisionedController.getCurrentUser();
        mRestoreGesturalNavBarMode.put(userId, false);
        if (mDeviceProvisionedController.isDeviceProvisioned()
                && mDeviceProvisionedController.isCurrentUserSetup()) {
            // User is already setup and device is provisioned, nothing to do
            if (DEBUG) {
                Log.d(TAG, "deferGesturalNavOverlayIfNecessary: device is provisioned and user is "
                        + "setup");
            }
            return;
        }

        ArrayList<String> defaultOverlays = new ArrayList<>();
        try {
            defaultOverlays.addAll(Arrays.asList(mOverlayManager.getDefaultOverlayPackages()));
        } catch (RemoteException e) {
            Log.e(TAG, "deferGesturalNavOverlayIfNecessary: failed to fetch default overlays");
        }
        if (!defaultOverlays.contains(NAV_BAR_MODE_GESTURAL_OVERLAY)) {
            // No default gesture nav overlay
            if (DEBUG) {
                Log.d(TAG, "deferGesturalNavOverlayIfNecessary: no default gestural overlay, "
                        + "default=" + defaultOverlays);
            }
            return;
        }

        // If the default is gestural, force-enable three button mode until the device is
        // provisioned
        setModeOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY, USER_CURRENT);
        mRestoreGesturalNavBarMode.put(userId, true);
        if (DEBUG) {
            Log.d(TAG, "deferGesturalNavOverlayIfNecessary: setting to 3 button mode");
        }
    }

    private void restoreGesturalNavOverlayIfNecessary() {
        if (DEBUG) {
            Log.d(TAG, "restoreGesturalNavOverlayIfNecessary: needs restore="
                    + mRestoreGesturalNavBarMode);
        }
        final int userId = mDeviceProvisionedController.getCurrentUser();
        if (mRestoreGesturalNavBarMode.get(userId)) {
            // Restore the gestural state if necessary
            setModeOverlay(NAV_BAR_MODE_GESTURAL_OVERLAY, USER_CURRENT);
            mRestoreGesturalNavBarMode.put(userId, false);
        }
    }

    public void setModeOverlay(String overlayPkg, int userId) {
        mUiOffloadThread.submit(() -> {
            try {
                mOverlayManager.setEnabledExclusiveInCategory(overlayPkg, userId);
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to enable overlay " + overlayPkg + " for user " + userId);
            }
        });
    }

    @Override
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        pw.println("NavigationModeController:");
        pw.println("  mode=" + mMode);
        String defaultOverlays = "";
        try {
            defaultOverlays = String.join(", ", mOverlayManager.getDefaultOverlayPackages());
        } catch (RemoteException e) {
            defaultOverlays = "failed_to_fetch";
        }
        pw.println("  defaultOverlays=" + defaultOverlays);
        dumpAssetPaths(getCurrentUserContext());
    }