• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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  */
16 package com.android.quickstep;
17 
18 import static android.view.MotionEvent.ACTION_DOWN;
19 
20 import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
21 import static com.android.launcher3.config.FeatureFlags.APPLY_CONFIG_AT_RUNTIME;
22 import static com.android.launcher3.config.FeatureFlags.ENABLE_HINTS_IN_OVERVIEW;
23 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
24 import static com.android.launcher3.config.FeatureFlags.FAKE_LANDSCAPE_UI;
25 import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
26 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
27 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
28 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
29 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
30 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
31 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
32 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
33 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
34 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
35 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
36 
37 import android.annotation.TargetApi;
38 import android.app.ActivityManager;
39 import android.app.ActivityManager.RunningTaskInfo;
40 import android.app.Service;
41 import android.content.BroadcastReceiver;
42 import android.content.ComponentName;
43 import android.content.Context;
44 import android.content.Intent;
45 import android.content.IntentFilter;
46 import android.graphics.Point;
47 import android.graphics.RectF;
48 import android.graphics.Region;
49 import android.hardware.display.DisplayManager;
50 import android.hardware.display.DisplayManager.DisplayListener;
51 import android.os.Build;
52 import android.os.Bundle;
53 import android.os.IBinder;
54 import android.os.Looper;
55 import android.os.Process;
56 import android.os.RemoteException;
57 import android.text.TextUtils;
58 import android.util.Log;
59 import android.view.Choreographer;
60 import android.view.Display;
61 import android.view.InputEvent;
62 import android.view.MotionEvent;
63 import android.view.Surface;
64 import android.view.WindowManager;
65 
66 import androidx.annotation.BinderThread;
67 import androidx.annotation.UiThread;
68 
69 import com.android.launcher3.BaseDraggingActivity;
70 import com.android.launcher3.MainThreadExecutor;
71 import com.android.launcher3.R;
72 import com.android.launcher3.ResourceUtils;
73 import com.android.launcher3.Utilities;
74 import com.android.launcher3.compat.UserManagerCompat;
75 import com.android.launcher3.logging.EventLogArray;
76 import com.android.launcher3.logging.UserEventDispatcher;
77 import com.android.launcher3.util.LooperExecutor;
78 import com.android.launcher3.util.UiThreadHelper;
79 import com.android.quickstep.SysUINavigationMode.Mode;
80 import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
81 import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
82 import com.android.quickstep.inputconsumers.AssistantTouchConsumer;
83 import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
84 import com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer;
85 import com.android.quickstep.inputconsumers.InputConsumer;
86 import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
87 import com.android.quickstep.inputconsumers.OverviewInputConsumer;
88 import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
89 import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
90 import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
91 import com.android.systemui.shared.recents.IOverviewProxy;
92 import com.android.systemui.shared.recents.ISystemUiProxy;
93 import com.android.systemui.shared.system.ActivityManagerWrapper;
94 import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
95 import com.android.systemui.shared.system.InputConsumerController;
96 import com.android.systemui.shared.system.InputMonitorCompat;
97 import com.android.systemui.shared.system.QuickStepContract;
98 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
99 import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat;
100 
101 import java.io.FileDescriptor;
102 import java.io.PrintWriter;
103 import java.util.Arrays;
104 import java.util.LinkedList;
105 import java.util.List;
106 
107 /**
108  * Wrapper around a list for processing arguments.
109  */
110 class ArgList extends LinkedList<String> {
ArgList(List<String> l)111     public ArgList(List<String> l) {
112         super(l);
113     }
114 
peekArg()115     public String peekArg() {
116         return peekFirst();
117     }
118 
nextArg()119     public String nextArg() {
120         return pollFirst().toLowerCase();
121     }
122 
nextArgExact()123     public String nextArgExact() {
124         return pollFirst();
125     }
126 }
127 
128 /**
129  * Service connected by system-UI for handling touch interaction.
130  */
131 @TargetApi(Build.VERSION_CODES.Q)
132 public class TouchInteractionService extends Service implements
133         NavigationModeChangeListener, DisplayListener {
134 
135     public static final MainThreadExecutor MAIN_THREAD_EXECUTOR = new MainThreadExecutor();
136     public static final LooperExecutor BACKGROUND_EXECUTOR =
137             new LooperExecutor(UiThreadHelper.getBackgroundLooper());
138 
139     public static final EventLogArray TOUCH_INTERACTION_LOG =
140             new EventLogArray("touch_interaction_log", 40);
141 
142     private static final String TAG = "TouchInteractionService";
143 
144     private final IBinder mMyBinder = new IOverviewProxy.Stub() {
145 
146         public void onActiveNavBarRegionChanges(Region region) {
147             mActiveNavBarRegion = region;
148         }
149 
150         public void onInitialize(Bundle bundle) {
151             mISystemUiProxy = ISystemUiProxy.Stub
152                     .asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
153             MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::initInputMonitor);
154             MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::onSystemUiProxySet);
155         }
156 
157         @Override
158         public void onOverviewToggle() {
159             mOverviewCommandHelper.onOverviewToggle();
160         }
161 
162         @Override
163         public void onOverviewShown(boolean triggeredFromAltTab) {
164             mOverviewCommandHelper.onOverviewShown(triggeredFromAltTab);
165         }
166 
167         @Override
168         public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
169             if (triggeredFromAltTab && !triggeredFromHomeKey) {
170                 // onOverviewShownFromAltTab hides the overview and ends at the target app
171                 mOverviewCommandHelper.onOverviewHidden();
172             }
173         }
174 
175         @Override
176         public void onTip(int actionType, int viewType) {
177             mOverviewCommandHelper.onTip(actionType, viewType);
178         }
179 
180         @Override
181         public void onAssistantAvailable(boolean available) {
182             mAssistantAvailable = available;
183         }
184 
185         @Override
186         public void onAssistantVisibilityChanged(float visibility) {
187             mLastAssistantVisibility = visibility;
188             MAIN_THREAD_EXECUTOR.execute(
189                     TouchInteractionService.this::onAssistantVisibilityChanged);
190         }
191 
192         public void onBackAction(boolean completed, int downX, int downY, boolean isButton,
193                 boolean gestureSwipeLeft) {
194             if (mOverviewComponentObserver == null) {
195                 return;
196             }
197 
198             final ActivityControlHelper activityControl =
199                     mOverviewComponentObserver.getActivityControlHelper();
200             UserEventDispatcher.newInstance(getBaseContext()).logActionBack(completed, downX, downY,
201                     isButton, gestureSwipeLeft, activityControl.getContainerType());
202         }
203 
204         public void onSystemUiStateChanged(int stateFlags) {
205             mSystemUiStateFlags = stateFlags;
206             MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::onSystemUiFlagsChanged);
207         }
208 
209         /** Deprecated methods **/
210         public void onQuickStep(MotionEvent motionEvent) { }
211 
212         public void onQuickScrubEnd() { }
213 
214         public void onQuickScrubProgress(float progress) { }
215 
216         public void onQuickScrubStart() { }
217 
218         public void onPreMotionEvent(int downHitTarget) { }
219 
220         public void onMotionEvent(MotionEvent ev) {
221             ev.recycle();
222         }
223 
224         public void onBind(ISystemUiProxy iSystemUiProxy) { }
225     };
226 
227     private static boolean sConnected = false;
228     private static final SwipeSharedState sSwipeSharedState = new SwipeSharedState();
229 
isConnected()230     public static boolean isConnected() {
231         return sConnected;
232     }
233 
getSwipeSharedState()234     public static SwipeSharedState getSwipeSharedState() {
235         return sSwipeSharedState;
236     }
237 
238     private final InputConsumer mResetGestureInputConsumer =
239             new ResetGestureInputConsumer(sSwipeSharedState);
240 
241     private ActivityManagerWrapper mAM;
242     private RecentsModel mRecentsModel;
243     private ISystemUiProxy mISystemUiProxy;
244     private OverviewCommandHelper mOverviewCommandHelper;
245     private OverviewComponentObserver mOverviewComponentObserver;
246     private OverviewInteractionState mOverviewInteractionState;
247     private OverviewCallbacks mOverviewCallbacks;
248     private TaskOverlayFactory mTaskOverlayFactory;
249     private InputConsumerController mInputConsumer;
250     private boolean mAssistantAvailable;
251     private float mLastAssistantVisibility = 0;
252     private @SystemUiStateFlags int mSystemUiStateFlags;
253 
254     private boolean mIsUserUnlocked;
255     private BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() {
256         @Override
257         public void onReceive(Context context, Intent intent) {
258             if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
259                 initWhenUserUnlocked();
260             }
261         }
262     };
263 
264     private InputConsumer mUncheckedConsumer = InputConsumer.NO_OP;
265     private InputConsumer mConsumer = InputConsumer.NO_OP;
266     private Choreographer mMainChoreographer;
267 
268     private Region mActiveNavBarRegion = new Region();
269 
270     private InputMonitorCompat mInputMonitorCompat;
271     private InputEventReceiver mInputEventReceiver;
272     private Mode mMode = Mode.THREE_BUTTONS;
273     private int mDefaultDisplayId;
274     private final RectF mSwipeTouchRegion = new RectF();
275     private final RectF mAssistantLeftRegion = new RectF();
276     private final RectF mAssistantRightRegion = new RectF();
277 
278     private ComponentName mGestureBlockingActivity;
279 
280     private Region mExclusionRegion;
281     private SystemGestureExclusionListenerCompat mExclusionListener;
282 
283     @Override
onCreate()284     public void onCreate() {
285         super.onCreate();
286 
287         // Initialize anything here that is needed in direct boot mode.
288         // Everything else should be initialized in initWhenUserUnlocked() below.
289         mMainChoreographer = Choreographer.getInstance();
290         mAM = ActivityManagerWrapper.getInstance();
291 
292         if (UserManagerCompat.getInstance(this).isUserUnlocked(Process.myUserHandle())) {
293             initWhenUserUnlocked();
294         } else {
295             mIsUserUnlocked = false;
296             registerReceiver(mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
297         }
298 
299         mDefaultDisplayId = getSystemService(WindowManager.class).getDefaultDisplay()
300                 .getDisplayId();
301         String blockingActivity = getString(R.string.gesture_blocking_activity);
302         mGestureBlockingActivity = TextUtils.isEmpty(blockingActivity) ? null :
303                 ComponentName.unflattenFromString(blockingActivity);
304 
305         mExclusionListener = new SystemGestureExclusionListenerCompat(mDefaultDisplayId) {
306             @Override
307             @BinderThread
308             public void onExclusionChanged(Region region) {
309                 // Assignments are atomic, it should be safe on binder thread
310                 mExclusionRegion = region;
311             }
312         };
313 
314         onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this));
315         sConnected = true;
316     }
317 
disposeEventHandlers()318     private void disposeEventHandlers() {
319         if (mInputEventReceiver != null) {
320             mInputEventReceiver.dispose();
321             mInputEventReceiver = null;
322         }
323         if (mInputMonitorCompat != null) {
324             mInputMonitorCompat.dispose();
325             mInputMonitorCompat = null;
326         }
327     }
328 
initInputMonitor()329     private void initInputMonitor() {
330         if (!mMode.hasGestures || mISystemUiProxy == null) {
331             return;
332         }
333         disposeEventHandlers();
334 
335         try {
336             mInputMonitorCompat = InputMonitorCompat.fromBundle(mISystemUiProxy
337                     .monitorGestureInput("swipe-up", mDefaultDisplayId), KEY_EXTRA_INPUT_MONITOR);
338             mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
339                     mMainChoreographer, this::onInputEvent);
340         } catch (RemoteException e) {
341             Log.e(TAG, "Unable to create input monitor", e);
342         }
343         initTouchBounds();
344     }
345 
getNavbarSize(String resName)346     private int getNavbarSize(String resName) {
347         return ResourceUtils.getNavbarSize(resName, getResources());
348     }
349 
initTouchBounds()350     private void initTouchBounds() {
351         if (!mMode.hasGestures) {
352             return;
353         }
354 
355         Display defaultDisplay = getSystemService(WindowManager.class).getDefaultDisplay();
356         Point realSize = new Point();
357         defaultDisplay.getRealSize(realSize);
358         mSwipeTouchRegion.set(0, 0, realSize.x, realSize.y);
359         if (mMode == Mode.NO_BUTTON) {
360             int touchHeight = getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
361             mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - touchHeight;
362 
363             final int assistantWidth = getResources()
364                     .getDimensionPixelSize(R.dimen.gestures_assistant_width);
365             final float assistantHeight = Math.max(touchHeight,
366                     QuickStepContract.getWindowCornerRadius(getResources()));
367             mAssistantLeftRegion.bottom = mAssistantRightRegion.bottom = mSwipeTouchRegion.bottom;
368             mAssistantLeftRegion.top = mAssistantRightRegion.top =
369                     mSwipeTouchRegion.bottom - assistantHeight;
370 
371             mAssistantLeftRegion.left = 0;
372             mAssistantLeftRegion.right = assistantWidth;
373 
374             mAssistantRightRegion.right = mSwipeTouchRegion.right;
375             mAssistantRightRegion.left = mSwipeTouchRegion.right - assistantWidth;
376         } else {
377             mAssistantLeftRegion.setEmpty();
378             mAssistantRightRegion.setEmpty();
379             switch (defaultDisplay.getRotation()) {
380                 case Surface.ROTATION_90:
381                     mSwipeTouchRegion.left = mSwipeTouchRegion.right
382                             - getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
383                     break;
384                 case Surface.ROTATION_270:
385                     mSwipeTouchRegion.right = mSwipeTouchRegion.left
386                             + getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
387                     break;
388                 default:
389                     mSwipeTouchRegion.top = mSwipeTouchRegion.bottom
390                             - getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
391             }
392         }
393     }
394 
395     @Override
onNavigationModeChanged(Mode newMode)396     public void onNavigationModeChanged(Mode newMode) {
397         if (mMode.hasGestures != newMode.hasGestures) {
398             if (newMode.hasGestures) {
399                 getSystemService(DisplayManager.class).registerDisplayListener(
400                         this, MAIN_THREAD_EXECUTOR.getHandler());
401             } else {
402                 getSystemService(DisplayManager.class).unregisterDisplayListener(this);
403             }
404         }
405         mMode = newMode;
406 
407         disposeEventHandlers();
408         initInputMonitor();
409 
410         if (mMode == Mode.NO_BUTTON) {
411             mExclusionListener.register();
412         } else {
413             mExclusionListener.unregister();
414         }
415     }
416 
417     @Override
onDisplayAdded(int i)418     public void onDisplayAdded(int i) { }
419 
420     @Override
onDisplayRemoved(int i)421     public void onDisplayRemoved(int i) { }
422 
423     @Override
onDisplayChanged(int displayId)424     public void onDisplayChanged(int displayId) {
425         if (displayId != mDefaultDisplayId) {
426             return;
427         }
428 
429         initTouchBounds();
430     }
431 
initWhenUserUnlocked()432     private void initWhenUserUnlocked() {
433         mRecentsModel = RecentsModel.INSTANCE.get(this);
434         mOverviewComponentObserver = new OverviewComponentObserver(this);
435 
436         mOverviewCommandHelper = new OverviewCommandHelper(this, mOverviewComponentObserver);
437         mOverviewInteractionState = OverviewInteractionState.INSTANCE.get(this);
438         mOverviewCallbacks = OverviewCallbacks.get(this);
439         mTaskOverlayFactory = TaskOverlayFactory.INSTANCE.get(this);
440         mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
441         mIsUserUnlocked = true;
442 
443         sSwipeSharedState.setOverviewComponentObserver(mOverviewComponentObserver);
444         mInputConsumer.registerInputConsumer();
445         onSystemUiProxySet();
446         onSystemUiFlagsChanged();
447         onAssistantVisibilityChanged();
448 
449         // Temporarily disable model preload
450         // new ModelPreload().start(this);
451 
452         Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver);
453     }
454 
455     @UiThread
onSystemUiProxySet()456     private void onSystemUiProxySet() {
457         if (mIsUserUnlocked) {
458             mRecentsModel.setSystemUiProxy(mISystemUiProxy);
459             mOverviewInteractionState.setSystemUiProxy(mISystemUiProxy);
460         }
461     }
462 
463     @UiThread
onSystemUiFlagsChanged()464     private void onSystemUiFlagsChanged() {
465         if (mIsUserUnlocked) {
466             mOverviewInteractionState.setSystemUiStateFlags(mSystemUiStateFlags);
467             mOverviewComponentObserver.onSystemUiStateChanged(mSystemUiStateFlags);
468         }
469     }
470 
471     @UiThread
onAssistantVisibilityChanged()472     private void onAssistantVisibilityChanged() {
473         if (mIsUserUnlocked) {
474             mOverviewComponentObserver.getActivityControlHelper().onAssistantVisibilityChanged(
475                     mLastAssistantVisibility);
476         }
477     }
478 
479     @Override
onDestroy()480     public void onDestroy() {
481         if (mIsUserUnlocked) {
482             mInputConsumer.unregisterInputConsumer();
483             mOverviewComponentObserver.onDestroy();
484         }
485         disposeEventHandlers();
486         if (mMode.hasGestures) {
487             getSystemService(DisplayManager.class).unregisterDisplayListener(this);
488         }
489 
490         sConnected = false;
491         Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver);
492         SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this);
493         mExclusionListener.unregister();
494 
495         super.onDestroy();
496     }
497 
498     @Override
onBind(Intent intent)499     public IBinder onBind(Intent intent) {
500         Log.d(TAG, "Touch service connected");
501         return mMyBinder;
502     }
503 
onInputEvent(InputEvent ev)504     private void onInputEvent(InputEvent ev) {
505         if (!(ev instanceof MotionEvent)) {
506             Log.e(TAG, "Unknown event " + ev);
507             return;
508         }
509         MotionEvent event = (MotionEvent) ev;
510         TOUCH_INTERACTION_LOG.addLog("onMotionEvent", event.getActionMasked());
511         if (event.getAction() == ACTION_DOWN) {
512             if (mSwipeTouchRegion.contains(event.getX(), event.getY())) {
513                 boolean useSharedState = mConsumer.useSharedSwipeState();
514                 mConsumer.onConsumerAboutToBeSwitched();
515                 mConsumer = newConsumer(useSharedState, event);
516                 TOUCH_INTERACTION_LOG.addLog("setInputConsumer", mConsumer.getType());
517                 mUncheckedConsumer = mConsumer;
518             } else if (mIsUserUnlocked && mMode == Mode.NO_BUTTON
519                     && canTriggerAssistantAction(event)) {
520                 // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we should
521                 // not interrupt it. QuickSwitch assumes that interruption can only happen if the
522                 // next gesture is also quick switch.
523                 mUncheckedConsumer =
524                         new AssistantTouchConsumer(this, mISystemUiProxy,
525                                 mOverviewComponentObserver.getActivityControlHelper(),
526                                 InputConsumer.NO_OP, mInputMonitorCompat);
527             } else {
528                 mUncheckedConsumer = InputConsumer.NO_OP;
529             }
530         }
531         mUncheckedConsumer.onMotionEvent(event);
532     }
533 
validSystemUiFlags()534     private boolean validSystemUiFlags() {
535         return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
536                 && (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0
537                 && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
538                         || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0);
539     }
540 
canTriggerAssistantAction(MotionEvent ev)541     private boolean canTriggerAssistantAction(MotionEvent ev) {
542         return mAssistantAvailable
543                 && !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
544                 && (mAssistantLeftRegion.contains(ev.getX(), ev.getY()) ||
545                     mAssistantRightRegion.contains(ev.getX(), ev.getY()))
546                 && !ActivityManagerWrapper.getInstance().isLockToAppActive();
547     }
548 
newConsumer(boolean useSharedState, MotionEvent event)549     private InputConsumer newConsumer(boolean useSharedState, MotionEvent event) {
550         boolean isInValidSystemUiState = validSystemUiFlags();
551 
552         if (!mIsUserUnlocked) {
553             if (isInValidSystemUiState) {
554                 // This handles apps launched in direct boot mode (e.g. dialer) as well as apps
555                 // launched while device is locked even after exiting direct boot mode (e.g. camera).
556                 return createDeviceLockedInputConsumer(mAM.getRunningTask(0));
557             } else {
558                 return mResetGestureInputConsumer;
559             }
560         }
561 
562         // When using sharedState, bypass systemState check as this is a followup gesture and the
563         // first gesture started in a valid system state.
564         InputConsumer base = isInValidSystemUiState || useSharedState
565                 ? newBaseConsumer(useSharedState, event) : mResetGestureInputConsumer;
566         if (mMode == Mode.NO_BUTTON) {
567             final ActivityControlHelper activityControl =
568                     mOverviewComponentObserver.getActivityControlHelper();
569             if (canTriggerAssistantAction(event)) {
570                 base = new AssistantTouchConsumer(this, mISystemUiProxy, activityControl, base,
571                         mInputMonitorCompat);
572             }
573 
574             if ((mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0) {
575                 // Note: we only allow accessibility to wrap this, and it replaces the previous
576                 // base input consumer (which should be NO_OP anyway since topTaskLocked == true).
577                 base = new ScreenPinnedInputConsumer(this, mISystemUiProxy, activityControl);
578             }
579 
580             if ((mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0) {
581                 base = new AccessibilityInputConsumer(this, mISystemUiProxy,
582                         (mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0, base,
583                         mInputMonitorCompat, mSwipeTouchRegion);
584             }
585         } else {
586             if ((mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0) {
587                 base = mResetGestureInputConsumer;
588             }
589         }
590         return base;
591     }
592 
newBaseConsumer(boolean useSharedState, MotionEvent event)593     private InputConsumer newBaseConsumer(boolean useSharedState, MotionEvent event) {
594         final RunningTaskInfo runningTaskInfo = mAM.getRunningTask(0);
595         if (!useSharedState) {
596             sSwipeSharedState.clearAllState(false /* finishAnimation */);
597         }
598         if ((mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0) {
599             // This handles apps showing over the lockscreen (e.g. camera)
600             return createDeviceLockedInputConsumer(runningTaskInfo);
601         }
602 
603         final ActivityControlHelper activityControl =
604                 mOverviewComponentObserver.getActivityControlHelper();
605 
606         if (runningTaskInfo == null && !sSwipeSharedState.goingToLauncher
607                 && !sSwipeSharedState.recentsAnimationFinishInterrupted) {
608             return mResetGestureInputConsumer;
609         } else if (sSwipeSharedState.recentsAnimationFinishInterrupted) {
610             // If the finish animation was interrupted, then continue using the other activity input
611             // consumer but with the next task as the running task
612             RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
613             info.id = sSwipeSharedState.nextRunningTaskId;
614             return createOtherActivityInputConsumer(event, info);
615         } else if (sSwipeSharedState.goingToLauncher || activityControl.isResumed()) {
616             return createOverviewInputConsumer(event);
617         } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityControl.isInLiveTileMode()) {
618             return createOverviewInputConsumer(event);
619         } else if (mGestureBlockingActivity != null && runningTaskInfo != null
620                 && mGestureBlockingActivity.equals(runningTaskInfo.topActivity)) {
621             return mResetGestureInputConsumer;
622         } else if (mMode == Mode.NO_BUTTON && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
623             return new FallbackNoButtonInputConsumer(this, activityControl,
624                     mInputMonitorCompat, sSwipeSharedState, mSwipeTouchRegion,
625                     mOverviewComponentObserver, disableHorizontalSwipe(event), runningTaskInfo);
626         } else {
627             return createOtherActivityInputConsumer(event, runningTaskInfo);
628         }
629     }
630 
disableHorizontalSwipe(MotionEvent event)631     private boolean disableHorizontalSwipe(MotionEvent event) {
632         // mExclusionRegion can change on binder thread, use a local instance here.
633         Region exclusionRegion = mExclusionRegion;
634         return mMode == Mode.NO_BUTTON && exclusionRegion != null
635                 && exclusionRegion.contains((int) event.getX(), (int) event.getY());
636     }
637 
createOtherActivityInputConsumer(MotionEvent event, RunningTaskInfo runningTaskInfo)638     private OtherActivityInputConsumer createOtherActivityInputConsumer(MotionEvent event,
639             RunningTaskInfo runningTaskInfo) {
640         final ActivityControlHelper activityControl =
641                 mOverviewComponentObserver.getActivityControlHelper();
642         boolean shouldDefer = activityControl.deferStartingActivity(mActiveNavBarRegion, event);
643 
644         return new OtherActivityInputConsumer(this, runningTaskInfo, mRecentsModel,
645                 mOverviewComponentObserver.getOverviewIntent(), activityControl,
646                 shouldDefer, mOverviewCallbacks, mInputConsumer, this::onConsumerInactive,
647                 sSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion,
648                 disableHorizontalSwipe(event));
649     }
650 
createDeviceLockedInputConsumer(RunningTaskInfo taskInfo)651     private InputConsumer createDeviceLockedInputConsumer(RunningTaskInfo taskInfo) {
652         if (mMode == Mode.NO_BUTTON && taskInfo != null) {
653             return new DeviceLockedInputConsumer(this, sSwipeSharedState, mInputMonitorCompat,
654                     mSwipeTouchRegion, taskInfo.taskId);
655         } else {
656             return mResetGestureInputConsumer;
657         }
658     }
659 
createOverviewInputConsumer(MotionEvent event)660     public InputConsumer createOverviewInputConsumer(MotionEvent event) {
661         final ActivityControlHelper activityControl =
662                 mOverviewComponentObserver.getActivityControlHelper();
663         BaseDraggingActivity activity = activityControl.getCreatedActivity();
664         if (activity == null) {
665             return mResetGestureInputConsumer;
666         }
667 
668         if (activity.getRootView().hasWindowFocus() || sSwipeSharedState.goingToLauncher) {
669             return new OverviewInputConsumer(activity, mInputMonitorCompat,
670                     false /* startingInActivityBounds */);
671         } else {
672             return new OverviewWithoutFocusInputConsumer(this, mInputMonitorCompat,
673                     disableHorizontalSwipe(event));
674         }
675     }
676 
677     /**
678      * To be called by the consumer when it's no longer active.
679      */
onConsumerInactive(InputConsumer caller)680     private void onConsumerInactive(InputConsumer caller) {
681         if (mConsumer == caller) {
682             mConsumer = mResetGestureInputConsumer;
683             mUncheckedConsumer = mConsumer;
684         }
685     }
686 
687     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs)688     protected void dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs) {
689         if (rawArgs.length > 0 && Utilities.IS_DEBUG_DEVICE) {
690             ArgList args = new ArgList(Arrays.asList(rawArgs));
691             switch (args.nextArg()) {
692                 case "cmd":
693                     if (args.peekArg() == null) {
694                         printAvailableCommands(pw);
695                     } else {
696                         onCommand(pw, args);
697                     }
698                     break;
699             }
700         } else {
701             // Dump everything
702             pw.println("TouchState:");
703             pw.println("  navMode=" + mMode);
704             pw.println("  validSystemUiFlags=" + validSystemUiFlags());
705             pw.println("  systemUiFlags=" + mSystemUiStateFlags);
706             pw.println("  systemUiFlagsDesc="
707                     + QuickStepContract.getSystemUiStateString(mSystemUiStateFlags));
708             pw.println("  assistantAvailable=" + mAssistantAvailable);
709             pw.println("  assistantDisabled="
710                     + QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags));
711             pw.println("  resumed="
712                     + mOverviewComponentObserver.getActivityControlHelper().isResumed());
713             pw.println("  useSharedState=" + mConsumer.useSharedSwipeState());
714             if (mConsumer.useSharedSwipeState()) {
715                 sSwipeSharedState.dump("    ", pw);
716             }
717             pw.println("  mConsumer=" + mConsumer.getName());
718             pw.println("FeatureFlags:");
719             pw.println("  APPLY_CONFIG_AT_RUNTIME=" + APPLY_CONFIG_AT_RUNTIME.get());
720             pw.println("  QUICKSTEP_SPRINGS=" + QUICKSTEP_SPRINGS.get());
721             pw.println("  ADAPTIVE_ICON_WINDOW_ANIM=" + ADAPTIVE_ICON_WINDOW_ANIM.get());
722             pw.println("  ENABLE_QUICKSTEP_LIVE_TILE=" + ENABLE_QUICKSTEP_LIVE_TILE.get());
723             pw.println("  ENABLE_HINTS_IN_OVERVIEW=" + ENABLE_HINTS_IN_OVERVIEW.get());
724             pw.println("  FAKE_LANDSCAPE_UI=" + FAKE_LANDSCAPE_UI.get());
725             TOUCH_INTERACTION_LOG.dump("", pw);
726 
727         }
728     }
729 
printAvailableCommands(PrintWriter pw)730     private void printAvailableCommands(PrintWriter pw) {
731         pw.println("Available commands:");
732         pw.println("  clear-touch-log: Clears the touch interaction log");
733     }
734 
onCommand(PrintWriter pw, ArgList args)735     private void onCommand(PrintWriter pw, ArgList args) {
736         switch (args.nextArg()) {
737             case "clear-touch-log":
738                 TOUCH_INTERACTION_LOG.clear();
739                 break;
740         }
741     }
742 }
743