summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2019-02-04 22:44:22 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2019-02-04 22:44:22 +0000
commitc5f8397f0fce25f88632ad83b1fea98e66e2e43b (patch)
tree43ef302ef153274445fee201a7cfea4b05c06edf
parentb031e8e7cb36326a1ba32b988de69fafd596c959 (diff)
parentb831fb4fd1446782bb88e7b43f4885d0de7a17ca (diff)
Merge "Implement screen edge swipe for prototype"
-rw-r--r--packages/SystemUI/res/values/dimens.xml5
-rw-r--r--packages/SystemUI/res/values/strings.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java78
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java118
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java147
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java84
7 files changed, 320 insertions, 148 deletions
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1060211cebf5..81c00bc86ddc 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -23,8 +23,9 @@
<dimen name="navigation_bar_size">@*android:dimen/navigation_bar_height</dimen>
<!-- Minimum swipe distance to catch the swipe gestures to invoke assist or switch tasks. -->
<dimen name="navigation_bar_min_swipe_distance">48dp</dimen>
- <!-- The distance from a side of device of the navigation bar to start an edge swipe -->
- <dimen name="navigation_bar_edge_swipe_threshold">48dp</dimen>
+ <!-- The default distance from a side of the device to start an edge swipe from -->
+ <dimen name="navigation_bar_default_edge_width">48dp</dimen>
+ <dimen name="navigation_bar_default_edge_height">500dp</dimen>
<!-- thickness (height) of the dead zone at the top of the navigation bar,
reducing false presses on navbar buttons; approx 2mm -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 56d9bf4c5f8f..5365dcf72f11 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1829,6 +1829,9 @@
<!-- SysUI Tuner: Button that leads to the navigation bar customization screen [CHAR LIMIT=60] -->
<string name="nav_bar">Navigation bar</string>
+ <!-- Label for navigation edge panel for gestures [CHAR LIMIT=60] -->
+ <string name="nav_bar_edge_panel" translatable="false">Navigation bar Edge Panel</string>
+
<!-- SysUI Tuner: Button that controls layout of navigation bar [CHAR LIMIT=60] -->
<string name="nav_bar_layout">Layout</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
new file mode 100644
index 000000000000..dae4da7355c7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 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 android.annotation.NonNull;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+public class NavigationBarEdgePanel extends View {
+ private static final String TAG = "NavigationBarEdgePanel";
+
+ public static NavigationBarEdgePanel create(@NonNull Context context, int width, int height,
+ int gravity) {
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ lp.gravity = gravity;
+ lp.setTitle(TAG + context.getDisplayId());
+ lp.accessibilityTitle = context.getString(R.string.nav_bar_edge_panel);
+ lp.windowAnimations = 0;
+ NavigationBarEdgePanel panel = new NavigationBarEdgePanel(context);
+ panel.setLayoutParams(lp);
+ return panel;
+ }
+
+ private NavigationBarEdgePanel(Context context) {
+ super(context);
+ }
+
+ public void setWindowFlag(int flags, boolean enable) {
+ WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
+ if (lp == null || enable == ((lp.flags & flags) != 0)) {
+ return;
+ }
+ if (enable) {
+ lp.flags |= flags;
+ } else {
+ lp.flags &= ~flags;
+ }
+ updateLayout(lp);
+ }
+
+ public void setDimensions(int width, int height) {
+ final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
+ if (lp.width != width || lp.height != height) {
+ lp.width = width;
+ lp.height = height;
+ updateLayout(lp);
+ }
+ }
+
+ private void updateLayout(WindowManager.LayoutParams lp) {
+ WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
+ wm.updateViewLayout(this, lp);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 02683c16d935..651670cbf2c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.phone;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_QUICK_SCRUB;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
@@ -35,6 +37,8 @@ import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.DrawableRes;
+import android.annotation.IntDef;
+import android.annotation.SuppressLint;
import android.app.StatusBarManager;
import android.content.Context;
import android.content.res.Configuration;
@@ -51,6 +55,7 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
+import android.view.Gravity;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
@@ -87,12 +92,21 @@ import com.android.systemui.statusbar.policy.KeyButtonDrawable;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.function.Consumer;
public class NavigationBarView extends FrameLayout implements PluginListener<NavGesture> {
final static boolean DEBUG = false;
final static String TAG = "StatusBar/NavBarView";
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({WINDOW_TARGET_BOTTOM, WINDOW_TARGET_LEFT, WINDOW_TARGET_RIGHT})
+ public @interface WindowTarget{}
+ public static final int WINDOW_TARGET_BOTTOM = 0;
+ public static final int WINDOW_TARGET_LEFT = 1;
+ public static final int WINDOW_TARGET_RIGHT = 2;
+
// slippery nav bar when everything is disabled, e.g. during setup
final static boolean SLIPPERY_WHEN_DISABLED = true;
@@ -109,6 +123,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
int mNavigationIconHints = 0;
private @NavigationBarCompat.HitTarget int mDownHitTarget = HIT_TARGET_NONE;
+ private @WindowTarget int mWindowHitTarget = WINDOW_TARGET_BOTTOM;
private Rect mHomeButtonBounds = new Rect();
private Rect mBackButtonBounds = new Rect();
private Rect mRecentsButtonBounds = new Rect();
@@ -160,6 +175,9 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
private NavigationAssistantAction mAssistantAction;
private NavigationNotificationPanelAction mNotificationPanelAction;
+ private NavigationBarEdgePanel mLeftEdgePanel;
+ private NavigationBarEdgePanel mRightEdgePanel;
+
/**
* Helper that is responsible for showing the right toast when a disallowed activity operation
* occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
@@ -222,6 +240,18 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
}
};
+ private final OnTouchListener mEdgePanelTouchListener = new OnTouchListener() {
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getActionMasked() == ACTION_DOWN) {
+ mWindowHitTarget = v == mLeftEdgePanel ? WINDOW_TARGET_LEFT : WINDOW_TARGET_RIGHT;
+ mDownHitTarget = HIT_TARGET_NONE;
+ }
+ return mGestureHelper.onTouchEvent(event);
+ }
+ };
+
private class H extends Handler {
public void handleMessage(Message m) {
switch (m.what) {
@@ -297,6 +327,16 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mColorAdaptionController.end();
}
}
+
+ @Override
+ public void onEdgeSensitivityChanged(int width, int height) {
+ if (mLeftEdgePanel != null) {
+ mLeftEdgePanel.setDimensions(width, height);
+ }
+ if (mRightEdgePanel != null) {
+ mRightEdgePanel.setDimensions(width, height);
+ }
+ }
};
public NavigationBarView(Context context, AttributeSet attrs) {
@@ -433,6 +473,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
int x = (int) event.getX();
int y = (int) event.getY();
mDownHitTarget = HIT_TARGET_NONE;
+ mWindowHitTarget = WINDOW_TARGET_BOTTOM;
if (deadZoneConsumed) {
mDownHitTarget = HIT_TARGET_DEAD_ZONE;
} else if (getBackButton().isVisible() && mBackButtonBounds.contains(x, y)) {
@@ -483,6 +524,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
return mDownHitTarget;
}
+ public @WindowTarget int getWindowTarget() {
+ return mWindowHitTarget;
+ }
+
public void abortCurrentGesture() {
getHomeButton().abortCurrentGesture();
}
@@ -837,24 +882,32 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
}
private void setSlippery(boolean slippery) {
- boolean changed = false;
+ setWindowFlag(WindowManager.LayoutParams.FLAG_SLIPPERY, slippery);
+ }
+
+ public void setWindowTouchable(boolean flag) {
+ setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
+ if (mLeftEdgePanel != null) {
+ mLeftEdgePanel.setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
+ }
+ if (mRightEdgePanel != null) {
+ mRightEdgePanel.setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
+ }
+ }
+
+ private void setWindowFlag(int flags, boolean enable) {
final ViewGroup navbarView = ((ViewGroup) getParent());
- final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) navbarView
- .getLayoutParams();
- if (lp == null) {
+ WindowManager.LayoutParams lp = (WindowManager.LayoutParams) navbarView.getLayoutParams();
+ if (lp == null || enable == ((lp.flags & flags) != 0)) {
return;
}
- if (slippery && (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) == 0) {
- lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
- changed = true;
- } else if (!slippery && (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) != 0) {
- lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY;
- changed = true;
- }
- if (changed) {
- WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
- wm.updateViewLayout(navbarView, lp);
+ if (enable) {
+ lp.flags |= flags;
+ } else {
+ lp.flags &= ~flags;
}
+ WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
+ wm.updateViewLayout(navbarView, lp);
}
public void setMenuVisibility(final boolean show) {
@@ -1016,6 +1069,17 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get nav bar position.", e);
}
+
+ // For landscape, hide the panel that would interfere with navigation bar layout
+ if (mLeftEdgePanel != null && mRightEdgePanel != null) {
+ mLeftEdgePanel.setVisibility(VISIBLE);
+ mRightEdgePanel.setVisibility(VISIBLE);
+ if (navBarPos == NAV_BAR_LEFT) {
+ mLeftEdgePanel.setVisibility(GONE);
+ } else if (navBarPos == NAV_BAR_RIGHT) {
+ mRightEdgePanel.setVisibility(GONE);
+ }
+ }
mGestureHelper.setBarState(isRtl, navBarPos);
}
@@ -1142,6 +1206,21 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
NavGesture.class, false /* Only one */);
setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
mColorAdaptionController.start();
+
+ if (mPrototypeController.isEnabled()) {
+ WindowManager wm = (WindowManager) getContext()
+ .getSystemService(Context.WINDOW_SERVICE);
+ int width = mPrototypeController.getEdgeSensitivityWidth();
+ int height = mPrototypeController.getEdgeSensitivityHeight();
+ mLeftEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height,
+ Gravity.START | Gravity.BOTTOM);
+ mRightEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height,
+ Gravity.END | Gravity.BOTTOM);
+ mLeftEdgePanel.setOnTouchListener(mEdgePanelTouchListener);
+ mRightEdgePanel.setOnTouchListener(mEdgePanelTouchListener);
+ wm.addView(mLeftEdgePanel, mLeftEdgePanel.getLayoutParams());
+ wm.addView(mRightEdgePanel, mRightEdgePanel.getLayoutParams());
+ }
}
@Override
@@ -1157,6 +1236,17 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
for (int i = 0; i < mButtonDispatchers.size(); ++i) {
mButtonDispatchers.valueAt(i).onDestroy();
}
+
+ if (mPrototypeController.isEnabled()) {
+ WindowManager wm = (WindowManager) getContext()
+ .getSystemService(Context.WINDOW_SERVICE);
+ if (mLeftEdgePanel != null) {
+ wm.removeView(mLeftEdgePanel);
+ }
+ if (mRightEdgePanel != null) {
+ wm.removeView(mRightEdgePanel);
+ }
+ }
}
private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index b4feb25fba7f..8421e23e97b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone;
import android.annotation.IntDef;
import android.content.Context;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
@@ -34,7 +35,12 @@ import java.lang.annotation.RetentionPolicy;
public class NavigationPrototypeController extends ContentObserver {
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";
+ private static final String EDGE_SENSITIVITY_HEIGHT_SETTING =
+ "quickstepcontroller_edge_height_sensitivity";
+ 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";
@@ -79,6 +85,8 @@ public class NavigationPrototypeController extends ContentObserver {
registerObserver(HIDE_HOME_BUTTON_SETTING);
registerObserver(GESTURE_MATCH_SETTING);
registerObserver(NAV_COLOR_ADAPT_ENABLE_SETTING);
+ registerObserver(EDGE_SENSITIVITY_WIDTH_SETTING);
+ registerObserver(EDGE_SENSITIVITY_HEIGHT_SETTING);
}
/**
@@ -106,10 +114,26 @@ public class NavigationPrototypeController extends ContentObserver {
} else if (path.endsWith(NAV_COLOR_ADAPT_ENABLE_SETTING)) {
mListener.onColorAdaptChanged(
NavBarTintController.isEnabled(mContext));
+ } else if (path.endsWith(EDGE_SENSITIVITY_WIDTH_SETTING)
+ || path.endsWith(EDGE_SENSITIVITY_HEIGHT_SETTING)) {
+ mListener.onEdgeSensitivityChanged(getEdgeSensitivityWidth(),
+ getEdgeSensitivityHeight());
}
}
}
+ public int getEdgeSensitivityWidth() {
+ return convertDpToPixel(getGlobalInt(EDGE_SENSITIVITY_WIDTH_SETTING, 0));
+ }
+
+ public int getEdgeSensitivityHeight() {
+ return convertDpToPixel(getGlobalInt(EDGE_SENSITIVITY_HEIGHT_SETTING, 0));
+ }
+
+ public boolean isEnabled() {
+ return getGlobalBool(PROTOTYPE_ENABLED, false);
+ }
+
/**
* Retrieve the action map to apply to the quick step controller
* @return an action map
@@ -144,15 +168,24 @@ public class NavigationPrototypeController extends ContentObserver {
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);
+ }
+
public interface OnPrototypeChangedListener {
void onGestureRemap(@GestureAction int[] actions);
void onBackButtonVisibilityChanged(boolean visible);
void onHomeButtonVisibilityChanged(boolean visible);
void onColorAdaptChanged(boolean enabled);
+ void onEdgeSensitivityChanged(int width, int height);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index d5d283c46b0a..84f1cef19b77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -28,9 +28,12 @@ import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
+import static com.android.systemui.statusbar.phone.NavigationBarView.WINDOW_TARGET_BOTTOM;
+import static com.android.systemui.statusbar.phone.NavigationPrototypeController.EDGE_SENSITIVITY_WIDTH_SETTING;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
@@ -42,12 +45,9 @@ import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
+import android.view.ViewConfiguration;
import android.view.ViewPropertyAnimator;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -72,6 +72,7 @@ public class QuickStepController implements GestureHelper {
/** Experiment to swipe home button left to execute a back key press */
private static final String HIDE_BACK_BUTTON_PROP = "quickstepcontroller_hideback";
private static final String ENABLE_CLICK_THROUGH_NAV_PROP = "quickstepcontroller_clickthrough";
+ private static final String GESTURE_REGION_THRESHOLD_SETTING = "gesture_region_threshold";
private static final long BACK_BUTTON_FADE_IN_ALPHA = 150;
private static final long CLICK_THROUGH_TAP_DELAY = 70;
private static final long CLICK_THROUGH_TAP_RESET_DELAY = 100;
@@ -109,10 +110,10 @@ public class QuickStepController implements GestureHelper {
private float mMaxDragLimit;
private float mMinDragLimit;
private float mDragDampeningFactor;
- private float mEdgeSwipeThreshold;
private boolean mClickThroughPressed;
private float mClickThroughPressX;
private float mClickThroughPressY;
+ private int mGestureRegionThreshold;
private NavigationGestureAction mCurrentAction;
private NavigationGestureAction[] mGestureActions = new NavigationGestureAction[MAX_GESTURES];
@@ -139,7 +140,7 @@ public class QuickStepController implements GestureHelper {
};
private final Runnable mClickThroughResetTap = () -> {
- setWindowTouchable(true);
+ mNavigationBarView.setWindowTouchable(true);
mClickThroughPressed = false;
};
@@ -210,7 +211,8 @@ public class QuickStepController implements GestureHelper {
// The same down event was just sent on intercept and therefore can be ignored here
final boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
- && mOverviewEventSender.getProxy() != null;
+ && mOverviewEventSender.getProxy() != null
+ && mNavigationBarView.getWindowTarget() == WINDOW_TARGET_BOTTOM;
return ignoreProxyDownEvent || handleTouchEvent(event);
}
@@ -268,12 +270,15 @@ public class QuickStepController implements GestureHelper {
mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
mAllowGestureDetection = true;
mNotificationsVisibleOnDown = !mNavigationBarView.isNotificationsFullyCollapsed();
- mEdgeSwipeThreshold = mContext.getResources()
- .getDimensionPixelSize(R.dimen.navigation_bar_edge_swipe_threshold);
+ final int defaultRegionThreshold = mContext.getResources()
+ .getDimensionPixelOffset(R.dimen.navigation_bar_default_edge_width);
+ mGestureRegionThreshold = convertDpToPixel(getIntGlobalSetting(mContext,
+ EDGE_SENSITIVITY_WIDTH_SETTING, defaultRegionThreshold));
break;
}
case MotionEvent.ACTION_MOVE: {
- if (!mAllowGestureDetection) {
+ if (!mAllowGestureDetection
+ || mNavigationBarView.getWindowTarget() != WINDOW_TARGET_BOTTOM) {
break;
}
int x = (int) event.getX();
@@ -330,18 +335,12 @@ public class QuickStepController implements GestureHelper {
} else if (exceededSwipeHorizontalTouchSlop) {
if (mDragHPositive ? (posH < touchDownH) : (posH > touchDownH)) {
// Swiping left (rtl) gesture
- int index = mGestureActions[ACTION_SWIPE_LEFT_FROM_EDGE_INDEX] != null
- && isEdgeSwipeAlongNavBar(touchDownH, !mDragHPositive)
- ? ACTION_SWIPE_LEFT_FROM_EDGE_INDEX : ACTION_SWIPE_LEFT_INDEX;
- tryToStartGesture(mGestureActions[index], true /* alignedWithNavBar */,
- event);
+ tryToStartGesture(mGestureActions[ACTION_SWIPE_LEFT_INDEX],
+ true /* alignedWithNavBar */, event);
} else {
// Swiping right (ltr) gesture
- int index = mGestureActions[ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX] != null
- && isEdgeSwipeAlongNavBar(touchDownH, mDragHPositive)
- ? ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX : ACTION_SWIPE_RIGHT_INDEX;
- tryToStartGesture(mGestureActions[index], true /* alignedWithNavBar */,
- event);
+ tryToStartGesture(mGestureActions[ACTION_SWIPE_RIGHT_INDEX],
+ true /* alignedWithNavBar */, event);
}
}
}
@@ -354,24 +353,34 @@ public class QuickStepController implements GestureHelper {
case MotionEvent.ACTION_UP:
if (mCurrentAction != null) {
mCurrentAction.endGesture();
- } else if (action == MotionEvent.ACTION_UP
- && getBoolGlobalSetting(mContext, ENABLE_CLICK_THROUGH_NAV_PROP)
- && !mClickThroughPressed) {
- // Enable click through functionality where no gesture has been detected and not
- // passed the drag slop so inject a touch event at the same location
- // after making the navigation bar window untouchable. After a some time, the
- // navigation bar will be able to take input events again
- float diffX = Math.abs(event.getX() - mTouchDownX);
- float diffY = Math.abs(event.getY() - mTouchDownY);
-
- if ((diffX <= NavigationBarCompat.getQuickStepDragSlopPx()
- && diffY <= NavigationBarCompat.getQuickStepDragSlopPx())) {
- setWindowTouchable(false);
- mClickThroughPressX = event.getRawX();
- mClickThroughPressY = event.getRawY();
- mClickThroughPressed = true;
- mNavigationBarView.postDelayed(mClickThroughSendTap,
- CLICK_THROUGH_TAP_DELAY);
+ } else if (action == MotionEvent.ACTION_UP) {
+ if (canTriggerEdgeSwipe(event)) {
+ int index = mNavigationBarView.getWindowTarget() == NAV_BAR_LEFT
+ ? ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX
+ : ACTION_SWIPE_LEFT_FROM_EDGE_INDEX;
+ tryToStartGesture(mGestureActions[index], false /* alignedWithNavBar */,
+ event);
+ if (mCurrentAction != null) {
+ mCurrentAction.endGesture();
+ }
+ } else if (getBoolGlobalSetting(mContext, ENABLE_CLICK_THROUGH_NAV_PROP)
+ && !mClickThroughPressed) {
+ // Enable click through functionality where no gesture has been detected and
+ // not passed the drag slop so inject a touch event at the same location
+ // after making the navigation bar window untouchable. After a some time,
+ // the navigation bar will be able to take input events again
+ float diffX = Math.abs(event.getX() - mTouchDownX);
+ float diffY = Math.abs(event.getY() - mTouchDownY);
+
+ if ((diffX <= NavigationBarCompat.getQuickStepDragSlopPx()
+ && diffY <= NavigationBarCompat.getQuickStepDragSlopPx())) {
+ mNavigationBarView.setWindowTouchable(false);
+ mClickThroughPressX = event.getRawX();
+ mClickThroughPressY = event.getRawY();
+ mClickThroughPressed = true;
+ mNavigationBarView.postDelayed(mClickThroughSendTap,
+ CLICK_THROUGH_TAP_DELAY);
+ }
}
}
@@ -403,30 +412,6 @@ public class QuickStepController implements GestureHelper {
return mCurrentAction != null || deadZoneConsumed;
}
- private void setWindowTouchable(boolean flag) {
- final WindowManager.LayoutParams lp = (WindowManager.LayoutParams)
- ((ViewGroup) mNavigationBarView.getParent()).getLayoutParams();
- if (flag) {
- lp.flags &= ~LayoutParams.FLAG_NOT_TOUCHABLE;
- } else {
- lp.flags |= LayoutParams.FLAG_NOT_TOUCHABLE;
- }
- final WindowManager wm = (WindowManager) mNavigationBarView.getContext()
- .getSystemService(Context.WINDOW_SERVICE);
- wm.updateViewLayout((View) mNavigationBarView.getParent(), lp);
- }
-
- private boolean isEdgeSwipeAlongNavBar(int touchDown, boolean dragPositiveDirection) {
- // Detect edge swipe from side of 0 -> threshold
- if (dragPositiveDirection) {
- return touchDown < mEdgeSwipeThreshold;
- }
- // Detect edge swipe from side of size -> (size - threshold)
- final int largeSide = isNavBarVertical()
- ? mNavigationBarView.getHeight() : mNavigationBarView.getWidth();
- return touchDown > largeSide - mEdgeSwipeThreshold;
- }
-
private void handleDragHitTarget(int position, int touchDown) {
// Drag the hit target if gesture action requires it
if (mHitTarget != null && (mGestureVerticalDragsButton || mGestureHorizontalDragsButton)) {
@@ -448,6 +433,10 @@ public class QuickStepController implements GestureHelper {
}
private boolean shouldProxyEvents(int action) {
+ // Do not send events for side navigation bar panels
+ if (mNavigationBarView.getWindowTarget() != WINDOW_TARGET_BOTTOM) {
+ return false;
+ }
final boolean actionValid = (mCurrentAction == null
|| !mCurrentAction.disableProxyEvents());
if (actionValid && !mIsInScreenPinning) {
@@ -619,6 +608,32 @@ public class QuickStepController implements GestureHelper {
}
}
+ /**
+ * To trigger an edge swipe, the user must start from the left or right edges of certain height
+ * from the bottom then past the drag slope towards the center of the screen, followed by either
+ * a timed trigger for fast swipes or distance if held on the screen longer.
+ * For time, user must swipe up quickly before the Tap Timeout (typically 100ms) and for
+ * distance, the user can drag back to cancel if the touch up has not past the threshold.
+ * @param event Touch up event
+ * @return whether or not edge swipe gesture occurs
+ */
+ private boolean canTriggerEdgeSwipe(MotionEvent event) {
+ if (mNavigationBarView.getWindowTarget() == WINDOW_TARGET_BOTTOM) {
+ return false;
+ }
+ int x = (int) event.getX();
+ int y = (int) event.getY();
+ int xDiff = Math.abs(x - mTouchDownX);
+ int yDiff = Math.abs(y - mTouchDownY);
+ final boolean exceededSwipeTouchSlop = xDiff > NavigationBarCompat.getQuickStepDragSlopPx()
+ && xDiff > yDiff;
+ if (exceededSwipeTouchSlop) {
+ long timeDiff = event.getEventTime() - event.getDownTime();
+ return xDiff > mGestureRegionThreshold || timeDiff < ViewConfiguration.getTapTimeout();
+ }
+ return false;
+ }
+
private boolean canPerformAnyAction() {
for (NavigationGestureAction action: mGestureActions) {
if (action != null && action.isEnabled()) {
@@ -684,10 +699,18 @@ public class QuickStepController implements GestureHelper {
return mNavBarPosition == NAV_BAR_LEFT || mNavBarPosition == NAV_BAR_RIGHT;
}
+ private static int convertDpToPixel(float dp) {
+ return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
+ }
+
static boolean getBoolGlobalSetting(Context context, String key) {
return Settings.Global.getInt(context.getContentResolver(), key, 0) != 0;
}
+ static int getIntGlobalSetting(Context context, String key, int defaultValue) {
+ return Settings.Global.getInt(context.getContentResolver(), key, defaultValue);
+ }
+
public static boolean shouldhideBackButton(Context context) {
return getBoolGlobalSetting(context, HIDE_BACK_BUTTON_PROP);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
index 382dde9ce043..dbf00a379c5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
@@ -23,6 +23,7 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_DEAD_ZONE;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
+import static com.android.systemui.statusbar.phone.NavigationBarView.WINDOW_TARGET_BOTTOM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -63,7 +64,6 @@ import org.mockito.MockitoAnnotations;
public class QuickStepControllerTest extends SysuiTestCase {
private static final int NAVBAR_WIDTH = 1000;
private static final int NAVBAR_HEIGHT = 300;
- private static final int EDGE_THRESHOLD = 100;
private QuickStepController mController;
private NavigationBarView mNavigationBarView;
@@ -77,8 +77,6 @@ public class QuickStepControllerTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
final ButtonDispatcher backButton = mock(ButtonDispatcher.class);
mResources = mock(Resources.class);
- doReturn(EDGE_THRESHOLD).when(mResources)
- .getDimensionPixelSize(R.dimen.navigation_bar_edge_swipe_threshold);
mProxyService = mock(OverviewProxyService.class);
mProxy = mock(IOverviewProxy.Stub.class);
@@ -95,6 +93,7 @@ public class QuickStepControllerTest extends SysuiTestCase {
doReturn(true).when(mNavigationBarView).isNotificationsFullyCollapsed();
doReturn(true).when(mNavigationBarView).isQuickScrubEnabled();
doReturn(HIT_TARGET_NONE).when(mNavigationBarView).getDownHitTarget();
+ doReturn(WINDOW_TARGET_BOTTOM).when(mNavigationBarView).getWindowTarget();
doReturn(backButton).when(mNavigationBarView).getBackButton();
doReturn(mResources).when(mNavigationBarView).getResources();
doReturn(mContext).when(mNavigationBarView).getContext();
@@ -196,10 +195,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- NavigationGestureAction swipeLeftFromEdge = mockAction(true);
- NavigationGestureAction swipeRightFromEdge = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
- swipeRightFromEdge);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+ null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
// Swipe Up
assertGestureTriggersAction(swipeUp, 1, 100, 5, 1);
@@ -209,10 +206,6 @@ public class QuickStepControllerTest extends SysuiTestCase {
assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH / 2, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeRight, NAVBAR_WIDTH / 2, 1, NAVBAR_WIDTH, 5);
- // Swipe Left from Edge
- assertGestureTriggersAction(swipeLeftFromEdge, NAVBAR_WIDTH, 1, 5, 1);
- // Swipe Right from Edge
- assertGestureTriggersAction(swipeRightFromEdge, 0, 1, NAVBAR_WIDTH, 5);
}
@Test
@@ -224,10 +217,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- NavigationGestureAction swipeLeftFromEdge = mockAction(true);
- NavigationGestureAction swipeRightFromEdge = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
- swipeRightFromEdge);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+ null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
// In landscape
mController.setBarState(false /* isRTL */, NAV_BAR_RIGHT);
@@ -240,10 +231,6 @@ public class QuickStepControllerTest extends SysuiTestCase {
assertGestureTriggersAction(swipeUp, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeDown, 1, 1, 100, 5);
- // Swipe Up from Edge
- assertGestureTriggersAction(swipeRightFromEdge, 1, NAVBAR_WIDTH, 5, 0);
- // Swipe Down from Edge
- assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
@@ -256,10 +243,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- NavigationGestureAction swipeLeftFromEdge = mockAction(true);
- NavigationGestureAction swipeRightFromEdge = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
- swipeRightFromEdge);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+ null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
// Swipe Up
assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, 1);
@@ -269,10 +254,6 @@ public class QuickStepControllerTest extends SysuiTestCase {
assertGestureTriggersAction(swipeDown, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeUp, 1, 1, 100, 5);
- // Swipe Up from Edge
- assertGestureTriggersAction(swipeLeftFromEdge, 1, NAVBAR_WIDTH, 5, 0);
- // Swipe Down from Edge
- assertGestureTriggersAction(swipeRightFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
@@ -286,10 +267,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- NavigationGestureAction swipeLeftFromEdge = mockAction(true);
- NavigationGestureAction swipeRightFromEdge = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
- swipeRightFromEdge);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+ null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
// Swipe Up in RTL
assertGestureTriggersAction(swipeUp, 1, 100, 5, 1);
@@ -299,10 +278,6 @@ public class QuickStepControllerTest extends SysuiTestCase {
assertGestureTriggersAction(swipeRight, NAVBAR_WIDTH / 2, 1, 5, 1);
// Swipe Right in RTL
assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH / 2, 1, NAVBAR_WIDTH, 0);
- // Swipe Left from Edge
- assertGestureTriggersAction(swipeRightFromEdge, NAVBAR_WIDTH, 1, 5, 1);
- // Swipe Right from Edge
- assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, NAVBAR_WIDTH, 5);
}
@Test
@@ -316,10 +291,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- NavigationGestureAction swipeLeftFromEdge = mockAction(true);
- NavigationGestureAction swipeRightFromEdge = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
- swipeRightFromEdge);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+ null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
// Swipe Up
assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, 1);
@@ -329,10 +302,6 @@ public class QuickStepControllerTest extends SysuiTestCase {
assertGestureTriggersAction(swipeUp, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeDown, 1, 1, 100, 5);
- // Swipe Up from Edge
- assertGestureTriggersAction(swipeLeftFromEdge, 1, NAVBAR_WIDTH, 5, 0);
- // Swipe Down from Edge
- assertGestureTriggersAction(swipeRightFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
@@ -346,10 +315,8 @@ public class QuickStepControllerTest extends SysuiTestCase {
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- NavigationGestureAction swipeLeftFromEdge = mockAction(true);
- NavigationGestureAction swipeRightFromEdge = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
- swipeRightFromEdge);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+ null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
// Swipe Up
assertGestureTriggersAction(swipeRight, 1, NAVBAR_WIDTH / 2, 5, 1);
@@ -359,10 +326,6 @@ public class QuickStepControllerTest extends SysuiTestCase {
assertGestureTriggersAction(swipeDown, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeUp, 1, 1, 100, 5);
- // Swipe Up from Edge
- assertGestureTriggersAction(swipeRightFromEdge, 1, NAVBAR_WIDTH, 5, 0);
- // Swipe Down from Edge
- assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
@@ -602,25 +565,6 @@ public class QuickStepControllerTest extends SysuiTestCase {
assertGestureDragsHitTargetAllDirections(buttonView, true /* isRTL */, NAV_BAR_LEFT);
}
- @Test
- public void testNoEdgeActionsTriggerNormalActions() {
- doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
- doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
-
- NavigationGestureAction swipeUp = mockAction(true);
- NavigationGestureAction swipeDown = mockAction(true);
- NavigationGestureAction swipeLeft = mockAction(true);
- NavigationGestureAction swipeRight = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
- null /* swipeLeftFromEdgeAction */,
- null /* swipeLeftFromEdgeAction */);
-
- // Swipe Left from Edge
- assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH, 1, 5, 1);
- // Swipe Right from Edge
- assertGestureTriggersAction(swipeRight, 0, 1, NAVBAR_WIDTH, 5);
- }
-
private void assertGestureDragsHitTargetAllDirections(View buttonView, boolean isRTL,
int navPos) {
mController.setBarState(isRTL, navPos);