• 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.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     private RotationTouchHelper mRotationTouchHelper;
262 
isConnected()263     public static boolean isConnected() {
264         return sConnected;
265     }
266 
isInitialized()267     public static boolean isInitialized() {
268         return sIsInitialized;
269     }
270 
271     private final BaseSwipeUpHandler.Factory mLauncherSwipeHandlerFactory =
272             this::createLauncherSwipeHandler;
273     private final BaseSwipeUpHandler.Factory mFallbackSwipeHandlerFactory =
274             this::createFallbackSwipeHandler;
275 
276     private ActivityManagerWrapper mAM;
277     private OverviewCommandHelper mOverviewCommandHelper;
278     private OverviewComponentObserver mOverviewComponentObserver;
279     private InputConsumerController mInputConsumer;
280     private RecentsAnimationDeviceState mDeviceState;
281     private TaskAnimationManager mTaskAnimationManager;
282 
283     private InputConsumer mUncheckedConsumer = InputConsumer.NO_OP;
284     private InputConsumer mConsumer = InputConsumer.NO_OP;
285     private Choreographer mMainChoreographer;
286     private InputConsumer mResetGestureInputConsumer;
287     private GestureState mGestureState = DEFAULT_STATE;
288 
289     private InputMonitorCompat mInputMonitorCompat;
290     private InputEventReceiver mInputEventReceiver;
291 
292     @Override
onCreate()293     public void onCreate() {
294         super.onCreate();
295         // Initialize anything here that is needed in direct boot mode.
296         // Everything else should be initialized in onUserUnlocked() below.
297         mMainChoreographer = Choreographer.getInstance();
298         mAM = ActivityManagerWrapper.getInstance();
299         mDeviceState = new RecentsAnimationDeviceState(this);
300         mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
301         mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
302         mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
303         ProtoTracer.INSTANCE.get(this).add(this);
304 
305         sConnected = true;
306     }
307 
disposeEventHandlers()308     private void disposeEventHandlers() {
309         if (mInputEventReceiver != null) {
310             mInputEventReceiver.dispose();
311             mInputEventReceiver = null;
312         }
313         if (mInputMonitorCompat != null) {
314             mInputMonitorCompat.dispose();
315             mInputMonitorCompat = null;
316         }
317     }
318 
initInputMonitor()319     private void initInputMonitor() {
320         disposeEventHandlers();
321         if (mDeviceState.isButtonNavMode() || !SystemUiProxy.INSTANCE.get(this).isActive()) {
322             return;
323         }
324 
325         Bundle bundle = SystemUiProxy.INSTANCE.get(this).monitorGestureInput("swipe-up",
326                 mDeviceState.getDisplayId());
327         mInputMonitorCompat = InputMonitorCompat.fromBundle(bundle, KEY_EXTRA_INPUT_MONITOR);
328         mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
329                 mMainChoreographer, this::onInputEvent);
330 
331         mRotationTouchHelper.updateGestureTouchRegions();
332     }
333 
334     /**
335      * Called when the navigation mode changes, guaranteed to be after the device state has updated.
336      */
onNavigationModeChanged(SysUINavigationMode.Mode mode)337     private void onNavigationModeChanged(SysUINavigationMode.Mode mode) {
338         initInputMonitor();
339         resetHomeBounceSeenOnQuickstepEnabledFirstTime();
340     }
341 
342     @UiThread
onUserUnlocked()343     public void onUserUnlocked() {
344         mTaskAnimationManager = new TaskAnimationManager();
345         mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
346         mOverviewCommandHelper = new OverviewCommandHelper(this, mDeviceState,
347                 mOverviewComponentObserver);
348         mResetGestureInputConsumer = new ResetGestureInputConsumer(mTaskAnimationManager);
349         mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
350         mInputConsumer.registerInputConsumer();
351         onSystemUiFlagsChanged();
352         onAssistantVisibilityChanged();
353 
354         // Temporarily disable model preload
355         // new ModelPreload().start(this);
356         mBackGestureNotificationCounter = Math.max(0, Utilities.getDevicePrefs(this)
357                 .getInt(KEY_BACK_NOTIFICATION_COUNT, MAX_BACK_NOTIFICATION_COUNT));
358         resetHomeBounceSeenOnQuickstepEnabledFirstTime();
359 
360         PluginManagerWrapper.INSTANCE.get(getBaseContext()).addPluginListener(this,
361                 OverscrollPlugin.class, false /* allowMultiple */);
362 
363         mOverviewComponentObserver.setOverviewChangeListener(this::onOverviewTargetChange);
364         onOverviewTargetChange(mOverviewComponentObserver.isHomeAndOverviewSame());
365     }
366 
resetHomeBounceSeenOnQuickstepEnabledFirstTime()367     private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
368         if (!mDeviceState.isUserUnlocked() || mDeviceState.isButtonNavMode()) {
369             // Skip if not yet unlocked (can't read user shared prefs) or if the current navigation
370             // mode doesn't have gestures
371             return;
372         }
373 
374         // Reset home bounce seen on quick step enabled for first time
375         SharedPreferences sharedPrefs = Utilities.getPrefs(this);
376         if (!sharedPrefs.getBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)) {
377             sharedPrefs.edit()
378                     .putBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)
379                     .putBoolean(OnboardingPrefs.HOME_BOUNCE_SEEN, false)
380                     .apply();
381         }
382     }
383 
onOverviewTargetChange(boolean isHomeAndOverviewSame)384     private void onOverviewTargetChange(boolean isHomeAndOverviewSame) {
385         AccessibilityManager am = getSystemService(AccessibilityManager.class);
386 
387         if (isHomeAndOverviewSame) {
388             Intent intent = new Intent(mOverviewComponentObserver.getHomeIntent())
389                     .setAction(Intent.ACTION_ALL_APPS);
390             RemoteAction allAppsAction = new RemoteAction(
391                     Icon.createWithResource(this, R.drawable.ic_apps),
392                     getString(R.string.all_apps_label),
393                     getString(R.string.all_apps_label),
394                     PendingIntent.getActivity(this, SYSTEM_ACTION_ID_ALL_APPS, intent,
395                             PendingIntent.FLAG_UPDATE_CURRENT));
396             am.registerSystemAction(allAppsAction, SYSTEM_ACTION_ID_ALL_APPS);
397         } else {
398             am.unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS);
399         }
400     }
401 
402     @UiThread
onSystemUiFlagsChanged()403     private void onSystemUiFlagsChanged() {
404         if (mDeviceState.isUserUnlocked()) {
405             SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(
406                     mDeviceState.getSystemUiStateFlags());
407             mOverviewComponentObserver.onSystemUiStateChanged();
408 
409             // Update the tracing state
410             if ((mDeviceState.getSystemUiStateFlags() & SYSUI_STATE_TRACING_ENABLED) != 0) {
411                 ProtoTracer.INSTANCE.get(TouchInteractionService.this).start();
412             } else {
413                 ProtoTracer.INSTANCE.get(TouchInteractionService.this).stop();
414             }
415         }
416     }
417 
418     @UiThread
onAssistantVisibilityChanged()419     private void onAssistantVisibilityChanged() {
420         if (mDeviceState.isUserUnlocked()) {
421             mOverviewComponentObserver.getActivityInterface().onAssistantVisibilityChanged(
422                     mDeviceState.getAssistantVisibility());
423         }
424     }
425 
426     @Override
onDestroy()427     public void onDestroy() {
428         sIsInitialized = false;
429         if (mDeviceState.isUserUnlocked()) {
430             mInputConsumer.unregisterInputConsumer();
431             mOverviewComponentObserver.onDestroy();
432             PluginManagerWrapper.INSTANCE.get(getBaseContext()).removePluginListener(this);
433         }
434         disposeEventHandlers();
435         mDeviceState.destroy();
436         SystemUiProxy.INSTANCE.get(this).setProxy(null);
437         ProtoTracer.INSTANCE.get(TouchInteractionService.this).stop();
438         ProtoTracer.INSTANCE.get(this).remove(this);
439 
440         getSystemService(AccessibilityManager.class)
441                 .unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS);
442 
443         sConnected = false;
444         super.onDestroy();
445     }
446 
447     @Override
onBind(Intent intent)448     public IBinder onBind(Intent intent) {
449         Log.d(TAG, "Touch service connected");
450         return mMyBinder;
451     }
452 
onInputEvent(InputEvent ev)453     private void onInputEvent(InputEvent ev) {
454         if (!(ev instanceof MotionEvent)) {
455             Log.e(TAG, "Unknown event " + ev);
456             return;
457         }
458         MotionEvent event = (MotionEvent) ev;
459 
460         TestLogging.recordMotionEvent(
461                 TestProtocol.SEQUENCE_TIS, "TouchInteractionService.onInputEvent", event);
462 
463         if (!mDeviceState.isUserUnlocked()) {
464             return;
465         }
466 
467         Object traceToken = TraceHelper.INSTANCE.beginFlagsOverride(
468                 TraceHelper.FLAG_ALLOW_BINDER_TRACKING);
469 
470         final int action = event.getAction();
471         if (action == ACTION_DOWN) {
472             if (TestProtocol.sDebugTracing) {
473                 Log.d(TestProtocol.NO_SWIPE_TO_HOME, "TouchInteractionService.onInputEvent:DOWN");
474             }
475             mRotationTouchHelper.setOrientationTransformIfNeeded(event);
476 
477             if (mRotationTouchHelper.isInSwipeUpTouchRegion(event)) {
478                 if (TestProtocol.sDebugTracing) {
479                     Log.d(TestProtocol.NO_SWIPE_TO_HOME,
480                             "TouchInteractionService.onInputEvent:isInSwipeUpTouchRegion");
481                 }
482                 // Clone the previous gesture state since onConsumerAboutToBeSwitched might trigger
483                 // onConsumerInactive and wipe the previous gesture state
484                 GestureState prevGestureState = new GestureState(mGestureState);
485                 GestureState newGestureState = createGestureState(mGestureState);
486                 mConsumer.onConsumerAboutToBeSwitched();
487                 mGestureState = newGestureState;
488                 mConsumer = newConsumer(prevGestureState, mGestureState, event);
489 
490                 ActiveGestureLog.INSTANCE.addLog("setInputConsumer: " + mConsumer.getName());
491                 mUncheckedConsumer = mConsumer;
492             } else if (mDeviceState.isUserUnlocked() && mDeviceState.isFullyGesturalNavMode()) {
493                 mGestureState = createGestureState(mGestureState);
494                 ActivityManager.RunningTaskInfo runningTask = mGestureState.getRunningTask();
495                 if (mDeviceState.canTriggerAssistantAction(event, runningTask)) {
496                     // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
497                     // should not interrupt it. QuickSwitch assumes that interruption can only
498                     // happen if the next gesture is also quick switch.
499                     mUncheckedConsumer = new AssistantInputConsumer(
500                             this,
501                             mGestureState,
502                             InputConsumer.NO_OP, mInputMonitorCompat,
503                             mOverviewComponentObserver.assistantGestureIsConstrained());
504                 } else {
505                     mUncheckedConsumer = InputConsumer.NO_OP;
506                 }
507             } else {
508                 mUncheckedConsumer = InputConsumer.NO_OP;
509             }
510         } else {
511             // Other events
512             if (mUncheckedConsumer != InputConsumer.NO_OP) {
513                 // Only transform the event if we are handling it in a proper consumer
514                 mRotationTouchHelper.setOrientationTransformIfNeeded(event);
515             }
516         }
517 
518         if (mUncheckedConsumer != InputConsumer.NO_OP) {
519             switch (event.getActionMasked()) {
520                 case ACTION_DOWN:
521                 case ACTION_UP:
522                     ActiveGestureLog.INSTANCE.addLog("onMotionEvent("
523                             + (int) event.getRawX() + ", " + (int) event.getRawY() + ")",
524                             event.getActionMasked());
525                     break;
526                 default:
527                     ActiveGestureLog.INSTANCE.addLog("onMotionEvent", event.getActionMasked());
528                     break;
529             }
530         }
531 
532         boolean cleanUpConsumer = (action == ACTION_UP || action == ACTION_CANCEL)
533                 && mConsumer != null
534                 && !mConsumer.getActiveConsumerInHierarchy().isConsumerDetachedFromGesture();
535         mUncheckedConsumer.onMotionEvent(event);
536 
537         if (cleanUpConsumer) {
538             reset();
539         }
540         TraceHelper.INSTANCE.endFlagsOverride(traceToken);
541     }
542 
createGestureState(GestureState previousGestureState)543     private GestureState createGestureState(GestureState previousGestureState) {
544         GestureState gestureState = new GestureState(mOverviewComponentObserver,
545                 ActiveGestureLog.INSTANCE.generateAndSetLogId());
546         if (mTaskAnimationManager.isRecentsAnimationRunning()) {
547             gestureState.updateRunningTask(previousGestureState.getRunningTask());
548             gestureState.updateLastStartedTaskId(previousGestureState.getLastStartedTaskId());
549             gestureState.updatePreviouslyAppearedTaskIds(
550                     previousGestureState.getPreviouslyAppearedTaskIds());
551         } else {
552             gestureState.updateRunningTask(TraceHelper.allowIpcs("getRunningTask.0",
553                     () -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
554         }
555         return gestureState;
556     }
557 
newConsumer(GestureState previousGestureState, GestureState newGestureState, MotionEvent event)558     private InputConsumer newConsumer(GestureState previousGestureState,
559             GestureState newGestureState, MotionEvent event) {
560         if (TestProtocol.sDebugTracing) {
561             Log.d(TestProtocol.NO_SWIPE_TO_HOME, "newConsumer");
562         }
563         boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
564 
565         if (!mDeviceState.isUserUnlocked()) {
566             if (canStartSystemGesture) {
567                 // This handles apps launched in direct boot mode (e.g. dialer) as well as apps
568                 // launched while device is locked even after exiting direct boot mode (e.g. camera).
569                 return createDeviceLockedInputConsumer(newGestureState);
570             } else {
571                 return mResetGestureInputConsumer;
572             }
573         }
574         if (TestProtocol.sDebugTracing) {
575             Log.d(TestProtocol.NO_SWIPE_TO_HOME, "newConsumer:user is unlocked");
576         }
577 
578         // When there is an existing recents animation running, bypass systemState check as this is
579         // a followup gesture and the first gesture started in a valid system state.
580         InputConsumer base = canStartSystemGesture
581                 || previousGestureState.isRecentsAnimationRunning()
582                         ? newBaseConsumer(previousGestureState, newGestureState, event)
583                         : mResetGestureInputConsumer;
584         if (mDeviceState.isGesturalNavMode()) {
585             handleOrientationSetup(base);
586         }
587         if (mDeviceState.isFullyGesturalNavMode()) {
588             if (mDeviceState.canTriggerAssistantAction(event, newGestureState.getRunningTask())) {
589                 base = new AssistantInputConsumer(
590                     this,
591                     newGestureState,
592                     base,
593                     mInputMonitorCompat,
594                     mOverviewComponentObserver.assistantGestureIsConstrained());
595             }
596 
597             if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) {
598                 OverscrollPlugin plugin = null;
599                 if (FeatureFlags.FORCE_LOCAL_OVERSCROLL_PLUGIN.get()) {
600                     plugin = OverscrollPluginFactory.INSTANCE.get(
601                             getApplicationContext()).getLocalOverscrollPlugin();
602                 }
603 
604                 // If not local plugin was forced, use the actual overscroll plugin if available.
605                 if (plugin == null && mOverscrollPlugin != null && mOverscrollPlugin.isActive()) {
606                     plugin = mOverscrollPlugin;
607                 }
608 
609                 if (plugin != null) {
610                     // Put the overscroll gesture as higher priority than the Assistant or base
611                     // gestures
612                     base = new OverscrollInputConsumer(this, newGestureState, base,
613                         mInputMonitorCompat, plugin);
614                 }
615             }
616 
617             // If Bubbles is expanded, use the overlay input consumer, which will close Bubbles
618             // instead of going all the way home when a swipe up is detected.
619             if (mDeviceState.isBubblesExpanded() || mDeviceState.isGlobalActionsShowing()) {
620                 base = new SysUiOverlayInputConsumer(
621                         getBaseContext(), mDeviceState, mInputMonitorCompat);
622             }
623 
624             if (mDeviceState.isScreenPinningActive()) {
625                 // Note: we only allow accessibility to wrap this, and it replaces the previous
626                 // base input consumer (which should be NO_OP anyway since topTaskLocked == true).
627                 base = new ScreenPinnedInputConsumer(this, newGestureState);
628             }
629 
630             if (mDeviceState.isAccessibilityMenuAvailable()) {
631                 base = new AccessibilityInputConsumer(this, mDeviceState, base,
632                         mInputMonitorCompat);
633             }
634         } else {
635             if (mDeviceState.isScreenPinningActive()) {
636                 base = mResetGestureInputConsumer;
637             }
638         }
639         return base;
640     }
641 
handleOrientationSetup(InputConsumer baseInputConsumer)642     private void handleOrientationSetup(InputConsumer baseInputConsumer) {
643         if (TestProtocol.sDebugTracing) {
644             Log.d(TestProtocol.PAUSE_NOT_DETECTED, "handleOrientationSetup.1");
645         }
646 
647         baseInputConsumer.notifyOrientationSetup();
648     }
649 
newBaseConsumer(GestureState previousGestureState, GestureState gestureState, MotionEvent event)650     private InputConsumer newBaseConsumer(GestureState previousGestureState,
651             GestureState gestureState, MotionEvent event) {
652         if (mDeviceState.isKeyguardShowingOccluded()) {
653             // This handles apps showing over the lockscreen (e.g. camera)
654             return createDeviceLockedInputConsumer(gestureState);
655         }
656 
657         // Use overview input consumer for sharesheets on top of home.
658         boolean forceOverviewInputConsumer = gestureState.getActivityInterface().isStarted()
659                 && gestureState.getRunningTask() != null
660                 && ACTION_CHOOSER.equals(gestureState.getRunningTask().baseIntent.getAction());
661         if (AssistantUtilities.isExcludedAssistant(gestureState.getRunningTask())) {
662             // In the case where we are in the excluded assistant state, ignore it and treat the
663             // running activity as the task behind the assistant
664             gestureState.updateRunningTask(TraceHelper.allowIpcs("getRunningTask.assistant",
665                     () -> mAM.getRunningTask(true /* filterOnlyVisibleRecents */)));
666             ComponentName homeComponent = mOverviewComponentObserver.getHomeIntent().getComponent();
667             ComponentName runningComponent =
668                     gestureState.getRunningTask().baseIntent.getComponent();
669             forceOverviewInputConsumer =
670                     runningComponent != null && runningComponent.equals(homeComponent);
671         }
672 
673         if (gestureState.getRunningTask() == null) {
674             return mResetGestureInputConsumer;
675         } else if (previousGestureState.isRunningAnimationToLauncher()
676                 || gestureState.getActivityInterface().isResumed()
677                 || forceOverviewInputConsumer) {
678             return createOverviewInputConsumer(
679                     previousGestureState, gestureState, event, forceOverviewInputConsumer);
680         } else if (ENABLE_QUICKSTEP_LIVE_TILE.get()
681                 && gestureState.getActivityInterface().isInLiveTileMode()) {
682             return createOverviewInputConsumer(
683                     previousGestureState, gestureState, event, forceOverviewInputConsumer);
684         } else if (mDeviceState.isGestureBlockedActivity(gestureState.getRunningTask())) {
685             return mResetGestureInputConsumer;
686         } else {
687             return createOtherActivityInputConsumer(gestureState, event);
688         }
689     }
690 
createOtherActivityInputConsumer(GestureState gestureState, MotionEvent event)691     private InputConsumer createOtherActivityInputConsumer(GestureState gestureState,
692             MotionEvent event) {
693 
694         final BaseSwipeUpHandler.Factory factory;
695         if (!mOverviewComponentObserver.isHomeAndOverviewSame()) {
696             factory = mFallbackSwipeHandlerFactory;
697         } else {
698             factory = mLauncherSwipeHandlerFactory;
699         }
700 
701         final boolean shouldDefer = !mOverviewComponentObserver.isHomeAndOverviewSame()
702                 || gestureState.getActivityInterface().deferStartingActivity(mDeviceState, event);
703         final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
704         return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
705                 gestureState, shouldDefer, this::onConsumerInactive,
706                 mInputMonitorCompat, disableHorizontalSwipe, factory);
707     }
708 
createDeviceLockedInputConsumer(GestureState gestureState)709     private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState) {
710         if (mDeviceState.isFullyGesturalNavMode() && gestureState.getRunningTask() != null) {
711             return new DeviceLockedInputConsumer(this, mDeviceState, mTaskAnimationManager,
712                     gestureState, mInputMonitorCompat);
713         } else {
714             return mResetGestureInputConsumer;
715         }
716     }
717 
createOverviewInputConsumer(GestureState previousGestureState, GestureState gestureState, MotionEvent event, boolean forceOverviewInputConsumer)718     public InputConsumer createOverviewInputConsumer(GestureState previousGestureState,
719             GestureState gestureState, MotionEvent event,
720             boolean forceOverviewInputConsumer) {
721         StatefulActivity activity = gestureState.getActivityInterface().getCreatedActivity();
722         if (activity == null) {
723             return mResetGestureInputConsumer;
724         }
725 
726         if (activity.getRootView().hasWindowFocus()
727                 || previousGestureState.isRunningAnimationToLauncher()
728                 || (FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS.get()
729                     && forceOverviewInputConsumer)) {
730             return new OverviewInputConsumer(gestureState, activity, mInputMonitorCompat,
731                     false /* startingInActivityBounds */);
732         } else {
733             final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
734             return new OverviewWithoutFocusInputConsumer(activity, mDeviceState, gestureState,
735                     mInputMonitorCompat, disableHorizontalSwipe);
736         }
737     }
738 
739     /**
740      * To be called by the consumer when it's no longer active. This can be called by any consumer
741      * in the hierarchy at any point during the gesture (ie. if a delegate consumer starts
742      * intercepting touches, the base consumer can try to call this).
743      */
onConsumerInactive(InputConsumer caller)744     private void onConsumerInactive(InputConsumer caller) {
745         if (mConsumer != null && mConsumer.getActiveConsumerInHierarchy() == caller) {
746             reset();
747         }
748     }
749 
reset()750     private void reset() {
751         mConsumer = mUncheckedConsumer = mResetGestureInputConsumer;
752         mGestureState = DEFAULT_STATE;
753     }
754 
preloadOverview(boolean fromInit)755     private void preloadOverview(boolean fromInit) {
756         if (!mDeviceState.isUserUnlocked()) {
757             return;
758         }
759 
760         if (mDeviceState.isButtonNavMode() && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
761             // Prevent the overview from being started before the real home on first boot.
762             return;
763         }
764 
765         if (RestoreDbTask.isPending(this) || !mDeviceState.isUserSetupComplete()) {
766             // Preloading while a restore is pending may cause launcher to start the restore
767             // too early.
768             return;
769         }
770 
771         final BaseActivityInterface activityInterface =
772                 mOverviewComponentObserver.getActivityInterface();
773         final Intent overviewIntent = new Intent(
774                 mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState());
775         if (activityInterface.getCreatedActivity() == null) {
776             // Make sure that UI states will be initialized.
777             activityInterface.createActivityInitListener((wasVisible) -> {
778                 AppLaunchTracker.INSTANCE.get(TouchInteractionService.this);
779                 return false;
780             }).register(overviewIntent);
781         } else if (fromInit) {
782             // The activity has been created before the initialization of overview service. It is
783             // usually happens when booting or launcher is the top activity, so we should already
784             // have the latest state.
785             return;
786         }
787 
788         mTaskAnimationManager.preloadRecentsAnimation(overviewIntent);
789     }
790 
791     @Override
onConfigurationChanged(Configuration newConfig)792     public void onConfigurationChanged(Configuration newConfig) {
793         if (!mDeviceState.isUserUnlocked()) {
794             return;
795         }
796         final BaseActivityInterface activityInterface =
797                 mOverviewComponentObserver.getActivityInterface();
798         final BaseDraggingActivity activity = activityInterface.getCreatedActivity();
799         if (activity == null || activity.isStarted()) {
800             // We only care about the existing background activity.
801             return;
802         }
803         if (mOverviewComponentObserver.canHandleConfigChanges(activity.getComponentName(),
804                 activity.getResources().getConfiguration().diff(newConfig))) {
805             return;
806         }
807 
808         preloadOverview(false /* fromInit */);
809     }
810 
811     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs)812     protected void dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs) {
813         if (rawArgs.length > 0 && Utilities.IS_DEBUG_DEVICE) {
814             ArgList args = new ArgList(Arrays.asList(rawArgs));
815             switch (args.nextArg()) {
816                 case "cmd":
817                     if (args.peekArg() == null) {
818                         printAvailableCommands(pw);
819                     } else {
820                         onCommand(pw, args);
821                     }
822                     break;
823             }
824         } else {
825             // Dump everything
826             FeatureFlags.dump(pw);
827             if (mDeviceState.isUserUnlocked()) {
828                 PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw);
829             }
830             mDeviceState.dump(pw);
831             if (mOverviewComponentObserver != null) {
832                 mOverviewComponentObserver.dump(pw);
833             }
834             if (mGestureState != null) {
835                 mGestureState.dump(pw);
836             }
837             SysUINavigationMode.INSTANCE.get(this).dump(pw);
838             pw.println("TouchState:");
839             BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null
840                     : mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
841             boolean resumed = mOverviewComponentObserver != null
842                     && mOverviewComponentObserver.getActivityInterface().isResumed();
843             pw.println("  createdOverviewActivity=" + createdOverviewActivity);
844             pw.println("  resumed=" + resumed);
845             pw.println("  mConsumer=" + mConsumer.getName());
846             ActiveGestureLog.INSTANCE.dump("", pw);
847             pw.println("ProtoTrace:");
848             pw.println("  file="
849                     + ProtoTracer.INSTANCE.get(TouchInteractionService.this).getTraceFile());
850         }
851     }
852 
printAvailableCommands(PrintWriter pw)853     private void printAvailableCommands(PrintWriter pw) {
854         pw.println("Available commands:");
855         pw.println("  clear-touch-log: Clears the touch interaction log");
856     }
857 
onCommand(PrintWriter pw, ArgList args)858     private void onCommand(PrintWriter pw, ArgList args) {
859         switch (args.nextArg()) {
860             case "clear-touch-log":
861                 ActiveGestureLog.INSTANCE.clear();
862                 break;
863         }
864     }
865 
createLauncherSwipeHandler( GestureState gestureState, long touchTimeMs, boolean continuingLastGesture)866     private BaseSwipeUpHandler createLauncherSwipeHandler(
867             GestureState gestureState, long touchTimeMs, boolean continuingLastGesture) {
868         return new LauncherSwipeHandlerV2(this, mDeviceState, mTaskAnimationManager,
869                 gestureState, touchTimeMs, continuingLastGesture, mInputConsumer);
870     }
871 
createFallbackSwipeHandler( GestureState gestureState, long touchTimeMs, boolean continuingLastGesture)872     private BaseSwipeUpHandler createFallbackSwipeHandler(
873             GestureState gestureState, long touchTimeMs, boolean continuingLastGesture) {
874         return new FallbackSwipeHandler(this, mDeviceState, mTaskAnimationManager,
875                 gestureState, touchTimeMs, continuingLastGesture, mInputConsumer);
876     }
877 
shouldNotifyBackGesture()878     protected boolean shouldNotifyBackGesture() {
879         return mBackGestureNotificationCounter > 0 &&
880                 !mDeviceState.getGestureBlockedActivityPackages().isEmpty();
881     }
882 
883     @WorkerThread
tryNotifyBackGesture()884     protected void tryNotifyBackGesture() {
885         if (shouldNotifyBackGesture()) {
886             mBackGestureNotificationCounter--;
887             Utilities.getDevicePrefs(this).edit()
888                     .putInt(KEY_BACK_NOTIFICATION_COUNT, mBackGestureNotificationCounter).apply();
889             mDeviceState.getGestureBlockedActivityPackages().forEach(blockedPackage ->
890                     sendBroadcast(new Intent(NOTIFY_ACTION_BACK).setPackage(blockedPackage)));
891         }
892     }
893 
894     @Override
onPluginConnected(OverscrollPlugin overscrollPlugin, Context context)895     public void onPluginConnected(OverscrollPlugin overscrollPlugin, Context context) {
896         mOverscrollPlugin = overscrollPlugin;
897     }
898 
899     @Override
onPluginDisconnected(OverscrollPlugin overscrollPlugin)900     public void onPluginDisconnected(OverscrollPlugin overscrollPlugin) {
901         mOverscrollPlugin = null;
902     }
903 
904     @Override
writeToProto(LauncherTraceProto proto)905     public void writeToProto(LauncherTraceProto proto) {
906         if (proto.touchInteractionService == null) {
907             proto.touchInteractionService = new TouchInteractionServiceProto();
908         }
909         proto.touchInteractionService.serviceConnected = true;
910         proto.touchInteractionService.serviceConnected = true;
911     }
912 }
913