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

Commit 56d145fe authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Autoenabling gesture mode only is the device is unmanaged

> Adding a protected broadcast to enable gesture mode

If the device is not managed, gesture mode will be wnabled once setup-wizard
finishes. Otherwise, it will wait for a protected broadcast from the device/profile
owner app which can switch the device to gesture mode.

Bug: 134473386
Test: Verified on device setup in device owner and profile owner mode
Change-Id: I7d32d5461eef19a30f323295c7a9bac975adbf91
parent 3d9cc127
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -49,6 +49,15 @@ public class QuickStepContract {
    public static final String NAV_BAR_MODE_GESTURAL_OVERLAY =
            WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;

    // Action sent by a system app to switch to gesture nav
    public static final String ACTION_ENABLE_GESTURE_NAV =
            "com.android.systemui.ENABLE_GESTURE_NAV";
    // Action for the intent to receive the result
    public static final String ACTION_ENABLE_GESTURE_NAV_RESULT =
            "com.android.systemui.action.ENABLE_GESTURE_NAV_RESULT";
    // Extra containing the pending intent to receive the result
    public static final String EXTRA_RESULT_INTENT = "com.android.systemui.EXTRA_RESULT_INTENT";

    // Overview is disabled, either because the device is in lock task mode, or because the device
    // policy has disabled the feature
    public static final int SYSUI_STATE_SCREEN_PINNING = 1 << 0;
+122 −1
Original line number Diff line number Diff line
@@ -16,17 +16,26 @@

package com.android.systemui.statusbar.phone;

import static android.app.Activity.RESULT_CANCELED;
import static android.app.Activity.RESULT_OK;
import static android.app.admin.DevicePolicyManager.STATE_USER_UNMANAGED;
import static android.content.Intent.ACTION_OVERLAY_CHANGED;
import static android.content.Intent.ACTION_PREFERRED_ACTIVITY_CHANGED;
import static android.content.pm.PackageManager.FEATURE_DEVICE_ADMIN;
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;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;

import static com.android.systemui.shared.system.QuickStepContract.ACTION_ENABLE_GESTURE_NAV;
import static com.android.systemui.shared.system.QuickStepContract.ACTION_ENABLE_GESTURE_NAV_RESULT;
import static com.android.systemui.shared.system.QuickStepContract.EXTRA_RESULT_INTENT;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -40,6 +49,7 @@ import android.os.PatternMatcher;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.text.TextUtils;
@@ -157,6 +167,8 @@ public class NavigationModeController implements Dumpable {
                }
            };

    private BroadcastReceiver mEnableGestureNavReceiver;

    @Inject
    public NavigationModeController(Context context,
            DeviceProvisionedController deviceProvisionedController,
@@ -177,6 +189,7 @@ public class NavigationModeController implements Dumpable {
        IntentFilter preferredActivityFilter = new IntentFilter(ACTION_PREFERRED_ACTIVITY_CHANGED);
        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, preferredActivityFilter, null,
                null);

        // We are only interested in launcher changes, so keeping track of the current default.
        mLastDefaultLauncher = getDefaultLauncherPackageName(mContext);

@@ -187,6 +200,82 @@ public class NavigationModeController implements Dumpable {
        deferGesturalNavOverlayIfNecessary();
    }

    private void removeEnableGestureNavListener() {
        if (mEnableGestureNavReceiver != null) {
            if (DEBUG) {
                Log.d(TAG, "mEnableGestureNavReceiver unregistered");
            }
            mContext.unregisterReceiver(mEnableGestureNavReceiver);
            mEnableGestureNavReceiver = null;
        }
    }

    private boolean setGestureModeOverlayForMainLauncher() {
        removeEnableGestureNavListener();
        if (getCurrentInteractionMode(mCurrentUserContext) == NAV_BAR_MODE_GESTURAL) {
            // Already in gesture mode
            return true;
        }
        final Boolean supported = isGestureNavSupportedByDefaultLauncher(mCurrentUserContext);
        if (supported == null || supported) {
            Log.d(TAG, "Switching system navigation to full-gesture mode:"
                    + " defaultLauncher="
                    + getDefaultLauncherPackageName(mCurrentUserContext)
                    + " contextUser="
                    + mCurrentUserContext.getUserId());

            setModeOverlay(NAV_BAR_MODE_GESTURAL_OVERLAY, USER_CURRENT);
            return true;
        } else {
            Log.e(TAG, "Gesture nav is not supported for defaultLauncher="
                    + getDefaultLauncherPackageName(mCurrentUserContext));
            return false;
        }
    }

    private boolean enableGestureNav(Intent intent) {
        if (!(intent.getParcelableExtra(EXTRA_RESULT_INTENT) instanceof PendingIntent)) {
            Log.e(TAG, "No callback pending intent was attached");
            return false;
        }

        PendingIntent callback = intent.getParcelableExtra(EXTRA_RESULT_INTENT);
        Intent callbackIntent = callback.getIntent();
        if (callbackIntent == null
                || !ACTION_ENABLE_GESTURE_NAV_RESULT.equals(callbackIntent.getAction())) {
            Log.e(TAG, "Invalid callback intent");
            return false;
        }
        String callerPackage = callback.getCreatorPackage();
        UserHandle callerUser = callback.getCreatorUserHandle();

        DevicePolicyManager dpm = mCurrentUserContext.getSystemService(DevicePolicyManager.class);
        ComponentName ownerComponent = dpm.getDeviceOwnerComponentOnCallingUser();

        if (ownerComponent != null) {
            // Verify that the caller is the owner component
            if (!ownerComponent.getPackageName().equals(callerPackage)
                    || !mCurrentUserContext.getUser().equals(callerUser)) {
                Log.e(TAG, "Callback must be from the device owner");
                return false;
            }
        } else {
            UserHandle callerParent = mCurrentUserContext.getSystemService(UserManager.class)
                    .getProfileParent(callerUser);
            if (callerParent == null || !callerParent.equals(mCurrentUserContext.getUser())) {
                Log.e(TAG, "Callback must be from a managed user");
                return false;
            }
            ComponentName profileOwner = dpm.getProfileOwnerAsUser(callerUser);
            if (profileOwner == null || !profileOwner.getPackageName().equals(callerPackage)) {
                Log.e(TAG, "Callback must be from the profile owner");
                return false;
            }
        }

        return setGestureModeOverlayForMainLauncher();
    }

    public void updateCurrentInteractionMode(boolean notify) {
        mCurrentUserContext = getCurrentUserContext();
        int mode = getCurrentInteractionMode(mCurrentUserContext);
@@ -245,6 +334,10 @@ public class NavigationModeController implements Dumpable {
        }
    }

    private boolean supportsDeviceAdmin() {
        return mContext.getPackageManager().hasSystemFeature(FEATURE_DEVICE_ADMIN);
    }

    private void deferGesturalNavOverlayIfNecessary() {
        final int userId = mDeviceProvisionedController.getCurrentUser();
        mRestoreGesturalNavBarMode.put(userId, false);
@@ -255,6 +348,7 @@ public class NavigationModeController implements Dumpable {
                Log.d(TAG, "deferGesturalNavOverlayIfNecessary: device is provisioned and user is "
                        + "setup");
            }
            removeEnableGestureNavListener();
            return;
        }

@@ -270,6 +364,7 @@ public class NavigationModeController implements Dumpable {
                Log.d(TAG, "deferGesturalNavOverlayIfNecessary: no default gestural overlay, "
                        + "default=" + defaultOverlays);
            }
            removeEnableGestureNavListener();
            return;
        }

@@ -277,6 +372,24 @@ public class NavigationModeController implements Dumpable {
        // provisioned
        setModeOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY, USER_CURRENT);
        mRestoreGesturalNavBarMode.put(userId, true);

        if (supportsDeviceAdmin() && mEnableGestureNavReceiver == null) {
            mEnableGestureNavReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    if (DEBUG) {
                        Log.d(TAG, "ACTION_ENABLE_GESTURE_NAV");
                    }
                    setResultCode(enableGestureNav(intent) ? RESULT_OK : RESULT_CANCELED);
                }
            };
            // Register for all users so that we can get managed users as well
            mContext.registerReceiverAsUser(mEnableGestureNavReceiver, UserHandle.ALL,
                    new IntentFilter(ACTION_ENABLE_GESTURE_NAV), null, null);
            if (DEBUG) {
                Log.d(TAG, "mEnableGestureNavReceiver registered");
            }
        }
        if (DEBUG) {
            Log.d(TAG, "deferGesturalNavOverlayIfNecessary: setting to 3 button mode");
        }
@@ -290,7 +403,15 @@ public class NavigationModeController implements Dumpable {
        final int userId = mDeviceProvisionedController.getCurrentUser();
        if (mRestoreGesturalNavBarMode.get(userId)) {
            // Restore the gestural state if necessary
            setModeOverlay(NAV_BAR_MODE_GESTURAL_OVERLAY, USER_CURRENT);
            if (!supportsDeviceAdmin()
                    || mCurrentUserContext.getSystemService(DevicePolicyManager.class)
                    .getUserProvisioningState() == STATE_USER_UNMANAGED) {
                setGestureModeOverlayForMainLauncher();
            } else {
                if (DEBUG) {
                    Log.d(TAG, "Not restoring to gesture nav for managed user");
                }
            }
            mRestoreGesturalNavBarMode.put(userId, false);
        }
    }