blob: 6bd122d97dea40ea8279e4ae31605ff314924537 [file] [log] [blame]
Sunny Goyala6a58122019-04-02 10:20:29 -07001/**
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.systemui.statusbar.phone;
17
Mady Mellor390bff42019-04-05 15:09:01 -070018import static android.view.Display.INVALID_DISPLAY;
19
Sunny Goyala6a58122019-04-02 10:20:29 -070020import android.content.Context;
Matthew Ng682ad7a2019-04-09 15:48:01 -070021import android.content.res.Resources;
Sunny Goyala6a58122019-04-02 10:20:29 -070022import android.graphics.PixelFormat;
23import android.graphics.Point;
24import android.graphics.PointF;
Sunny Goyala6a58122019-04-02 10:20:29 -070025import android.graphics.Region;
26import android.hardware.display.DisplayManager;
27import android.hardware.display.DisplayManager.DisplayListener;
28import android.hardware.input.InputManager;
29import android.os.Looper;
30import android.os.RemoteException;
31import android.os.SystemClock;
Adam Cohena699c282019-08-07 15:29:34 -070032import android.os.SystemProperties;
Sunny Goyala6a58122019-04-02 10:20:29 -070033import android.util.Log;
Sunny Goyala6a58122019-04-02 10:20:29 -070034import android.view.ISystemGestureExclusionListener;
Siarhei Vishniakoufaa87992019-05-29 09:12:18 -070035import android.view.InputChannel;
Sunny Goyala6a58122019-04-02 10:20:29 -070036import android.view.InputDevice;
37import android.view.InputEvent;
Siarhei Vishniakoufaa87992019-05-29 09:12:18 -070038import android.view.InputEventReceiver;
Sunny Goyala6a58122019-04-02 10:20:29 -070039import android.view.InputMonitor;
40import android.view.KeyCharacterMap;
41import android.view.KeyEvent;
42import android.view.MotionEvent;
43import android.view.ViewConfiguration;
44import android.view.WindowManager;
45import android.view.WindowManagerGlobal;
46
Mady Mellor390bff42019-04-05 15:09:01 -070047import com.android.systemui.Dependency;
Sunny Goyala6a58122019-04-02 10:20:29 -070048import com.android.systemui.R;
Mady Mellor390bff42019-04-05 15:09:01 -070049import com.android.systemui.bubbles.BubbleController;
Vinit Nayak59b114e62019-08-12 11:50:00 -070050import com.android.systemui.model.SysUiState;
Andy Wickham20297012019-11-06 14:56:26 -080051import com.android.systemui.plugins.NavigationEdgeBackPlugin;
52import com.android.systemui.plugins.PluginListener;
Winson Chung04ff8bda2019-04-02 15:08:59 -070053import com.android.systemui.recents.OverviewProxyService;
Andy Wickham20297012019-11-06 14:56:26 -080054import com.android.systemui.shared.plugins.PluginManager;
Sunny Goyala6a58122019-04-02 10:20:29 -070055import com.android.systemui.shared.system.QuickStepContract;
Muhammad Qureshi9bced7d2020-01-16 15:22:12 -080056import com.android.systemui.shared.system.SysUiStatsLog;
Sunny Goyala6a58122019-04-02 10:20:29 -070057
Winson Chung316f6732019-06-14 09:31:46 -070058import java.io.PrintWriter;
Sunny Goyala6a58122019-04-02 10:20:29 -070059import java.util.concurrent.Executor;
60
61/**
62 * Utility class to handle edge swipes for back gesture
63 */
Andy Wickham20297012019-11-06 14:56:26 -080064public class EdgeBackGestureHandler implements DisplayListener,
65 PluginListener<NavigationEdgeBackPlugin> {
Sunny Goyala6a58122019-04-02 10:20:29 -070066
67 private static final String TAG = "EdgeBackGestureHandler";
Adam Cohena699c282019-08-07 15:29:34 -070068 private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt(
69 "gestures.back_timeout", 250);
Sunny Goyala6a58122019-04-02 10:20:29 -070070
Sunny Goyala6a58122019-04-02 10:20:29 -070071 private ISystemGestureExclusionListener mGestureExclusionListener =
72 new ISystemGestureExclusionListener.Stub() {
73 @Override
74 public void onSystemGestureExclusionChanged(int displayId,
Adrian Roos5f2c9a12019-07-03 18:31:46 +020075 Region systemGestureExclusion, Region unrestrictedOrNull) {
Sunny Goyala6a58122019-04-02 10:20:29 -070076 if (displayId == mDisplayId) {
Hyunyoung Song36d7a2f2019-08-05 17:19:54 -070077 mMainExecutor.execute(() -> {
78 mExcludeRegion.set(systemGestureExclusion);
79 mUnrestrictedExcludeRegion.set(unrestrictedOrNull != null
80 ? unrestrictedOrNull : systemGestureExclusion);
81 });
Sunny Goyala6a58122019-04-02 10:20:29 -070082 }
83 }
84 };
85
86 private final Context mContext;
Winson Chung04ff8bda2019-04-02 15:08:59 -070087 private final OverviewProxyService mOverviewProxyService;
Andy Wickham20297012019-11-06 14:56:26 -080088 private PluginManager mPluginManager;
Sunny Goyala6a58122019-04-02 10:20:29 -070089
90 private final Point mDisplaySize = new Point();
91 private final int mDisplayId;
92
93 private final Executor mMainExecutor;
94
95 private final Region mExcludeRegion = new Region();
Hyunyoung Song36d7a2f2019-08-05 17:19:54 -070096 private final Region mUnrestrictedExcludeRegion = new Region();
97
Sunny Goyala6a58122019-04-02 10:20:29 -070098 // The edge width where touch down is allowed
Winson Chung316f6732019-06-14 09:31:46 -070099 private int mEdgeWidth;
Winson Chung77b2d1d2019-12-20 15:18:42 -0800100 // The bottom gesture area height
101 private int mBottomGestureHeight;
Sunny Goyala6a58122019-04-02 10:20:29 -0700102 // The slop to distinguish between horizontal and vertical motion
103 private final float mTouchSlop;
Sunny Goyal3c317f32019-05-21 11:49:11 -0700104 // Duration after which we consider the event as longpress.
105 private final int mLongPressTimeout;
Sunny Goyala6a58122019-04-02 10:20:29 -0700106
107 private final PointF mDownPoint = new PointF();
108 private boolean mThresholdCrossed = false;
Winson Chunge2a686d2019-04-17 16:54:23 -0700109 private boolean mAllowGesture = false;
Hyunyoung Song36d7a2f2019-08-05 17:19:54 -0700110 private boolean mInRejectedExclusion = false;
Sunny Goyala6a58122019-04-02 10:20:29 -0700111 private boolean mIsOnLeftEdge;
112
Sunny Goyala6a58122019-04-02 10:20:29 -0700113 private boolean mIsAttached;
114 private boolean mIsGesturalModeEnabled;
115 private boolean mIsEnabled;
Jorim Jaggi956ca412019-01-07 14:49:14 +0100116 private boolean mIsNavBarShownTransiently;
Sunny Goyala6a58122019-04-02 10:20:29 -0700117
118 private InputMonitor mInputMonitor;
119 private InputEventReceiver mInputEventReceiver;
120
Andy Wickham20297012019-11-06 14:56:26 -0800121 private NavigationEdgeBackPlugin mEdgeBackPlugin;
Selim Cineke50b1212019-06-04 18:40:31 -0700122 private int mLeftInset;
123 private int mRightInset;
Vinit Nayak59b114e62019-08-12 11:50:00 -0700124 private int mSysUiFlags;
Sunny Goyala6a58122019-04-02 10:20:29 -0700125
Andy Wickham20297012019-11-06 14:56:26 -0800126 private final NavigationEdgeBackPlugin.BackCallback mBackCallback =
127 new NavigationEdgeBackPlugin.BackCallback() {
128 @Override
129 public void triggerBack() {
130 sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
131 sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
132
133 mOverviewProxyService.notifyBackAction(true, (int) mDownPoint.x,
134 (int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge);
135 int backtype = (mInRejectedExclusion
Muhammad Qureshi9bced7d2020-01-16 15:22:12 -0800136 ? SysUiStatsLog.BACK_GESTURE__TYPE__COMPLETED_REJECTED :
137 SysUiStatsLog.BACK_GESTURE__TYPE__COMPLETED);
138 SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED, backtype,
Andy Wickham20297012019-11-06 14:56:26 -0800139 (int) mDownPoint.y, mIsOnLeftEdge
Muhammad Qureshi9bced7d2020-01-16 15:22:12 -0800140 ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT :
141 SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT);
Andy Wickham20297012019-11-06 14:56:26 -0800142 }
143
144 @Override
145 public void cancelBack() {
146 mOverviewProxyService.notifyBackAction(false, (int) mDownPoint.x,
147 (int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge);
Muhammad Qureshi9bced7d2020-01-16 15:22:12 -0800148 int backtype = SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE;
149 SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED, backtype,
Andy Wickham20297012019-11-06 14:56:26 -0800150 (int) mDownPoint.y, mIsOnLeftEdge
Muhammad Qureshi9bced7d2020-01-16 15:22:12 -0800151 ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT :
152 SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT);
Andy Wickham20297012019-11-06 14:56:26 -0800153 }
154 };
155
Vinit Nayak59b114e62019-08-12 11:50:00 -0700156 public EdgeBackGestureHandler(Context context, OverviewProxyService overviewProxyService,
Andy Wickham20297012019-11-06 14:56:26 -0800157 SysUiState sysUiFlagContainer, PluginManager pluginManager) {
Matthew Ng682ad7a2019-04-09 15:48:01 -0700158 final Resources res = context.getResources();
Sunny Goyala6a58122019-04-02 10:20:29 -0700159 mContext = context;
160 mDisplayId = context.getDisplayId();
161 mMainExecutor = context.getMainExecutor();
Winson Chung04ff8bda2019-04-02 15:08:59 -0700162 mOverviewProxyService = overviewProxyService;
Andy Wickham20297012019-11-06 14:56:26 -0800163 mPluginManager = pluginManager;
Sunny Goyala6a58122019-04-02 10:20:29 -0700164
Siarhei Vishniakoufaa87992019-05-29 09:12:18 -0700165 // Reduce the default touch slop to ensure that we can intercept the gesture
166 // before the app starts to react to it.
167 // TODO(b/130352502) Tune this value and extract into a constant
168 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 0.75f;
Winson Chung05d4be32019-06-19 13:12:10 -0700169 mLongPressTimeout = Math.min(MAX_LONG_PRESS_TIMEOUT,
170 ViewConfiguration.getLongPressTimeout());
Sunny Goyala6a58122019-04-02 10:20:29 -0700171
Winson Chung316f6732019-06-14 09:31:46 -0700172 updateCurrentUserResources(res);
Vinit Nayak59b114e62019-08-12 11:50:00 -0700173 sysUiFlagContainer.addCallback(sysUiFlags -> mSysUiFlags = sysUiFlags);
Winson Chung316f6732019-06-14 09:31:46 -0700174 }
175
176 public void updateCurrentUserResources(Resources res) {
177 mEdgeWidth = res.getDimensionPixelSize(
178 com.android.internal.R.dimen.config_backGestureInset);
Winson Chung77b2d1d2019-12-20 15:18:42 -0800179 mBottomGestureHeight = res.getDimensionPixelSize(
180 com.android.internal.R.dimen.navigation_bar_gesture_height);
Sunny Goyala6a58122019-04-02 10:20:29 -0700181 }
182
183 /**
184 * @see NavigationBarView#onAttachedToWindow()
185 */
186 public void onNavBarAttached() {
187 mIsAttached = true;
Winson Chung1aa24b92019-04-24 15:17:33 -0700188 updateIsEnabled();
Sunny Goyala6a58122019-04-02 10:20:29 -0700189 }
190
191 /**
192 * @see NavigationBarView#onDetachedFromWindow()
193 */
194 public void onNavBarDetached() {
195 mIsAttached = false;
196 updateIsEnabled();
197 }
198
Winson Chung316f6732019-06-14 09:31:46 -0700199 public void onNavigationModeChanged(int mode, Context currentUserContext) {
Winson Chung1aa24b92019-04-24 15:17:33 -0700200 mIsGesturalModeEnabled = QuickStepContract.isGesturalMode(mode);
Sunny Goyala6a58122019-04-02 10:20:29 -0700201 updateIsEnabled();
Winson Chung316f6732019-06-14 09:31:46 -0700202 updateCurrentUserResources(currentUserContext.getResources());
Sunny Goyala6a58122019-04-02 10:20:29 -0700203 }
204
Jorim Jaggi956ca412019-01-07 14:49:14 +0100205 public void onNavBarTransientStateChanged(boolean isTransient) {
206 mIsNavBarShownTransiently = isTransient;
Winson Chung3d6c0802019-10-04 10:37:12 -0700207 }
208
Sunny Goyala6a58122019-04-02 10:20:29 -0700209 private void disposeInputChannel() {
210 if (mInputEventReceiver != null) {
211 mInputEventReceiver.dispose();
212 mInputEventReceiver = null;
213 }
214 if (mInputMonitor != null) {
215 mInputMonitor.dispose();
216 mInputMonitor = null;
217 }
218 }
219
220 private void updateIsEnabled() {
221 boolean isEnabled = mIsAttached && mIsGesturalModeEnabled;
222 if (isEnabled == mIsEnabled) {
223 return;
224 }
225 mIsEnabled = isEnabled;
226 disposeInputChannel();
227
Andy Wickham20297012019-11-06 14:56:26 -0800228 if (mEdgeBackPlugin != null) {
229 mEdgeBackPlugin.onDestroy();
230 mEdgeBackPlugin = null;
Sunny Goyala6a58122019-04-02 10:20:29 -0700231 }
232
233 if (!mIsEnabled) {
Sunny Goyal19049692019-04-08 11:56:07 -0700234 mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
Andy Wickham20297012019-11-06 14:56:26 -0800235 mPluginManager.removePluginListener(this);
Sunny Goyala6a58122019-04-02 10:20:29 -0700236
237 try {
238 WindowManagerGlobal.getWindowManagerService()
239 .unregisterSystemGestureExclusionListener(
240 mGestureExclusionListener, mDisplayId);
241 } catch (RemoteException e) {
242 Log.e(TAG, "Failed to unregister window manager callbacks", e);
243 }
244
245 } else {
246 updateDisplaySize();
Sunny Goyal19049692019-04-08 11:56:07 -0700247 mContext.getSystemService(DisplayManager.class).registerDisplayListener(this,
248 mContext.getMainThreadHandler());
Sunny Goyala6a58122019-04-02 10:20:29 -0700249
250 try {
Sunny Goyala6a58122019-04-02 10:20:29 -0700251 WindowManagerGlobal.getWindowManagerService()
252 .registerSystemGestureExclusionListener(
253 mGestureExclusionListener, mDisplayId);
254 } catch (RemoteException e) {
255 Log.e(TAG, "Failed to register window manager callbacks", e);
256 }
257
258 // Register input event receiver
259 mInputMonitor = InputManager.getInstance().monitorGestureInput(
260 "edge-swipe", mDisplayId);
Siarhei Vishniakoufaa87992019-05-29 09:12:18 -0700261 mInputEventReceiver = new SysUiInputEventReceiver(
262 mInputMonitor.getInputChannel(), Looper.getMainLooper());
Sunny Goyala6a58122019-04-02 10:20:29 -0700263
264 // Add a nav bar panel window
Andy Wickham20297012019-11-06 14:56:26 -0800265 setEdgeBackPlugin(new NavigationBarEdgePanel(mContext));
266 mPluginManager.addPluginListener(
267 this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false);
Sunny Goyala6a58122019-04-02 10:20:29 -0700268 }
269 }
270
Andy Wickham20297012019-11-06 14:56:26 -0800271 @Override
272 public void onPluginConnected(NavigationEdgeBackPlugin plugin, Context context) {
273 setEdgeBackPlugin(plugin);
274 }
275
276 @Override
277 public void onPluginDisconnected(NavigationEdgeBackPlugin plugin) {
278 setEdgeBackPlugin(new NavigationBarEdgePanel(mContext));
279 }
280
281 private void setEdgeBackPlugin(NavigationEdgeBackPlugin edgeBackPlugin) {
282 if (mEdgeBackPlugin != null) {
283 mEdgeBackPlugin.onDestroy();
284 }
285 mEdgeBackPlugin = edgeBackPlugin;
286 mEdgeBackPlugin.setBackCallback(mBackCallback);
287 mEdgeBackPlugin.setLayoutParams(createLayoutParams());
288 updateDisplaySize();
289 }
290
291 private WindowManager.LayoutParams createLayoutParams() {
292 Resources resources = mContext.getResources();
293 WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
294 resources.getDimensionPixelSize(R.dimen.navigation_edge_panel_width),
295 resources.getDimensionPixelSize(R.dimen.navigation_edge_panel_height),
296 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
297 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
298 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
299 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
300 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
301 PixelFormat.TRANSLUCENT);
302 layoutParams.privateFlags |=
303 WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
304 layoutParams.setTitle(TAG + mContext.getDisplayId());
305 layoutParams.accessibilityTitle = mContext.getString(R.string.nav_bar_edge_panel);
306 layoutParams.windowAnimations = 0;
Tiger Huang52724442020-01-20 21:38:42 +0800307 layoutParams.setFitInsetsTypes(0 /* types */);
Andy Wickham20297012019-11-06 14:56:26 -0800308 return layoutParams;
309 }
310
Sunny Goyala6a58122019-04-02 10:20:29 -0700311 private void onInputEvent(InputEvent ev) {
312 if (ev instanceof MotionEvent) {
313 onMotionEvent((MotionEvent) ev);
314 }
315 }
316
317 private boolean isWithinTouchRegion(int x, int y) {
Winson Chung3d6c0802019-10-04 10:37:12 -0700318 // Disallow if too far from the edge
Selim Cineke50b1212019-06-04 18:40:31 -0700319 if (x > mEdgeWidth + mLeftInset && x < (mDisplaySize.x - mEdgeWidth - mRightInset)) {
Sunny Goyala6a58122019-04-02 10:20:29 -0700320 return false;
321 }
Winson Chung3d6c0802019-10-04 10:37:12 -0700322
Winson Chung77b2d1d2019-12-20 15:18:42 -0800323 // Disallow if we are in the bottom gesture area
324 if (y >= (mDisplaySize.y - mBottomGestureHeight)) {
325 return false;
326 }
327
Winson Chung3d6c0802019-10-04 10:37:12 -0700328 // Always allow if the user is in a transient sticky immersive state
Jorim Jaggi956ca412019-01-07 14:49:14 +0100329 if (mIsNavBarShownTransiently) {
Winson Chung3d6c0802019-10-04 10:37:12 -0700330 return true;
331 }
332
Winson Chung51787a12019-04-10 15:33:31 -0700333 boolean isInExcludedRegion = mExcludeRegion.contains(x, y);
334 if (isInExcludedRegion) {
335 mOverviewProxyService.notifyBackAction(false /* completed */, -1, -1,
336 false /* isButton */, !mIsOnLeftEdge);
Muhammad Qureshi9bced7d2020-01-16 15:22:12 -0800337 SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED,
338 SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_EXCLUDED, y,
339 mIsOnLeftEdge ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT :
340 SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT);
Hyunyoung Song36d7a2f2019-08-05 17:19:54 -0700341 } else {
342 mInRejectedExclusion = mUnrestrictedExcludeRegion.contains(x, y);
Winson Chung51787a12019-04-10 15:33:31 -0700343 }
344 return !isInExcludedRegion;
Sunny Goyala6a58122019-04-02 10:20:29 -0700345 }
346
Sunny Goyal3c317f32019-05-21 11:49:11 -0700347 private void cancelGesture(MotionEvent ev) {
348 // Send action cancel to reset all the touch events
349 mAllowGesture = false;
Hyunyoung Song36d7a2f2019-08-05 17:19:54 -0700350 mInRejectedExclusion = false;
Sunny Goyal3c317f32019-05-21 11:49:11 -0700351 MotionEvent cancelEv = MotionEvent.obtain(ev);
352 cancelEv.setAction(MotionEvent.ACTION_CANCEL);
Andy Wickham20297012019-11-06 14:56:26 -0800353 mEdgeBackPlugin.onMotionEvent(cancelEv);
Sunny Goyal3c317f32019-05-21 11:49:11 -0700354 cancelEv.recycle();
355 }
356
Sunny Goyala6a58122019-04-02 10:20:29 -0700357 private void onMotionEvent(MotionEvent ev) {
Sunny Goyal3c317f32019-05-21 11:49:11 -0700358 int action = ev.getActionMasked();
359 if (action == MotionEvent.ACTION_DOWN) {
Winson Chunge2a686d2019-04-17 16:54:23 -0700360 // Verify if this is in within the touch region and we aren't in immersive mode, and
361 // either the bouncer is showing or the notification panel is hidden
Selim Cineke50b1212019-06-04 18:40:31 -0700362 mIsOnLeftEdge = ev.getX() <= mEdgeWidth + mLeftInset;
Hyunyoung Song36d7a2f2019-08-05 17:19:54 -0700363 mInRejectedExclusion = false;
Vinit Nayak59b114e62019-08-12 11:50:00 -0700364 mAllowGesture = !QuickStepContract.isBackGestureDisabled(mSysUiFlags)
Winson Chunge2a686d2019-04-17 16:54:23 -0700365 && isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
366 if (mAllowGesture) {
Andy Wickham20297012019-11-06 14:56:26 -0800367 mEdgeBackPlugin.setIsLeftPanel(mIsOnLeftEdge);
368 mEdgeBackPlugin.onMotionEvent(ev);
Sunny Goyala6a58122019-04-02 10:20:29 -0700369
370 mDownPoint.set(ev.getX(), ev.getY());
371 mThresholdCrossed = false;
Sunny Goyala6a58122019-04-02 10:20:29 -0700372 }
Winson Chunge2a686d2019-04-17 16:54:23 -0700373 } else if (mAllowGesture) {
Sunny Goyal3c317f32019-05-21 11:49:11 -0700374 if (!mThresholdCrossed) {
375 if (action == MotionEvent.ACTION_POINTER_DOWN) {
376 // We do not support multi touch for back gesture
377 cancelGesture(ev);
Sunny Goyala6a58122019-04-02 10:20:29 -0700378 return;
Sunny Goyal3c317f32019-05-21 11:49:11 -0700379 } else if (action == MotionEvent.ACTION_MOVE) {
380 if ((ev.getEventTime() - ev.getDownTime()) > mLongPressTimeout) {
381 cancelGesture(ev);
382 return;
383 }
384 float dx = Math.abs(ev.getX() - mDownPoint.x);
385 float dy = Math.abs(ev.getY() - mDownPoint.y);
386 if (dy > dx && dy > mTouchSlop) {
387 cancelGesture(ev);
388 return;
Sunny Goyala6a58122019-04-02 10:20:29 -0700389
Sunny Goyal3c317f32019-05-21 11:49:11 -0700390 } else if (dx > dy && dx > mTouchSlop) {
391 mThresholdCrossed = true;
392 // Capture inputs
393 mInputMonitor.pilferPointers();
394 }
Sunny Goyala6a58122019-04-02 10:20:29 -0700395 }
Sunny Goyal3c317f32019-05-21 11:49:11 -0700396
Sunny Goyala6a58122019-04-02 10:20:29 -0700397 }
398
399 // forward touch
Andy Wickham20297012019-11-06 14:56:26 -0800400 mEdgeBackPlugin.onMotionEvent(ev);
Sunny Goyala6a58122019-04-02 10:20:29 -0700401 }
402 }
403
404 @Override
405 public void onDisplayAdded(int displayId) { }
406
407 @Override
408 public void onDisplayRemoved(int displayId) { }
409
410 @Override
411 public void onDisplayChanged(int displayId) {
412 if (displayId == mDisplayId) {
413 updateDisplaySize();
414 }
415 }
416
417 private void updateDisplaySize() {
418 mContext.getSystemService(DisplayManager.class)
Sunny Goyal19049692019-04-08 11:56:07 -0700419 .getDisplay(mDisplayId)
420 .getRealSize(mDisplaySize);
Andy Wickham20297012019-11-06 14:56:26 -0800421 if (mEdgeBackPlugin != null) {
422 mEdgeBackPlugin.setDisplaySize(mDisplaySize);
423 }
Sunny Goyala6a58122019-04-02 10:20:29 -0700424 }
425
426 private void sendEvent(int action, int code) {
427 long when = SystemClock.uptimeMillis();
428 final KeyEvent ev = new KeyEvent(when, when, action, code, 0 /* repeat */,
429 0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
430 KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
431 InputDevice.SOURCE_KEYBOARD);
Mady Mellor390bff42019-04-05 15:09:01 -0700432
433 // Bubble controller will give us a valid display id if it should get the back event
434 BubbleController bubbleController = Dependency.get(BubbleController.class);
435 int bubbleDisplayId = bubbleController.getExpandedDisplayId(mContext);
436 if (code == KeyEvent.KEYCODE_BACK && bubbleDisplayId != INVALID_DISPLAY) {
437 ev.setDisplayId(bubbleDisplayId);
438 }
Sunny Goyala6a58122019-04-02 10:20:29 -0700439 InputManager.getInstance().injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
440 }
Siarhei Vishniakoufaa87992019-05-29 09:12:18 -0700441
Selim Cineke50b1212019-06-04 18:40:31 -0700442 public void setInsets(int leftInset, int rightInset) {
443 mLeftInset = leftInset;
444 mRightInset = rightInset;
Andy Wickham20297012019-11-06 14:56:26 -0800445 if (mEdgeBackPlugin != null) {
446 mEdgeBackPlugin.setInsets(leftInset, rightInset);
447 }
Selim Cineke50b1212019-06-04 18:40:31 -0700448 }
449
Winson Chung316f6732019-06-14 09:31:46 -0700450 public void dump(PrintWriter pw) {
451 pw.println("EdgeBackGestureHandler:");
452 pw.println(" mIsEnabled=" + mIsEnabled);
453 pw.println(" mAllowGesture=" + mAllowGesture);
Hyunyoung Song36d7a2f2019-08-05 17:19:54 -0700454 pw.println(" mInRejectedExclusion" + mInRejectedExclusion);
Winson Chung316f6732019-06-14 09:31:46 -0700455 pw.println(" mExcludeRegion=" + mExcludeRegion);
Hyunyoung Song36d7a2f2019-08-05 17:19:54 -0700456 pw.println(" mUnrestrictedExcludeRegion=" + mUnrestrictedExcludeRegion);
Winson Chung316f6732019-06-14 09:31:46 -0700457 pw.println(" mIsAttached=" + mIsAttached);
458 pw.println(" mEdgeWidth=" + mEdgeWidth);
459 }
460
Siarhei Vishniakoufaa87992019-05-29 09:12:18 -0700461 class SysUiInputEventReceiver extends InputEventReceiver {
462 SysUiInputEventReceiver(InputChannel channel, Looper looper) {
463 super(channel, looper);
464 }
465
466 public void onInputEvent(InputEvent event) {
467 EdgeBackGestureHandler.this.onInputEvent(event);
468 finishInputEvent(event, true);
469 }
470 }
Sunny Goyala6a58122019-04-02 10:20:29 -0700471}