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.content.Intent.ACTION_CHOOSER;
19 import static android.view.MotionEvent.ACTION_CANCEL;
20 import static android.view.MotionEvent.ACTION_DOWN;
21 import static android.view.MotionEvent.ACTION_UP;
22 
23 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
24 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
25 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
26 import static com.android.quickstep.GestureState.DEFAULT_STATE;
27 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
28 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
29 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
30 
31 import android.annotation.TargetApi;
32 import android.app.ActivityManager;
33 import android.app.PendingIntent;
34 import android.app.RemoteAction;
35 import android.app.Service;
36 import android.content.ComponentName;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.SharedPreferences;
40 import android.content.res.Configuration;
41 import android.graphics.Rect;
42 import android.graphics.Region;
43 import android.graphics.drawable.Icon;
44 import android.os.Build;
45 import android.os.Bundle;
46 import android.os.IBinder;
47 import android.os.Looper;
48 import android.util.Log;
49 import android.view.Choreographer;
50 import android.view.InputEvent;
51 import android.view.MotionEvent;
52 import android.view.accessibility.AccessibilityManager;
53 
54 import androidx.annotation.BinderThread;
55 import androidx.annotation.Nullable;
56 import androidx.annotation.UiThread;
57 import androidx.annotation.WorkerThread;
58 
59 import com.android.launcher3.BaseDraggingActivity;
60 import com.android.launcher3.R;
61 import com.android.launcher3.Utilities;
62 import com.android.launcher3.config.FeatureFlags;
63 import com.android.launcher3.logging.UserEventDispatcher;
64 import com.android.launcher3.model.AppLaunchTracker;
65 import com.android.launcher3.provider.RestoreDbTask;
66 import com.android.launcher3.statemanager.StatefulActivity;
67 import com.android.launcher3.testing.TestLogging;
68 import com.android.launcher3.testing.TestProtocol;
69 import com.android.launcher3.tracing.nano.LauncherTraceProto;
70 import com.android.launcher3.tracing.nano.TouchInteractionServiceProto;
71 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
72 import com.android.launcher3.util.OnboardingPrefs;
73 import com.android.launcher3.util.TraceHelper;
74 import com.android.launcher3.util.WindowBounds;
75 import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
76 import com.android.quickstep.inputconsumers.AssistantInputConsumer;
77 import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
78 import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
79 import com.android.quickstep.inputconsumers.OverscrollInputConsumer;
80 import com.android.quickstep.inputconsumers.OverviewInputConsumer;
81 import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
82 import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
83 import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
84 import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer;
85 import com.android.quickstep.util.ActiveGestureLog;
86 import com.android.quickstep.util.AssistantUtilities;
87 import com.android.quickstep.util.ProtoTracer;
88 import com.android.quickstep.util.SplitScreenBounds;
89 import com.android.systemui.plugins.OverscrollPlugin;
90 import com.android.systemui.plugins.PluginListener;
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.tracing.ProtoTraceable;
98 
99 import java.io.FileDescriptor;
100 import java.io.PrintWriter;
101 import java.util.Arrays;
102 import java.util.LinkedList;
103 import java.util.List;
104 
105 /**
106  * Wrapper around a list for processing arguments.
107  */
108 class ArgList extends LinkedList<String> {
ArgList(List<String> l)109     public ArgList(List<String> l) {
110         super(l);
111     }
112 
peekArg()113     public String peekArg() {
114         return peekFirst();
115     }
116 
nextArg()117     public String nextArg() {
118         return pollFirst().toLowerCase();
119     }
120 }
121 
122 /**
123  * Service connected by system-UI for handling touch interaction.
124  */
125 @TargetApi(Build.VERSION_CODES.R)
126 public class TouchInteractionService extends Service implements PluginListener<OverscrollPlugin>,
127         ProtoTraceable<LauncherTraceProto> {
128 
129     private static final String TAG = "TouchInteractionService";
130 
131     private static final String KEY_BACK_NOTIFICATION_COUNT = "backNotificationCount";
132     private static final String NOTIFY_ACTION_BACK = "com.android.quickstep.action.BACK_GESTURE";
133     private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once";
134     private static final int MAX_BACK_NOTIFICATION_COUNT = 3;
135 
136     /**
137      * System Action ID to show all apps.
138      * TODO: Use AccessibilityService's corresponding global action constant in S
139      */
140     private static final int SYSTEM_ACTION_ID_ALL_APPS = 14;
141 
142     private int mBackGestureNotificationCounter = -1;
143     @Nullable
144     private OverscrollPlugin mOverscrollPlugin;
145 
146     private final IBinder mMyBinder = new IOverviewProxy.Stub() {
147 
148         @BinderThread
149         public void onInitialize(Bundle bundle) {
150             ISystemUiProxy proxy = ISystemUiProxy.Stub.asInterface(
151                     bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
152             MAIN_EXECUTOR.execute(() -> {
153                 SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy);
154                 TouchInteractionService.this.initInputMonitor();
155                 preloadOverview(true /* fromInit */);
156             });
157             sIsInitialized = true;
158         }
159 
160         @BinderThread
161         @Override
162         public void onOverviewToggle() {
163             TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle");
164             mOverviewCommandHelper.onOverviewToggle();
165         }
166 
167         @BinderThread
168         @Override
169         public void onOverviewShown(boolean triggeredFromAltTab) {
170             mOverviewCommandHelper.onOverviewShown(triggeredFromAltTab);
171         }
172 
173         @BinderThread
174         @Override
175         public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
176             if (triggeredFromAltTab && !triggeredFromHomeKey) {
177                 // onOverviewShownFromAltTab hides the overview and ends at the target app
178                 mOverviewCommandHelper.onOverviewHidden();
179             }
180         }
181 
182         @BinderThread
183         @Override
184         public void onTip(int actionType, int viewType) {
185             mOverviewCommandHelper.onTip(actionType, viewType);
186         }
187 
188         @BinderThread
189         @Override
190         public void onAssistantAvailable(boolean available) {
191             MAIN_EXECUTOR.execute(() -> {
192                 mDeviceState.setAssistantAvailable(available);
193                 TouchInteractionService.this.onAssistantVisibilityChanged();
194             });
195         }
196 
197         @BinderThread
198         @Override
199         public void onAssistantVisibilityChanged(float visibility) {
200             MAIN_EXECUTOR.execute(() -> {
201                 mDeviceState.setAssistantVisibility(visibility);
202                 TouchInteractionService.this.onAssistantVisibilityChanged();
203             });
204         }
205 
206         @BinderThread
207         public void onBackAction(boolean completed, int downX, int downY, boolean isButton,
208                 boolean gestureSwipeLeft) {
209             if (mOverviewComponentObserver == null) {
210                 return;
211             }
212 
213             final BaseActivityInterface activityInterface =
214                     mOverviewComponentObserver.getActivityInterface();
215             UserEventDispatcher.newInstance(getBaseContext()).logActionBack(completed, downX, downY,
216                     isButton, gestureSwipeLeft, activityInterface.getContainerType());
217 
218             if (completed && !isButton && shouldNotifyBackGesture()) {
219                 UI_HELPER_EXECUTOR.execute(TouchInteractionService.this::tryNotifyBackGesture);
220             }
221         }
222 
223         @BinderThread
224         public void onSystemUiStateChanged(int stateFlags) {
225             MAIN_EXECUTOR.execute(() -> {
226                 mDeviceState.setSystemUiFlags(stateFlags);
227                 TouchInteractionService.this.onSystemUiFlagsChanged();
228             });
229         }
230 
231         @BinderThread
232         public void onActiveNavBarRegionChanges(Region region) {
233             MAIN_EXECUTOR.execute(() -> mDeviceState.setDeferredGestureRegion(region));
234         }
235 
236         public void onSplitScreenSecondaryBoundsChanged(Rect bounds, Rect insets)  {
237             WindowBounds wb = new WindowBounds(bounds, insets);
238             MAIN_EXECUTOR.execute(() -> SplitScreenBounds.INSTANCE.setSecondaryWindowBounds(wb));
239         }
240 
241         /** Deprecated methods **/
242         public void onQuickStep(MotionEvent motionEvent) { }
243 
244         public void onQuickScrubEnd() { }
245 
246         public void onQuickScrubProgress(float progress) { }
247 
248         public void onQuickScrubStart() { }
249 
250         public void onPreMotionEvent(int downHitTarget) { }
251 
252         public void onMotionEvent(MotionEvent ev) {
253             ev.recycle();
254         }
255 
256         public void onBind(ISystemUiProxy iSystemUiProxy) { }
257     };
258 
259     private static boolean sConnected = false;
260     private static boolean sIsInitialized = false;
261 
isConnected()262     public static boolean isConnected() {
263         return sConnected;
264     }
265 
isInitialized()266     public static boolean isInitialized() {
267         return sIsInitialized;
268     }
269 
270     private final BaseSwipeUpHandler.Factory mLauncherSwipeHandlerFactory =
271             this::createLauncherSwipeHandler;
272     private final BaseSwipeUpHandler.Factory mFallbackSwipeHandlerFactory =
273             this::createFallbackSwipeHandler;
274 
275     private ActivityManagerWrapper mAM;
276     private OverviewCommandHelper mOverviewCommandHelper;
277     private OverviewComponentObserver mOverviewComponentObserver;
278     private InputConsumerController mInputConsumer;
279     private RecentsAnimationDeviceState mDeviceState;
280     private TaskAnimationManager mTaskAnimationManager;
281 
282     private InputConsumer mUncheckedConsumer = InputConsumer.NO_OP;
283     private InputConsumer mConsumer = InputConsumer.NO_OP;
284     private Choreographer mMainChoreographer;
285     private InputConsumer mResetGestureInputConsumer;
286     private GestureState mGestureState = DEFAULT_STATE;
287 
288     private InputMonitorCompat mInputMonitorCompat;
289     private InputEventReceiver mInputEventReceiver;
290 
291     @Override
onCreate()292     public void onCreate() {
293         super.onCreate();
294         // Initialize anything here that is needed in direct boot mode.
295         // Everything else should be initialized in onUserUnlocked() below.
296         mMainChoreographer = Choreographer.getInstance();
297         mAM = ActivityManagerWrapper.getInstance();
298         mDeviceState = new RecentsAnimationDeviceState(this);
299         mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
300         mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
301         ProtoTracer.INSTANCE.get(this).add(this);
302 
303         sConnected = true;
304     }
305 
disposeEventHandlers()306     private void disposeEventHandlers() {
307         if (mInputEventReceiver != null) {
308             mInputEventReceiver.dispose();
309             mInputEventReceiver = null;
310         }
311         if (mInputMonitorCompat != null) {
312             mInputMonitorCompat.dispose();
313             mInputMonitorCompat = null;
314         }
315     }
316 
initInputMonitor()317     private void initInputMonitor() {
318         disposeEventHandlers();
319         if (mDeviceState.isButtonNavMode() || !SystemUiProxy.INSTANCE.get(this).isActive()) {
320             return;
321         }
322 
323         Bundle bundle = SystemUiProxy.INSTANCE.get(this).monitorGestureInput("swipe-up",
324                 mDeviceState.getDisplayId());
325         mInputMonitorCompat = InputMonitorCompat.fromBundle(bundle, KEY_EXTRA_INPUT_MONITOR);
326         mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
327                 mMainChoreographer, this::onInputEvent);
328 
329         mDeviceState.updateGestureTouchRegions();
330     }
331 
332     /**
333      * Called when the navigation mode changes, guaranteed to be after the device state has updated.
334      */
onNavigationModeChanged(SysUINavigationMode.Mode mode)335     private void onNavigationModeChanged(SysUINavigationMode.Mode mode) {
336         initInputMonitor();
337         resetHomeBounceSeenOnQuickstepEnabledFirstTime();
338     }
339 
340     @UiThread
onUserUnlocked()341     public void onUserUnlocked() {
342         mTaskAnimationManager = new TaskAnimationManager();
343         mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
344         mOverviewCommandHelper = new OverviewCommandHelper(this, mDeviceState,
345                 mOverviewComponentObserver);
346         mResetGestureInputConsumer = new ResetGestureInputConsumer(mTaskAnimationManager);
347         mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
348         mInputConsumer.registerInputConsumer();
349         onSystemUiFlagsChanged();
350         onAssistantVisibilityChanged();
351 
352         // Temporarily disable model preload
353         // new ModelPreload().start(this);
354         mBackGestureNotificationCounter = Math.max(0, Utilities.getDevicePrefs(this)
355                 .getInt(KEY_BACK_NOTIFICATION_COUNT, MAX_BACK_NOTIFICATION_COUNT));
356         resetHomeBounceSeenOnQuickstepEnabledFirstTime();
357 
358         PluginManagerWrapper.INSTANCE.get(getBaseContext()).addPluginListener(this,
359                 OverscrollPlugin.class, false /* allowMultiple */);
360 
361         mOverviewComponentObserver.setOverviewChangeListener(this::onOverviewTargetChange);
362         onOverviewTargetChange(mOverviewComponentObserver.isHomeAndOverviewSame());
363     }
364 
resetHomeBounceSeenOnQuickstepEnabledFirstTime()365     private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
366         if (!mDeviceState.isUserUnlocked() || mDeviceState.isButtonNavMode()) {
367             // Skip if not yet unlocked (can't read user shared prefs) or if the current navigation
368             // mode doesn't have gestures
369             return;
370         }
371 
372         // Reset home bounce seen on quick step enabled for first time
373         SharedPreferences sharedPrefs = Utilities.getPrefs(this);
374         if (!sharedPrefs.getBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)) {
375             sharedPrefs.edit()
376                     .putBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)
377                     .putBoolean(OnboardingPrefs.HOME_BOUNCE_SEEN, false)
378                     .apply();
379         }
380     }
381 
onOverviewTargetChange(boolean isHomeAndOverviewSame)382     private void onOverviewTargetChange(boolean isHomeAndOverviewSame) {
383         AccessibilityManager am = getSystemService(AccessibilityManager.class);
384 
385         if (isHomeAndOverviewSame) {
386             Intent intent = new Intent(mOverviewComponentObserver.getHomeIntent())
387                     .setAction(Intent.ACTION_ALL_APPS);
388             RemoteAction allAppsAction = new RemoteAction(
389                     Icon.createWithResource(this, R.drawable.ic_apps),
390                     getString(R.string.all_apps_label),
391                     getString(R.string.all_apps_label),
392                     PendingIntent.getActivity(this, SYSTEM_ACTION_ID_ALL_APPS, intent,
393                             PendingIntent.FLAG_UPDATE_CURRENT));
394             am.registerSystemAction(allAppsAction, SYSTEM_ACTION_ID_ALL_APPS);
395         } else {
396             am.unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS);
397         }
398     }
399 
400     @UiThread
onSystemUiFlagsChanged()401     private void onSystemUiFlagsChanged() {
402         if (mDeviceState.isUserUnlocked()) {
403             SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(
404                     mDeviceState.getSystemUiStateFlags());
405             mOverviewComponentObserver.onSystemUiStateChanged();
406 
407             // Update the tracing state
408             if ((mDeviceState.getSystemUiStateFlags() & SYSUI_STATE_TRACING_ENABLED) != 0) {
409                 ProtoTracer.INSTANCE.get(TouchInteractionService.this).start();
410             } else {
411                 ProtoTracer.INSTANCE.get(TouchInteractionService.this).stop();
412             }
413         }
414     }
415 
416     @UiThread
onAssistantVisibilityChanged()417     private void onAssistantVisibilityChanged() {
418         if (mDeviceState.isUserUnlocked()) {
419             mOverviewComponentObserver.getActivityInterface().onAssistantVisibilityChanged(
420                     mDeviceState.getAssistantVisibility());
421         }
422     }
423 
424     @Override
onDestroy()425     public void onDestroy() {
426         sIsInitialized = false;
427         if (mDeviceState.isUserUnlocked()) {
428             mInputConsumer.unregisterInputConsumer();
429             mOverviewComponentObserver.onDestroy();
430             PluginManagerWrapper.INSTANCE.get(getBaseContext()).removePluginListener(this);
431         }
432         disposeEventHandlers();
433         mDeviceState.destroy();
434         SystemUiProxy.INSTANCE.get(this).setProxy(null);
435         ProtoTracer.INSTANCE.get(TouchInteractionService.this).stop();
436         ProtoTracer.INSTANCE.get(this).remove(this);
437 
438         getSystemService(AccessibilityManager.class)
439                 .unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS);
440 
441         sConnected = false;
442         super.onDestroy();
443     }
444 
445     @Override
onBind(Intent intent)446     public IBinder onBind(Intent intent) {
447         Log.d(TAG, "Touch service connected");
448         return mMyBinder;
449     }
450 
onInputEvent(InputEvent ev)451     private void onInputEvent(InputEvent ev) {
452         if (!(ev instanceof MotionEvent)) {
453             Log.e(TAG, "Unknown event " + ev);
454             return;
455         }
456         MotionEvent event = (MotionEvent) ev;
457 
458         TestLogging.recordMotionEvent(
459                 TestProtocol.SEQUENCE_TIS, "TouchInteractionService.onInputEvent", event);
460 
461         if (!mDeviceState.isUserUnlocked()) {
462             return;
463         }
464 
465         Object traceToken = TraceHelper.INSTANCE.beginFlagsOverride(
466                 TraceHelper.FLAG_ALLOW_BINDER_TRACKING);
467 
468         final int action = event.getAction();
469         if (action == ACTION_DOWN) {
470             if (TestProtocol.sDebugTracing) {
471                 Log.d(TestProtocol.NO_SWIPE_TO_HOME, "TouchInteractionService.onInputEvent:DOWN");
472             }
473             mDeviceState.setOrientationTransformIfNeeded(event);
474 
475             if (mDeviceState.isInSwipeUpTouchRegion(event)) {
476                 if (TestProtocol.sDebugTracing) {
477                     Log.d(TestProtocol.NO_SWIPE_TO_HOME,
478                             "TouchInteractionService.onInputEvent:isInSwipeUpTouchRegion");
479                 }
480                 // Clone the previous gesture state since onConsumerAboutToBeSwitched might trigger
481                 // onConsumerInactive and wipe the previous gesture state
482                 GestureState prevGestureState = new GestureState(mGestureState);
483                 GestureState newGestureState = createGestureState(mGestureState);
484                 mConsumer.onConsumerAboutToBeSwitched();
485                 mGestureState = newGestureState;
486                 mConsumer = newConsumer(prevGestureState, mGestureState, event);
487 
488                 ActiveGestureLog.INSTANCE.addLog("setInputConsumer: " + mConsumer.getName());
489                 mUncheckedConsumer = mConsumer;
490             } else if (mDeviceState.isUserUnlocked() && mDeviceState.isFullyGesturalNavMode()) {
491                 mGestureState = createGestureState(mGestureState);
492                 ActivityManager.RunningTaskInfo runningTask = mGestureState.getRunningTask();
493                 if (mDeviceState.canTriggerAssistantAction(event, runningTask)) {
494                     // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
495                     // should not interrupt it. QuickSwitch assumes that interruption can only
496                     // happen if the next gesture is also quick switch.
497                     mUncheckedConsumer = new AssistantInputConsumer(
498                             this,
499                             mGestureState,
500                             InputConsumer.NO_OP, mInputMonitorCompat,
501                             mOverviewComponentObserver.assistantGestureIsConstrained());
502                 } else {
503                     mUncheckedConsumer = InputConsumer.NO_OP;
504                 }
505             } else {
506                 mUncheckedConsumer = InputConsumer.NO_OP;
507             }
508         } else {
509             // Other events
510             if (mUncheckedConsumer != InputConsumer.NO_OP) {
511                 // Only transform the event if we are handling it in a proper consumer
512                 mDeviceState.setOrientationTransformIfNeeded(event);
513             }
514         }
515 
516         if (mUncheckedConsumer != InputConsumer.NO_OP) {
517             switch (event.getActionMasked()) {
518                 case ACTION_DOWN:
519                 case ACTION_UP:
520                     ActiveGestureLog.INSTANCE.addLog("onMotionEvent("
521                             + (int) event.getRawX() + ", " + (int) event.getRawY() + ")",
522                             event.getActionMasked());
523                     break;
524                 default:
525                     ActiveGestureLog.INSTANCE.addLog("onMotionEvent", event.getActionMasked());
526                     break;
527             }
528         }
529 
530         boolean cleanUpConsumer = (action == ACTION_UP || action == ACTION_CANCEL)
531                 && mConsumer != null
532                 && !mConsumer.getActiveConsumerInHierarchy().isConsumerDetachedFromGesture();
533         mUncheckedConsumer.onMotionEvent(event);
534 
535         if (cleanUpConsumer) {
536             reset();
537         }
538         TraceHelper.INSTANCE.endFlagsOverride(traceToken);
539     }
540 
createGestureState(GestureState previousGestureState)541     private GestureState createGestureState(GestureState previousGestureState) {
542         GestureState gestureState = new GestureState(mOverviewComponentObserver,
543                 ActiveGestureLog.INSTANCE.generateAndSetLogId());
544         if (mTaskAnimationManager.isRecentsAnimationRunning()) {
545             gestureState.updateRunningTask(previousGestureState.getRunningTask());
546             gestureState.updateLastStartedTaskId(previousGestureState.getLastStartedTaskId());
547             gestureState.updatePreviouslyAppearedTaskIds(
548                     previousGestureState.getPreviouslyAppearedTaskIds());
549         } else {
550             gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
551                     () -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
552         }
553         return gestureState;
554     }
555 
newConsumer(GestureState previousGestureState, GestureState newGestureState, MotionEvent event)556     private InputConsumer newConsumer(GestureState previousGestureState,
557             GestureState newGestureState, MotionEvent event) {
558         if (TestProtocol.sDebugTracing) {
559             Log.d(TestProtocol.NO_SWIPE_TO_HOME, "newConsumer");
560         }
561         boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
562 
563         if (!mDeviceState.isUserUnlocked()) {
564             if (canStartSystemGesture) {
565                 // This handles apps launched in direct boot mode (e.g. dialer) as well as apps
566                 // launched while device is locked even after exiting direct boot mode (e.g. camera).
567                 return createDeviceLockedInputConsumer(newGestureState);
568             } else {
569                 return mResetGestureInputConsumer;
570             }
571         }
572         if (TestProtocol.sDebugTracing) {
573             Log.d(TestProtocol.NO_SWIPE_TO_HOME, "newConsumer:user is unlocked");
574         }
575 
576         // When there is an existing recents animation running, bypass systemState check as this is
577         // a followup gesture and the first gesture started in a valid system state.
578         InputConsumer base = canStartSystemGesture
579                 || previousGestureState.isRecentsAnimationRunning()
580                         ? newBaseConsumer(previousGestureState, newGestureState, event)
581                         : mResetGestureInputConsumer;
582         if (mDeviceState.isGesturalNavMode()) {
583             handleOrientationSetup(base);
584         }
585         if (mDeviceState.isFullyGesturalNavMode()) {
586             if (mDeviceState.canTriggerAssistantAction(event, newGestureState.getRunningTask())) {
587                 base = new AssistantInputConsumer(
588                     this,
589                     newGestureState,
590                     base,
591                     mInputMonitorCompat,
592                     mOverviewComponentObserver.assistantGestureIsConstrained());
593             }
594 
595             if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) {
596                 OverscrollPlugin plugin = null;
597                 if (FeatureFlags.FORCE_LOCAL_OVERSCROLL_PLUGIN.get()) {
598                     TaskOverlayFactory factory =
599                             TaskOverlayFactory.INSTANCE.get(getApplicationContext());
600                     plugin = factory.getLocalOverscrollPlugin();  // may be null
601                 }
602 
603                 // If not local plugin was forced, use the actual overscroll plugin if available.
604                 if (plugin == null && mOverscrollPlugin != null && mOverscrollPlugin.isActive()) {
605                     plugin = mOverscrollPlugin;
606                 }
607 
608                 if (plugin != null) {
609                     // Put the overscroll gesture as higher priority than the Assistant or base
610                     // gestures
611                     base = new OverscrollInputConsumer(this, newGestureState, base,
612                         mInputMonitorCompat, plugin);
613                 }
614             }
615 
616             // If Bubbles is expanded, use the overlay input consumer, which will close Bubbles
617             // instead of going all the way home when a swipe up is detected.
618             if (mDeviceState.isBubblesExpanded() || mDeviceState.isGlobalActionsShowing()) {
619                 base = new SysUiOverlayInputConsumer(
620                         getBaseContext(), mDeviceState, mInputMonitorCompat);
621             }
622 
623             if (mDeviceState.isScreenPinningActive()) {
624                 // Note: we only allow accessibility to wrap this, and it replaces the previous
625                 // base input consumer (which should be NO_OP anyway since topTaskLocked == true).
626                 base = new ScreenPinnedInputConsumer(this, newGestureState);
627             }
628 
629             if (mDeviceState.isAccessibilityMenuAvailable()) {
630                 base = new AccessibilityInputConsumer(this, mDeviceState, base,
631                         mInputMonitorCompat);
632             }
633         } else {
634             if (mDeviceState.isScreenPinningActive()) {
635                 base = mResetGestureInputConsumer;
636             }
637         }
638         return base;
639     }
640 
handleOrientationSetup(InputConsumer baseInputConsumer)641     private void handleOrientationSetup(InputConsumer baseInputConsumer) {
642         if (TestProtocol.sDebugTracing) {
643             Log.d(TestProtocol.PAUSE_NOT_DETECTED, "handleOrientationSetup.1");
644         }
645 
646         baseInputConsumer.notifyOrientationSetup();
647     }
648 
newBaseConsumer(GestureState previousGestureState, GestureState gestureState, MotionEvent event)649     private InputConsumer newBaseConsumer(GestureState previousGestureState,
650             GestureState gestureState, MotionEvent event) {
651         if (mDeviceState.isKeyguardShowingOccluded()) {
652             // This handles apps showing over the lockscreen (e.g. camera)
653             return createDeviceLockedInputConsumer(gestureState);
654         }
655 
656         // Use overview input consumer for sharesheets on top of home.
657         boolean forceOverviewInputConsumer = gestureState.getActivityInterface().isStarted()
658                 && gestureState.getRunningTask() != null
659                 && ACTION_CHOOSER.equals(gestureState.getRunningTask().baseIntent.getAction());
660         if (AssistantUtilities.isExcludedAssistant(gestureState.getRunningTask())) {
661             // In the case where we are in the excluded assistant state, ignore it and treat the
662             // running activity as the task behind the assistant
663             gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.assistant",
664                     () -> mAM.getRunningTask(true /* filterOnlyVisibleRecents */)));
665             ComponentName homeComponent = mOverviewComponentObserver.getHomeIntent().getComponent();
666             ComponentName runningComponent =
667                     gestureState.getRunningTask().baseIntent.getComponent();
668             forceOverviewInputConsumer =
669                     runningComponent != null && runningComponent.equals(homeComponent);
670         }
671 
672         if (gestureState.getRunningTask() == null) {
673             return mResetGestureInputConsumer;
674         } else if (previousGestureState.isRunningAnimationToLauncher()
675                 || gestureState.getActivityInterface().isResumed()
676                 || forceOverviewInputConsumer) {
677             return createOverviewInputConsumer(
678                     previousGestureState, gestureState, event, forceOverviewInputConsumer);
679         } else if (ENABLE_QUICKSTEP_LIVE_TILE.get()
680                 && gestureState.getActivityInterface().isInLiveTileMode()) {
681             return createOverviewInputConsumer(
682                     previousGestureState, gestureState, event, forceOverviewInputConsumer);
683         } else if (mDeviceState.isGestureBlockedActivity(gestureState.getRunningTask())) {
684             return mResetGestureInputConsumer;
685         } else {
686             return createOtherActivityInputConsumer(gestureState, event);
687         }
688     }
689 
createOtherActivityInputConsumer(GestureState gestureState, MotionEvent event)690     private InputConsumer createOtherActivityInputConsumer(GestureState gestureState,
691             MotionEvent event) {
692 
693         final BaseSwipeUpHandler.Factory factory;
694         if (!mOverviewComponentObserver.isHomeAndOverviewSame()) {
695             factory = mFallbackSwipeHandlerFactory;
696         } else {
697             factory = mLauncherSwipeHandlerFactory;
698         }
699 
700         final boolean shouldDefer = !mOverviewComponentObserver.isHomeAndOverviewSame()
701                 || gestureState.getActivityInterface().deferStartingActivity(mDeviceState, event);
702         final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
703         return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
704                 gestureState, shouldDefer, this::onConsumerInactive,
705                 mInputMonitorCompat, disableHorizontalSwipe, factory);
706     }
707 
createDeviceLockedInputConsumer(GestureState gestureState)708     private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState) {
709         if (mDeviceState.isFullyGesturalNavMode() && gestureState.getRunningTask() != null) {
710             return new DeviceLockedInputConsumer(this, mDeviceState, mTaskAnimationManager,
711                     gestureState, mInputMonitorCompat);
712         } else {
713             return mResetGestureInputConsumer;
714         }
715     }
716 
createOverviewInputConsumer(GestureState previousGestureState, GestureState gestureState, MotionEvent event, boolean forceOverviewInputConsumer)717     public InputConsumer createOverviewInputConsumer(GestureState previousGestureState,
718             GestureState gestureState, MotionEvent event,
719             boolean forceOverviewInputConsumer) {
720         StatefulActivity activity = gestureState.getActivityInterface().getCreatedActivity();
721         if (activity == null) {
722             return mResetGestureInputConsumer;
723         }
724 
725         if (activity.getRootView().hasWindowFocus()
726                 || previousGestureState.isRunningAnimationToLauncher()
727                 || (FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS.get()
728                     && forceOverviewInputConsumer)) {
729             return new OverviewInputConsumer(gestureState, activity, mInputMonitorCompat,
730                     false /* startingInActivityBounds */);
731         } else {
732             final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
733             return new OverviewWithoutFocusInputConsumer(activity, mDeviceState, gestureState,
734                     mInputMonitorCompat, disableHorizontalSwipe);
735         }
736     }
737 
738     /**
739      * To be called by the consumer when it's no longer active. This can be called by any consumer
740      * in the hierarchy at any point during the gesture (ie. if a delegate consumer starts
741      * intercepting touches, the base consumer can try to call this).
742      */
onConsumerInactive(InputConsumer caller)743     private void onConsumerInactive(InputConsumer caller) {
744         if (mConsumer != null && mConsumer.getActiveConsumerInHierarchy() == caller) {
745             reset();
746         }
747     }
748 
reset()749     private void reset() {
750         mConsumer = mUncheckedConsumer = mResetGestureInputConsumer;
751         mGestureState = DEFAULT_STATE;
752     }
753 
preloadOverview(boolean fromInit)754     private void preloadOverview(boolean fromInit) {
755         if (!mDeviceState.isUserUnlocked()) {
756             return;
757         }
758 
759         if (mDeviceState.isButtonNavMode() && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
760             // Prevent the overview from being started before the real home on first boot.
761             return;
762         }
763 
764         if (RestoreDbTask.isPending(this) || !mDeviceState.isUserSetupComplete()) {
765             // Preloading while a restore is pending may cause launcher to start the restore
766             // too early.
767             return;
768         }
769 
770         final BaseActivityInterface activityInterface =
771                 mOverviewComponentObserver.getActivityInterface();
772         final Intent overviewIntent = new Intent(
773                 mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState());
774         if (activityInterface.getCreatedActivity() == null) {
775             // Make sure that UI states will be initialized.
776             activityInterface.createActivityInitListener((wasVisible) -> {
777                 AppLaunchTracker.INSTANCE.get(TouchInteractionService.this);
778                 return false;
779             }).register(overviewIntent);
780         } else if (fromInit) {
781             // The activity has been created before the initialization of overview service. It is
782             // usually happens when booting or launcher is the top activity, so we should already
783             // have the latest state.
784             return;
785         }
786 
787         mTaskAnimationManager.preloadRecentsAnimation(overviewIntent);
788     }
789 
790     @Override
onConfigurationChanged(Configuration newConfig)791     public void onConfigurationChanged(Configuration newConfig) {
792         if (!mDeviceState.isUserUnlocked()) {
793             return;
794         }
795         final BaseActivityInterface activityInterface =
796                 mOverviewComponentObserver.getActivityInterface();
797         final BaseDraggingActivity activity = activityInterface.getCreatedActivity();
798         if (activity == null || activity.isStarted()) {
799             // We only care about the existing background activity.
800             return;
801         }
802         if (mOverviewComponentObserver.canHandleConfigChanges(activity.getComponentName(),
803                 activity.getResources().getConfiguration().diff(newConfig))) {
804             return;
805         }
806 
807         preloadOverview(false /* fromInit */);
808     }
809 
810     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs)811     protected void dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs) {
812         if (rawArgs.length > 0 && Utilities.IS_DEBUG_DEVICE) {
813             ArgList args = new ArgList(Arrays.asList(rawArgs));
814             switch (args.nextArg()) {
815                 case "cmd":
816                     if (args.peekArg() == null) {
817                         printAvailableCommands(pw);
818                     } else {
819                         onCommand(pw, args);
820                     }
821                     break;
822             }
823         } else {
824             // Dump everything
825             FeatureFlags.dump(pw);
826             if (mDeviceState.isUserUnlocked()) {
827                 PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw);
828             }
829             mDeviceState.dump(pw);
830             if (mOverviewComponentObserver != null) {
831                 mOverviewComponentObserver.dump(pw);
832             }
833             if (mGestureState != null) {
834                 mGestureState.dump(pw);
835             }
836             SysUINavigationMode.INSTANCE.get(this).dump(pw);
837             pw.println("TouchState:");
838             BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null
839                     : mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
840             boolean resumed = mOverviewComponentObserver != null
841                     && mOverviewComponentObserver.getActivityInterface().isResumed();
842             pw.println("  createdOverviewActivity=" + createdOverviewActivity);
843             pw.println("  resumed=" + resumed);
844             pw.println("  mConsumer=" + mConsumer.getName());
845             ActiveGestureLog.INSTANCE.dump("", pw);
846             pw.println("ProtoTrace:");
847             pw.println("  file="
848                     + ProtoTracer.INSTANCE.get(TouchInteractionService.this).getTraceFile());
849         }
850     }
851 
printAvailableCommands(PrintWriter pw)852     private void printAvailableCommands(PrintWriter pw) {
853         pw.println("Available commands:");
854         pw.println("  clear-touch-log: Clears the touch interaction log");
855     }
856 
onCommand(PrintWriter pw, ArgList args)857     private void onCommand(PrintWriter pw, ArgList args) {
858         switch (args.nextArg()) {
859             case "clear-touch-log":
860                 ActiveGestureLog.INSTANCE.clear();
861                 break;
862         }
863     }
864 
createLauncherSwipeHandler( GestureState gestureState, long touchTimeMs, boolean continuingLastGesture)865     private BaseSwipeUpHandler createLauncherSwipeHandler(
866             GestureState gestureState, long touchTimeMs, boolean continuingLastGesture) {
867         return new LauncherSwipeHandlerV2(this, mDeviceState, mTaskAnimationManager,
868                 gestureState, touchTimeMs, continuingLastGesture, mInputConsumer);
869     }
870 
createFallbackSwipeHandler( GestureState gestureState, long touchTimeMs, boolean continuingLastGesture)871     private BaseSwipeUpHandler createFallbackSwipeHandler(
872             GestureState gestureState, long touchTimeMs, boolean continuingLastGesture) {
873         return new FallbackSwipeHandler(this, mDeviceState, mTaskAnimationManager,
874                 gestureState, touchTimeMs, continuingLastGesture, mInputConsumer);
875     }
876 
shouldNotifyBackGesture()877     protected boolean shouldNotifyBackGesture() {
878         return mBackGestureNotificationCounter > 0 &&
879                 !mDeviceState.getGestureBlockedActivityPackages().isEmpty();
880     }
881 
882     @WorkerThread
tryNotifyBackGesture()883     protected void tryNotifyBackGesture() {
884         if (shouldNotifyBackGesture()) {
885             mBackGestureNotificationCounter--;
886             Utilities.getDevicePrefs(this).edit()
887                     .putInt(KEY_BACK_NOTIFICATION_COUNT, mBackGestureNotificationCounter).apply();
888             mDeviceState.getGestureBlockedActivityPackages().forEach(blockedPackage ->
889                     sendBroadcast(new Intent(NOTIFY_ACTION_BACK).setPackage(blockedPackage)));
890         }
891     }
892 
893     @Override
onPluginConnected(OverscrollPlugin overscrollPlugin, Context context)894     public void onPluginConnected(OverscrollPlugin overscrollPlugin, Context context) {
895         mOverscrollPlugin = overscrollPlugin;
896     }
897 
898     @Override
onPluginDisconnected(OverscrollPlugin overscrollPlugin)899     public void onPluginDisconnected(OverscrollPlugin overscrollPlugin) {
900         mOverscrollPlugin = null;
901     }
902 
903     @Override
writeToProto(LauncherTraceProto proto)904     public void writeToProto(LauncherTraceProto proto) {
905         if (proto.touchInteractionService == null) {
906             proto.touchInteractionService = new TouchInteractionServiceProto();
907         }
908         proto.touchInteractionService.serviceConnected = true;
909         proto.touchInteractionService.serviceConnected = true;
910     }
911 }
912