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
This commit is contained in:
@@ -89,4 +89,9 @@ public interface OneHanded {
|
||||
* Receive onConfigurationChanged() events
|
||||
*/
|
||||
void onConfigChanged(Configuration newConfig);
|
||||
|
||||
/**
|
||||
* Notifies when user switch complete
|
||||
*/
|
||||
void onUserSwitch(int userId);
|
||||
}
|
||||
|
||||
@@ -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<OneHandedController>
|
||||
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<OneHandedController>
|
||||
}
|
||||
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<OneHandedController>
|
||||
mTimeoutHandler.setTimeout(timeout / 1000);
|
||||
} else {
|
||||
mTimeoutHandler.setTimeout(mOneHandedSettingsUtil
|
||||
.getSettingsOneHandedModeTimeout(mContext.getContentResolver()));
|
||||
.getSettingsOneHandedModeTimeout(
|
||||
mContext.getContentResolver(), mUserId));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -247,12 +251,13 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
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<OneHandedController>
|
||||
getObserver(this::onSwipeToNotificationEnabledSettingChanged);
|
||||
|
||||
mDisplayController.addDisplayChangingController(mRotationController);
|
||||
|
||||
setupCallback();
|
||||
setupSettingObservers();
|
||||
registerSettingObservers(mUserId);
|
||||
setupTimeoutListener();
|
||||
setupGesturalOverlay();
|
||||
updateSettings();
|
||||
@@ -379,27 +383,38 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
}
|
||||
}
|
||||
|
||||
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<OneHandedController>
|
||||
@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<OneHandedController>
|
||||
// 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<OneHandedController>
|
||||
@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<OneHandedController>
|
||||
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<OneHandedController>
|
||||
|
||||
private void setupGesturalOverlay() {
|
||||
if (!mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
|
||||
mContext.getContentResolver())) {
|
||||
mContext.getContentResolver(), mUserId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -572,6 +587,14 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
}
|
||||
}
|
||||
|
||||
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<OneHandedController>
|
||||
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<OneHandedController>
|
||||
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>
|
||||
OneHandedController.this.onConfigChanged(newConfig);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserSwitch(int userId) {
|
||||
mMainExecutor.execute(() -> {
|
||||
OneHandedController.this.onUserSwitch(userId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -296,6 +296,11 @@ public final class WMShell extends SystemUI
|
||||
}
|
||||
oneHanded.stopOneHanded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserSwitchComplete(int userId) {
|
||||
oneHanded.onUserSwitch(userId);
|
||||
}
|
||||
};
|
||||
mKeyguardUpdateMonitor.registerCallback(mOneHandedKeyguardCallback);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user