From f18a7b0bc17d062917ba021c68d3a6795b2319ae Mon Sep 17 00:00:00 2001 From: Bill Lin Date: Fri, 12 Mar 2021 18:17:39 +0800 Subject: [PATCH] 1/ Make One handed mode support multiple user switch Previously OHM did not support for multile user switch Now we hook SysUI onUserSwitch callback to update latest one handed mode functionality by currentUserId Test: atest SystemUITests Test: atest WMShellUnitTests Test: manually switch user and observe verify different OHM config for different users Bug: 182278800 Change-Id: I8ae7d0aedcafc8f477f41d2703df2df53839a89f --- .../android/wm/shell/onehanded/OneHanded.java | 5 ++ .../shell/onehanded/OneHandedController.java | 78 +++++++++++++------ .../onehanded/OneHandedSettingsUtil.java | 56 +++++++------ .../onehanded/OneHandedControllerTest.java | 11 ++- .../com/android/systemui/wmshell/WMShell.java | 5 ++ 5 files changed, 104 insertions(+), 51 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java index a7e9a0135de0e..242f8f120e274 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java @@ -89,4 +89,9 @@ public interface OneHanded { * Receive onConfigurationChanged() events */ void onConfigChanged(Configuration newConfig); + + /** + * Notifies when user switch complete + */ + void onUserSwitch(int userId); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 7965a80deead2..c5c29a85fbfcd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -17,6 +17,7 @@ package com.android.wm.shell.onehanded; import static android.os.UserHandle.USER_CURRENT; +import static android.os.UserHandle.myUserId; import static android.view.Display.DEFAULT_DISPLAY; import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; @@ -74,6 +75,7 @@ public class OneHandedController implements RemoteCallable private volatile boolean mIsSwipeToNotificationEnabled; private boolean mTaskChangeToExit; private boolean mLockedDisabled; + private int mUserId; private float mOffSetFraction; private Context mContext; @@ -141,7 +143,8 @@ public class OneHandedController implements RemoteCallable } if (enabled) { final int mOneHandedTimeout = mOneHandedSettingsUtil - .getSettingsOneHandedModeTimeout(mContext.getContentResolver()); + .getSettingsOneHandedModeTimeout( + mContext.getContentResolver(), mUserId); final int timeout = mAccessibilityManager .getRecommendedTimeoutMillis(mOneHandedTimeout * 1000 /* align with A11y timeout millis */, @@ -149,7 +152,8 @@ public class OneHandedController implements RemoteCallable mTimeoutHandler.setTimeout(timeout / 1000); } else { mTimeoutHandler.setTimeout(mOneHandedSettingsUtil - .getSettingsOneHandedModeTimeout(mContext.getContentResolver())); + .getSettingsOneHandedModeTimeout( + mContext.getContentResolver(), mUserId)); } } }; @@ -247,12 +251,13 @@ public class OneHandedController implements RemoteCallable R.fraction.config_one_handed_offset, 1, 1); final int sysPropPercentageConfig = SystemProperties.getInt( ONE_HANDED_MODE_OFFSET_PERCENTAGE, Math.round(offsetPercentageConfig * 100.0f)); + mUserId = myUserId(); mOffSetFraction = sysPropPercentageConfig / 100.0f; mIsOneHandedEnabled = mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled( - context.getContentResolver()); + context.getContentResolver(), mUserId); mIsSwipeToNotificationEnabled = mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( - context.getContentResolver()); + context.getContentResolver(), mUserId); mTimeoutHandler = timeoutHandler; mEnabledObserver = getObserver(this::onEnabledSettingChanged); @@ -262,9 +267,8 @@ public class OneHandedController implements RemoteCallable getObserver(this::onSwipeToNotificationEnabledSettingChanged); mDisplayController.addDisplayChangingController(mRotationController); - setupCallback(); - setupSettingObservers(); + registerSettingObservers(mUserId); setupTimeoutListener(); setupGesturalOverlay(); updateSettings(); @@ -379,27 +383,38 @@ public class OneHandedController implements RemoteCallable } } - private void setupSettingObservers() { + private void registerSettingObservers(int newUserId) { mOneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_ENABLED, - mContext.getContentResolver(), mEnabledObserver); + mContext.getContentResolver(), mEnabledObserver, newUserId); mOneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_TIMEOUT, - mContext.getContentResolver(), mTimeoutObserver); + mContext.getContentResolver(), mTimeoutObserver, newUserId); mOneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.TAPS_APP_TO_EXIT, - mContext.getContentResolver(), mTaskChangeExitObserver); + mContext.getContentResolver(), mTaskChangeExitObserver, newUserId); mOneHandedSettingsUtil.registerSettingsKeyObserver( Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, - mContext.getContentResolver(), mSwipeToNotificationEnabledObserver); + mContext.getContentResolver(), mSwipeToNotificationEnabledObserver, newUserId); + } + + private void unregisterSettingObservers() { + mOneHandedSettingsUtil.unregisterSettingsKeyObserver(mContext.getContentResolver(), + mEnabledObserver); + mOneHandedSettingsUtil.unregisterSettingsKeyObserver(mContext.getContentResolver(), + mTimeoutObserver); + mOneHandedSettingsUtil.unregisterSettingsKeyObserver(mContext.getContentResolver(), + mTaskChangeExitObserver); + mOneHandedSettingsUtil.unregisterSettingsKeyObserver(mContext.getContentResolver(), + mSwipeToNotificationEnabledObserver); } private void updateSettings() { setOneHandedEnabled(mOneHandedSettingsUtil - .getSettingsOneHandedModeEnabled(mContext.getContentResolver())); + .getSettingsOneHandedModeEnabled(mContext.getContentResolver(), mUserId)); mTimeoutHandler.setTimeout(mOneHandedSettingsUtil - .getSettingsOneHandedModeTimeout(mContext.getContentResolver())); + .getSettingsOneHandedModeTimeout(mContext.getContentResolver(), mUserId)); setTaskChangeToExit(mOneHandedSettingsUtil - .getSettingsTapsAppToExit(mContext.getContentResolver())); + .getSettingsTapsAppToExit(mContext.getContentResolver(), mUserId)); setSwipeToNotificationEnabled(mOneHandedSettingsUtil - .getSettingsSwipeToNotificationEnabled(mContext.getContentResolver())); + .getSettingsSwipeToNotificationEnabled(mContext.getContentResolver(), mUserId)); } private void updateDisplayLayout(int displayId) { @@ -420,7 +435,7 @@ public class OneHandedController implements RemoteCallable @VisibleForTesting void onEnabledSettingChanged() { final boolean enabled = mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled( - mContext.getContentResolver()); + mContext.getContentResolver(), mUserId); mOneHandedUiEventLogger.writeEvent(enabled ? OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_ENABLED_ON : OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_ENABLED_OFF); @@ -430,13 +445,13 @@ public class OneHandedController implements RemoteCallable // Also checks swipe to notification settings since they all need gesture overlay. setEnabledGesturalOverlay( enabled || mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( - mContext.getContentResolver())); + mContext.getContentResolver(), mUserId)); } @VisibleForTesting void onTimeoutSettingChanged() { final int newTimeout = mOneHandedSettingsUtil.getSettingsOneHandedModeTimeout( - mContext.getContentResolver()); + mContext.getContentResolver(), mUserId); int metricsId = OneHandedUiEventLogger.OneHandedSettingsTogglesEvent.INVALID.getId(); switch (newTimeout) { case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_NEVER: @@ -465,7 +480,7 @@ public class OneHandedController implements RemoteCallable @VisibleForTesting void onTaskChangeExitSettingChanged() { final boolean enabled = mOneHandedSettingsUtil.getSettingsTapsAppToExit( - mContext.getContentResolver()); + mContext.getContentResolver(), mUserId); mOneHandedUiEventLogger.writeEvent(enabled ? OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_ON : OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_OFF); @@ -477,13 +492,13 @@ public class OneHandedController implements RemoteCallable void onSwipeToNotificationEnabledSettingChanged() { final boolean enabled = mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( - mContext.getContentResolver()); + mContext.getContentResolver(), mUserId); setSwipeToNotificationEnabled(enabled); // Also checks one handed mode settings since they all need gesture overlay. setEnabledGesturalOverlay( enabled || mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled( - mContext.getContentResolver())); + mContext.getContentResolver(), mUserId)); } private void setupTimeoutListener() { @@ -524,7 +539,7 @@ public class OneHandedController implements RemoteCallable private void setupGesturalOverlay() { if (!mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled( - mContext.getContentResolver())) { + mContext.getContentResolver(), mUserId)) { return; } @@ -572,6 +587,14 @@ public class OneHandedController implements RemoteCallable } } + private void onUserSwitch(int newUserId) { + unregisterSettingObservers(); + mUserId = newUserId; + registerSettingObservers(newUserId); + updateSettings(); + updateOneHandedEnabled(); + } + public void dump(@NonNull PrintWriter pw) { final String innerPrefix = " "; pw.println(TAG + "States: "); @@ -579,6 +602,8 @@ public class OneHandedController implements RemoteCallable pw.println(mOffSetFraction); pw.print(innerPrefix + "mLockedDisabled="); pw.println(mLockedDisabled); + pw.print(innerPrefix + "mUserId="); + pw.println(mUserId); if (mBackgroundPanelOrganizer != null) { mBackgroundPanelOrganizer.dump(pw); @@ -604,7 +629,7 @@ public class OneHandedController implements RemoteCallable mTutorialHandler.dump(pw); } - mOneHandedSettingsUtil.dump(pw, innerPrefix, mContext.getContentResolver()); + mOneHandedSettingsUtil.dump(pw, innerPrefix, mContext.getContentResolver(), mUserId); if (mOverlayManager != null) { OverlayInfo info = null; @@ -703,6 +728,13 @@ public class OneHandedController implements RemoteCallable OneHandedController.this.onConfigChanged(newConfig); }); } + + @Override + public void onUserSwitch(int userId) { + mMainExecutor.execute(() -> { + OneHandedController.this.onUserSwitch(userId); + }); + } } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java index fa94ec5578830..1b2fcdd6313e6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java @@ -22,6 +22,8 @@ import android.database.ContentObserver; import android.net.Uri; import android.provider.Settings; +import androidx.annotation.Nullable; + import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -62,17 +64,19 @@ public final class OneHandedSettingsUtil { /** * Register one handed preference settings observer * - * @param key Setting key to monitor in observer - * @param resolver ContentResolver of context - * @param observer Observer from caller + * @param key Setting key to monitor in observer + * @param resolver ContentResolver of context + * @param observer Observer from caller + * @param newUserId New user id to be registered * @return uri key for observing */ + @Nullable public Uri registerSettingsKeyObserver(String key, ContentResolver resolver, - ContentObserver observer) { + ContentObserver observer, int newUserId) { Uri uriKey = null; uriKey = Settings.Secure.getUriFor(key); if (resolver != null && uriKey != null) { - resolver.registerContentObserver(uriKey, false, observer); + resolver.registerContentObserver(uriKey, false, observer, newUserId); } return uriKey; } @@ -80,8 +84,8 @@ public final class OneHandedSettingsUtil { /** * Unregister one handed preference settings observer * - * @param resolver ContentResolver of context - * @param observer preference key change observer + * @param resolver ContentResolver of context + * @param observer preference key change observer */ public void unregisterSettingsKeyObserver(ContentResolver resolver, ContentObserver observer) { @@ -95,9 +99,9 @@ public final class OneHandedSettingsUtil { * * @return enable or disable one handed mode flag. */ - public boolean getSettingsOneHandedModeEnabled(ContentResolver resolver) { - return Settings.Secure.getInt(resolver, - Settings.Secure.ONE_HANDED_MODE_ENABLED, 0 /* Disabled */) == 1; + public boolean getSettingsOneHandedModeEnabled(ContentResolver resolver, int userId) { + return Settings.Secure.getIntForUser(resolver, + Settings.Secure.ONE_HANDED_MODE_ENABLED, 0 /* Disabled */, userId) == 1; } /** @@ -105,40 +109,44 @@ public final class OneHandedSettingsUtil { * * @return enable or disable taps app exit. */ - public boolean getSettingsTapsAppToExit(ContentResolver resolver) { - return Settings.Secure.getInt(resolver, - Settings.Secure.TAPS_APP_TO_EXIT, 0) == 1; + public boolean getSettingsTapsAppToExit(ContentResolver resolver, int userId) { + return Settings.Secure.getIntForUser(resolver, + Settings.Secure.TAPS_APP_TO_EXIT, 0, userId) == 1; } /** - * Query timeout value from Settings provider. - * Default is {@link OneHandedSettingsUtil#ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS} + * Query timeout value from Settings provider. Default is + * {@link OneHandedSettingsUtil#ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS} * * @return timeout value in seconds. */ - public @OneHandedTimeout int getSettingsOneHandedModeTimeout(ContentResolver resolver) { - return Settings.Secure.getInt(resolver, - Settings.Secure.ONE_HANDED_MODE_TIMEOUT, ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS); + public @OneHandedTimeout int getSettingsOneHandedModeTimeout(ContentResolver resolver, + int userId) { + return Settings.Secure.getIntForUser(resolver, + Settings.Secure.ONE_HANDED_MODE_TIMEOUT, ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS, + userId); } /** * Returns whether swipe bottom to notification gesture enabled or not. */ - public boolean getSettingsSwipeToNotificationEnabled(ContentResolver resolver) { + public boolean getSettingsSwipeToNotificationEnabled(ContentResolver resolver, int userId) { return Settings.Secure.getInt(resolver, Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 0 /* Default OFF */) == 1; } - void dump(PrintWriter pw, String prefix, ContentResolver resolver) { + void dump(PrintWriter pw, String prefix, ContentResolver resolver, + int userId) { final String innerPrefix = prefix + " "; - pw.println(prefix + TAG); + pw.println(innerPrefix + TAG); pw.print(innerPrefix + "isOneHandedModeEnable="); - pw.println(getSettingsOneHandedModeEnabled(resolver)); + pw.println(getSettingsOneHandedModeEnabled(resolver, userId)); pw.print(innerPrefix + "oneHandedTimeOut="); - pw.println(getSettingsOneHandedModeTimeout(resolver)); + pw.println(getSettingsOneHandedModeTimeout(resolver, userId)); pw.print(innerPrefix + "tapsAppToExit="); - pw.println(getSettingsTapsAppToExit(resolver)); + pw.println(getSettingsTapsAppToExit(resolver, userId)); } + public OneHandedSettingsUtil() { } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java index b0fc4c14a6bfc..e309f9659338d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java @@ -31,6 +31,7 @@ import static org.mockito.Mockito.when; import android.content.om.IOverlayManager; import android.graphics.Rect; import android.os.Handler; +import android.os.UserHandle; import android.testing.AndroidTestingRunner; import android.util.ArrayMap; import android.view.Display; @@ -53,6 +54,8 @@ import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) public class OneHandedControllerTest extends OneHandedTestCase { + private int mCurrentUser = UserHandle.myUserId(); + Display mDisplay; DisplayLayout mDisplayLayout; OneHandedController mSpiedOneHandedController; @@ -100,13 +103,13 @@ public class OneHandedControllerTest extends OneHandedTestCase { when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false); when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>()); when(mMockBackgroundOrganizer.getBackgroundSurface()).thenReturn(mMockLeash); - when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any())).thenReturn( + when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn( mDefaultEnabled); - when(mMockSettingsUitl.getSettingsOneHandedModeTimeout(any())).thenReturn( + when(mMockSettingsUitl.getSettingsOneHandedModeTimeout(any(), anyInt())).thenReturn( OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS); - when(mMockSettingsUitl.getSettingsTapsAppToExit(any())).thenReturn( + when(mMockSettingsUitl.getSettingsTapsAppToExit(any(), anyInt())).thenReturn( mDefaultTapAppToExitEnabled); - when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any())).thenReturn( + when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn( mDefaultSwipeToNotificationEnabled); when(mMockDisplayAreaOrganizer.getLastDisplayBounds()).thenReturn( diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java index 4eb75ebe4553f..74b79d57adcb0 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java @@ -296,6 +296,11 @@ public final class WMShell extends SystemUI } oneHanded.stopOneHanded(); } + + @Override + public void onUserSwitchComplete(int userId) { + oneHanded.onUserSwitch(userId); + } }; mKeyguardUpdateMonitor.registerCallback(mOneHandedKeyguardCallback);