Merge "Applies left and right edge scale to side swipe width" into rvc-dev am: 7161e49836

Change-Id: Id3fd51e4750b2ee51c827e7593cba799778635b9
This commit is contained in:
Automerger Merge Worker
2020-03-16 04:06:36 +00:00
7 changed files with 159 additions and 240 deletions

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.policy;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
/**
* @hide
*/
public class GestureNavigationSettingsObserver extends ContentObserver {
private Context mContext;
private Runnable mOnChangeRunnable;
public GestureNavigationSettingsObserver(Handler handler, Context context,
Runnable onChangeRunnable) {
super(handler);
mContext = context;
mOnChangeRunnable = onChangeRunnable;
}
public void register() {
ContentResolver r = mContext.getContentResolver();
r.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT),
false, this, UserHandle.USER_ALL);
r.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT),
false, this, UserHandle.USER_ALL);
}
public void unregister() {
mContext.getContentResolver().unregisterContentObserver(this);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
if (mOnChangeRunnable != null) {
mOnChangeRunnable.run();
}
}
public int getLeftSensitivity(Resources userRes) {
return getSensitivity(userRes, Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT);
}
public int getRightSensitivity(Resources userRes) {
return getSensitivity(userRes, Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT);
}
private int getSensitivity(Resources userRes, String side) {
final int inset = userRes.getDimensionPixelSize(
com.android.internal.R.dimen.config_backGestureInset);
final float scale = Settings.Secure.getFloatForUser(
mContext.getContentResolver(), side, 1.0f, UserHandle.USER_CURRENT);
return (int) (inset * scale);
}
}

View File

@@ -44,6 +44,7 @@ import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.internal.policy.GestureNavigationSettingsObserver;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleController;
@@ -99,8 +100,10 @@ public class EdgeBackGestureHandler implements DisplayListener,
private final Region mExcludeRegion = new Region();
private final Region mUnrestrictedExcludeRegion = new Region();
// The edge width where touch down is allowed
private int mEdgeWidth;
// The left side edge width where touch down is allowed
private int mEdgeWidthLeft;
// The right side edge width where touch down is allowed
private int mEdgeWidthRight;
// The bottom gesture area height
private int mBottomGestureHeight;
// The slop to distinguish between horizontal and vertical motion
@@ -127,6 +130,8 @@ public class EdgeBackGestureHandler implements DisplayListener,
private int mRightInset;
private int mSysUiFlags;
private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
private final NavigationEdgeBackPlugin.BackCallback mBackCallback =
new NavigationEdgeBackPlugin.BackCallback() {
@Override
@@ -174,13 +179,17 @@ public class EdgeBackGestureHandler implements DisplayListener,
mLongPressTimeout = Math.min(MAX_LONG_PRESS_TIMEOUT,
ViewConfiguration.getLongPressTimeout());
mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(
mContext.getMainThreadHandler(), mContext, () -> updateCurrentUserResources(res));
updateCurrentUserResources(res);
sysUiFlagContainer.addCallback(sysUiFlags -> mSysUiFlags = sysUiFlags);
}
public void updateCurrentUserResources(Resources res) {
mEdgeWidth = res.getDimensionPixelSize(
com.android.internal.R.dimen.config_backGestureInset);
mEdgeWidthLeft = mGestureNavigationSettingsObserver.getLeftSensitivity(res);
mEdgeWidthRight = mGestureNavigationSettingsObserver.getRightSensitivity(res);
mBottomGestureHeight = res.getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_gesture_height);
}
@@ -236,6 +245,7 @@ public class EdgeBackGestureHandler implements DisplayListener,
}
if (!mIsEnabled) {
mGestureNavigationSettingsObserver.unregister();
mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
mPluginManager.removePluginListener(this);
@@ -248,6 +258,7 @@ public class EdgeBackGestureHandler implements DisplayListener,
}
} else {
mGestureNavigationSettingsObserver.register();
updateDisplaySize();
mContext.getSystemService(DisplayManager.class).registerDisplayListener(this,
mContext.getMainThreadHandler());
@@ -321,7 +332,8 @@ public class EdgeBackGestureHandler implements DisplayListener,
private boolean isWithinTouchRegion(int x, int y) {
// Disallow if too far from the edge
if (x > mEdgeWidth + mLeftInset && x < (mDisplaySize.x - mEdgeWidth - mRightInset)) {
if (x > mEdgeWidthLeft + mLeftInset
&& x < (mDisplaySize.x - mEdgeWidthRight - mRightInset)) {
return false;
}
@@ -364,7 +376,7 @@ public class EdgeBackGestureHandler implements DisplayListener,
if (action == MotionEvent.ACTION_DOWN) {
// Verify if this is in within the touch region and we aren't in immersive mode, and
// either the bouncer is showing or the notification panel is hidden
mIsOnLeftEdge = ev.getX() <= mEdgeWidth + mLeftInset;
mIsOnLeftEdge = ev.getX() <= mEdgeWidthLeft + mLeftInset;
mInRejectedExclusion = false;
mAllowGesture = !QuickStepContract.isBackGestureDisabled(mSysUiFlags)
&& isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
@@ -461,7 +473,8 @@ public class EdgeBackGestureHandler implements DisplayListener,
pw.println(" mExcludeRegion=" + mExcludeRegion);
pw.println(" mUnrestrictedExcludeRegion=" + mUnrestrictedExcludeRegion);
pw.println(" mIsAttached=" + mIsAttached);
pw.println(" mEdgeWidth=" + mEdgeWidth);
pw.println(" mEdgeWidthLeft=" + mEdgeWidthLeft);
pw.println(" mEdgeWidthRight=" + mEdgeWidthRight);
}
@Override

View File

@@ -28,6 +28,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
import android.content.pm.PackageManager;
import android.content.res.ApkAssets;
import android.os.PatternMatcher;
@@ -172,6 +173,9 @@ public class NavigationModeController implements Dumpable {
public void updateCurrentInteractionMode(boolean notify) {
mCurrentUserContext = getCurrentUserContext();
int mode = getCurrentInteractionMode(mCurrentUserContext);
if (mode == NAV_BAR_MODE_GESTURAL) {
switchToDefaultGestureNavOverlayIfNecessary();
}
mUiBgExecutor.execute(() -> {
Settings.Secure.putString(mCurrentUserContext.getContentResolver(),
Secure.NAVIGATION_MODE, String.valueOf(mode));
@@ -277,6 +281,34 @@ public class NavigationModeController implements Dumpable {
}
}
private void switchToDefaultGestureNavOverlayIfNecessary() {
final int userId = mCurrentUserContext.getUserId();
try {
final IOverlayManager om = mOverlayManager;
final OverlayInfo info = om.getOverlayInfo(NAV_BAR_MODE_GESTURAL_OVERLAY, userId);
if (info != null && !info.isEnabled()) {
// Enable the default gesture nav overlay, and move the back gesture inset scale to
// Settings.Secure for left and right sensitivity.
final int curInset = mCurrentUserContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.config_backGestureInset);
om.setEnabledExclusiveInCategory(NAV_BAR_MODE_GESTURAL_OVERLAY, userId);
final int defInset = mCurrentUserContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.config_backGestureInset);
final float scale = defInset == 0 ? 1.0f : ((float) curInset) / defInset;
Settings.Secure.putFloat(mCurrentUserContext.getContentResolver(),
Secure.BACK_GESTURE_INSET_SCALE_LEFT, scale);
Settings.Secure.putFloat(mCurrentUserContext.getContentResolver(),
Secure.BACK_GESTURE_INSET_SCALE_RIGHT, scale);
if (DEBUG) {
Log.v(TAG, "Moved back sensitivity for user " + userId + " to scale " + scale);
}
}
} catch (SecurityException | IllegalStateException | RemoteException e) {
Log.e(TAG, "Failed to switch to default gesture nav overlay for user " + userId);
}
}
public void setModeOverlay(String overlayPkg, int userId) {
mUiBgExecutor.execute(() -> {
try {

View File

@@ -1,228 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.phone;
import static android.view.Display.DEFAULT_DISPLAY;
import android.annotation.IntDef;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Point;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Coordinates with the prototype settings plugin app that uses Settings.Global to allow different
* prototypes to run in the system. The class will handle communication changes from the settings
* app and call back to listeners.
*/
public class NavigationPrototypeController extends ContentObserver implements ComponentCallbacks {
private static final String HIDE_BACK_BUTTON_SETTING = "quickstepcontroller_hideback";
private static final String HIDE_HOME_BUTTON_SETTING = "quickstepcontroller_hidehome";
private static final String PROTOTYPE_ENABLED = "prototype_enabled";
public static final String EDGE_SENSITIVITY_WIDTH_SETTING =
"quickstepcontroller_edge_width_sensitivity";
private final String GESTURE_MATCH_SETTING = "quickstepcontroller_gesture_match_map";
public static final String NAV_COLOR_ADAPT_ENABLE_SETTING = "navbar_color_adapt_enable";
public static final String SHOW_HOME_HANDLE_SETTING = "quickstepcontroller_showhandle";
public static final String ENABLE_ASSISTANT_GESTURE = "ENABLE_ASSISTANT_GESTURE";
@Retention(RetentionPolicy.SOURCE)
@IntDef({ACTION_DEFAULT, ACTION_QUICKSTEP, ACTION_QUICKSCRUB, ACTION_BACK,
ACTION_QUICKSWITCH, ACTION_NOTHING, ACTION_ASSISTANT})
@interface GestureAction {}
static final int ACTION_DEFAULT = 0;
static final int ACTION_QUICKSTEP = 1;
static final int ACTION_QUICKSCRUB = 2;
static final int ACTION_BACK = 3;
static final int ACTION_QUICKSWITCH = 4;
static final int ACTION_NOTHING = 5;
static final int ACTION_ASSISTANT = 6;
private OnPrototypeChangedListener mListener;
/**
* Each index corresponds to a different action set in QuickStepController
* {@see updateSwipeLTRBackSetting}
*/
private int[] mActionMap = new int[6];
private final Context mContext;
public NavigationPrototypeController(Context context) {
super(new Handler());
mContext = context;
updateSwipeLTRBackSetting();
}
public void setOnPrototypeChangedListener(OnPrototypeChangedListener listener) {
mListener = listener;
}
/**
* Observe all the settings to react to from prototype settings
*/
public void register() {
registerObserver(HIDE_BACK_BUTTON_SETTING);
registerObserver(HIDE_HOME_BUTTON_SETTING);
registerObserver(GESTURE_MATCH_SETTING);
registerObserver(NAV_COLOR_ADAPT_ENABLE_SETTING);
registerObserver(SHOW_HOME_HANDLE_SETTING);
registerObserver(ENABLE_ASSISTANT_GESTURE);
mContext.registerComponentCallbacks(this);
}
/**
* Disable observing settings to react to from prototype settings
*/
public void unregister() {
mContext.getContentResolver().unregisterContentObserver(this);
mContext.unregisterComponentCallbacks(this);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
if (!selfChange && mListener != null) {
final String path = uri.getPath();
if (path.endsWith(GESTURE_MATCH_SETTING)) {
// Get the settings gesture map corresponding to each action
// {@see updateSwipeLTRBackSetting}
updateSwipeLTRBackSetting();
mListener.onGestureRemap(mActionMap);
} else if (path.endsWith(HIDE_BACK_BUTTON_SETTING)) {
mListener.onBackButtonVisibilityChanged(
!getGlobalBool(HIDE_BACK_BUTTON_SETTING, false));
} else if (path.endsWith(HIDE_HOME_BUTTON_SETTING)) {
mListener.onHomeButtonVisibilityChanged(!hideHomeButton());
} else if (path.endsWith(NAV_COLOR_ADAPT_ENABLE_SETTING)) {
mListener.onColorAdaptChanged(mContext.getDisplayId() == DEFAULT_DISPLAY);
} else if (path.endsWith(SHOW_HOME_HANDLE_SETTING)) {
mListener.onHomeHandleVisiblilityChanged(showHomeHandle());
} else if (path.endsWith(ENABLE_ASSISTANT_GESTURE)) {
mListener.onAssistantGestureEnabled(isAssistantGestureEnabled());
}
}
}
/**
* @return the width for edge swipe
*/
public int getEdgeSensitivityWidth() {
return mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.config_backGestureInset);
}
/**
* @return full screen height
*/
public int getEdgeSensitivityHeight() {
final Point size = new Point();
mContext.getDisplay().getRealSize(size);
return size.y;
}
public boolean isEnabled() {
return getGlobalBool(PROTOTYPE_ENABLED, false);
}
/**
* Retrieve the action map to apply to the quick step controller
* @return an action map
*/
int[] getGestureActionMap() {
return mActionMap;
}
/**
* @return if home button should be invisible
*/
boolean hideHomeButton() {
return getGlobalBool(HIDE_HOME_BUTTON_SETTING, false /* default */);
}
boolean showHomeHandle() {
return getGlobalBool(SHOW_HOME_HANDLE_SETTING, false /* default */);
}
boolean isAssistantGestureEnabled() {
return getGlobalBool(ENABLE_ASSISTANT_GESTURE, false /* default */);
}
/**
* Since Settings.Global cannot pass arrays, use a string to represent each character as a
* gesture map to actions corresponding to {@see GestureAction}. The number is represented as:
* Number: [up] [down] [left] [right]
*/
private void updateSwipeLTRBackSetting() {
String value = Settings.Global.getString(mContext.getContentResolver(),
GESTURE_MATCH_SETTING);
if (value != null) {
for (int i = 0; i < mActionMap.length; ++i) {
mActionMap[i] = Character.getNumericValue(value.charAt(i));
}
}
}
private boolean getGlobalBool(String name, boolean defaultVal) {
return Settings.Global.getInt(mContext.getContentResolver(), name, defaultVal ? 1 : 0) == 1;
}
private int getGlobalInt(String name, int defaultVal) {
return Settings.Global.getInt(mContext.getContentResolver(), name, defaultVal);
}
private void registerObserver(String name) {
mContext.getContentResolver()
.registerContentObserver(Settings.Global.getUriFor(name), false, this);
}
private static int convertDpToPixel(float dp) {
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (mListener != null) {
mListener.onEdgeSensitivityChanged(getEdgeSensitivityWidth(),
getEdgeSensitivityHeight());
}
}
@Override
public void onLowMemory() {
}
public interface OnPrototypeChangedListener {
void onGestureRemap(@GestureAction int[] actions);
void onBackButtonVisibilityChanged(boolean visible);
void onHomeButtonVisibilityChanged(boolean visible);
void onHomeHandleVisiblilityChanged(boolean visible);
void onColorAdaptChanged(boolean enabled);
void onEdgeSensitivityChanged(int width, int height);
void onAssistantGestureEnabled(boolean enabled);
}
}

View File

@@ -6523,6 +6523,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
lastReparentedStack.postReparent();
}
releaseSelfIfNeeded();
mDisplayPolicy.release();
if (!mAllSleepTokens.isEmpty()) {
mRootWindowContainer.mSleepTokens.removeAll(mAllSleepTokens);

View File

@@ -179,6 +179,7 @@ import android.view.accessibility.AccessibilityManager;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.GestureNavigationSettingsObserver;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.util.ScreenshotHelper;
import com.android.internal.util.function.TriConsumer;
@@ -259,7 +260,9 @@ public class DisplayPolicy {
@Px
private int mBottomGestureAdditionalInset;
@Px
private int mSideGestureInset;
private int mLeftGestureInset;
@Px
private int mRightGestureInset;
StatusBarManagerInternal getStatusBarManagerInternal() {
synchronized (mServiceAcquireLock) {
@@ -427,6 +430,8 @@ public class DisplayPolicy {
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
private class PolicyHandler extends Handler {
PolicyHandler(Looper looper) {
@@ -651,6 +656,16 @@ public class DisplayPolicy {
mRefreshRatePolicy = new RefreshRatePolicy(mService,
mDisplayContent.getDisplayInfo(),
mService.mHighRefreshRateBlacklist);
mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler,
mContext, () -> {
synchronized (mLock) {
onConfigurationChanged();
mSystemGestures.onConfigurationChanged();
mDisplayContent.updateSystemGestureExclusion();
}
});
mHandler.post(mGestureNavigationSettingsObserver::register);
}
void systemReady() {
@@ -723,7 +738,7 @@ public class DisplayPolicy {
}
boolean hasSideGestures() {
return mHasNavigationBar && mSideGestureInset > 0;
return mHasNavigationBar && (mLeftGestureInset > 0 || mRightGestureInset > 0);
}
public boolean navigationBarCanMove() {
@@ -1076,11 +1091,12 @@ public class DisplayPolicy {
inOutFrame.left = 0;
inOutFrame.top = 0;
inOutFrame.bottom = displayFrames.mDisplayHeight;
inOutFrame.right = displayFrames.mUnrestricted.left + mSideGestureInset;
inOutFrame.right = displayFrames.mUnrestricted.left + mLeftGestureInset;
});
mDisplayContent.setInsetProvider(ITYPE_RIGHT_GESTURES, win,
(displayFrames, windowState, inOutFrame) -> {
inOutFrame.left = displayFrames.mUnrestricted.right - mSideGestureInset;
inOutFrame.left = displayFrames.mUnrestricted.right
- mRightGestureInset;
inOutFrame.top = 0;
inOutFrame.bottom = displayFrames.mDisplayHeight;
inOutFrame.right = displayFrames.mDisplayWidth;
@@ -2819,7 +2835,8 @@ public class DisplayPolicy {
}
mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
mSideGestureInset = res.getDimensionPixelSize(R.dimen.config_backGestureInset);
mLeftGestureInset = mGestureNavigationSettingsObserver.getLeftSensitivity(res);
mRightGestureInset = mGestureNavigationSettingsObserver.getRightSensitivity(res);
mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
mNavigationBarAlwaysShowOnSideGesture =
res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
@@ -3953,6 +3970,10 @@ public class DisplayPolicy {
return false;
}
void release() {
mHandler.post(mGestureNavigationSettingsObserver::unregister);
}
@VisibleForTesting
static boolean isOverlappingWithNavBar(WindowState targetWindow, WindowState navBarWindow) {
if (navBarWindow == null || !navBarWindow.isVisibleLw()

View File

@@ -322,6 +322,8 @@ public class SystemServicesTestRule implements TestRule {
}
private void tearDown() {
mWmService.mRoot.forAllDisplayPolicies(DisplayPolicy::release);
// Unregister display listener from root to avoid issues with subsequent tests.
mContext.getSystemService(DisplayManager.class)
.unregisterDisplayListener(mAtmService.mRootWindowContainer);