• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.accessibilityservice.AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS;
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.ASSISTANT_GIVES_LAUNCHER_FOCUS;
24 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
25 import static com.android.quickstep.GestureState.DEFAULT_STATE;
26 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER;
27 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_DOWN;
28 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_UP;
29 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
30 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
31 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER;
32 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER;
33 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE;
34 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
35 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
36 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
37 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
38 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE;
39 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_ONE_HANDED;
40 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_PIP;
41 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS;
42 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
43 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
44 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW;
45 
46 import android.annotation.TargetApi;
47 import android.app.PendingIntent;
48 import android.app.RemoteAction;
49 import android.app.Service;
50 import android.content.Intent;
51 import android.content.SharedPreferences;
52 import android.content.res.Configuration;
53 import android.graphics.Region;
54 import android.graphics.drawable.Icon;
55 import android.os.Build;
56 import android.os.Bundle;
57 import android.os.IBinder;
58 import android.os.Looper;
59 import android.os.SystemClock;
60 import android.util.Log;
61 import android.view.Choreographer;
62 import android.view.InputEvent;
63 import android.view.MotionEvent;
64 import android.view.SurfaceControl;
65 import android.view.accessibility.AccessibilityManager;
66 
67 import androidx.annotation.BinderThread;
68 import androidx.annotation.NonNull;
69 import androidx.annotation.Nullable;
70 import androidx.annotation.UiThread;
71 
72 import com.android.app.viewcapture.SettingsAwareViewCapture;
73 import com.android.launcher3.BaseDraggingActivity;
74 import com.android.launcher3.LauncherPrefs;
75 import com.android.launcher3.R;
76 import com.android.launcher3.Utilities;
77 import com.android.launcher3.anim.AnimatedFloat;
78 import com.android.launcher3.config.FeatureFlags;
79 import com.android.launcher3.provider.RestoreDbTask;
80 import com.android.launcher3.statehandlers.DesktopVisibilityController;
81 import com.android.launcher3.statemanager.StatefulActivity;
82 import com.android.launcher3.taskbar.TaskbarActivityContext;
83 import com.android.launcher3.taskbar.TaskbarManager;
84 import com.android.launcher3.testing.TestLogging;
85 import com.android.launcher3.testing.shared.ResourceUtils;
86 import com.android.launcher3.testing.shared.TestProtocol;
87 import com.android.launcher3.tracing.LauncherTraceProto;
88 import com.android.launcher3.tracing.TouchInteractionServiceProto;
89 import com.android.launcher3.uioverrides.flags.FlagsFactory;
90 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
91 import com.android.launcher3.util.DisplayController;
92 import com.android.launcher3.util.OnboardingPrefs;
93 import com.android.launcher3.util.TraceHelper;
94 import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
95 import com.android.quickstep.inputconsumers.AssistantInputConsumer;
96 import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
97 import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
98 import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
99 import com.android.quickstep.inputconsumers.OverviewInputConsumer;
100 import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
101 import com.android.quickstep.inputconsumers.ProgressDelegateInputConsumer;
102 import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
103 import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
104 import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer;
105 import com.android.quickstep.inputconsumers.TaskbarStashInputConsumer;
106 import com.android.quickstep.util.ActiveGestureLog;
107 import com.android.quickstep.util.ActiveGestureLog.CompoundString;
108 import com.android.quickstep.util.ProtoTracer;
109 import com.android.quickstep.util.ProxyScreenStatusProvider;
110 import com.android.systemui.shared.recents.IOverviewProxy;
111 import com.android.systemui.shared.recents.ISystemUiProxy;
112 import com.android.systemui.shared.system.ActivityManagerWrapper;
113 import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
114 import com.android.systemui.shared.system.InputConsumerController;
115 import com.android.systemui.shared.system.InputMonitorCompat;
116 import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController;
117 import com.android.systemui.shared.tracing.ProtoTraceable;
118 import com.android.systemui.unfold.progress.IUnfoldAnimation;
119 import com.android.wm.shell.back.IBackAnimation;
120 import com.android.wm.shell.desktopmode.IDesktopMode;
121 import com.android.wm.shell.onehanded.IOneHanded;
122 import com.android.wm.shell.pip.IPip;
123 import com.android.wm.shell.recents.IRecentTasks;
124 import com.android.wm.shell.splitscreen.ISplitScreen;
125 import com.android.wm.shell.startingsurface.IStartingWindow;
126 import com.android.wm.shell.transition.IShellTransitions;
127 
128 import java.io.FileDescriptor;
129 import java.io.PrintWriter;
130 import java.util.Arrays;
131 import java.util.LinkedList;
132 import java.util.function.Function;
133 
134 /**
135  * Service connected by system-UI for handling touch interaction.
136  */
137 @TargetApi(Build.VERSION_CODES.R)
138 public class TouchInteractionService extends Service
139         implements ProtoTraceable<LauncherTraceProto.Builder> {
140 
141     private static final String SUBSTRING_PREFIX = "; ";
142     private static final String NEWLINE_PREFIX = "\n\t\t\t-> ";
143 
144     private static final String TAG = "TouchInteractionService";
145 
146     private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once";
147 
148     private final TISBinder mTISBinder = new TISBinder();
149 
150     /**
151      * Local IOverviewProxy implementation with some methods for local components
152      */
153     public class TISBinder extends IOverviewProxy.Stub {
154 
155         @Nullable private Runnable mOnOverviewTargetChangeListener = null;
156 
157         @BinderThread
onInitialize(Bundle bundle)158         public void onInitialize(Bundle bundle) {
159             ISystemUiProxy proxy = ISystemUiProxy.Stub.asInterface(
160                     bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
161             IPip pip = IPip.Stub.asInterface(bundle.getBinder(KEY_EXTRA_SHELL_PIP));
162             ISplitScreen splitscreen = ISplitScreen.Stub.asInterface(bundle.getBinder(
163                     KEY_EXTRA_SHELL_SPLIT_SCREEN));
164             IOneHanded onehanded = IOneHanded.Stub.asInterface(
165                     bundle.getBinder(KEY_EXTRA_SHELL_ONE_HANDED));
166             IShellTransitions shellTransitions = IShellTransitions.Stub.asInterface(
167                     bundle.getBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS));
168             IStartingWindow startingWindow = IStartingWindow.Stub.asInterface(
169                     bundle.getBinder(KEY_EXTRA_SHELL_STARTING_WINDOW));
170             ISysuiUnlockAnimationController launcherUnlockAnimationController =
171                     ISysuiUnlockAnimationController.Stub.asInterface(
172                             bundle.getBinder(KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER));
173             IRecentTasks recentTasks = IRecentTasks.Stub.asInterface(
174                     bundle.getBinder(KEY_EXTRA_SHELL_RECENT_TASKS));
175             IBackAnimation backAnimation = IBackAnimation.Stub.asInterface(
176                     bundle.getBinder(KEY_EXTRA_SHELL_BACK_ANIMATION));
177             IDesktopMode desktopMode = IDesktopMode.Stub.asInterface(
178                     bundle.getBinder(KEY_EXTRA_SHELL_DESKTOP_MODE));
179             IUnfoldAnimation unfoldTransition = IUnfoldAnimation.Stub.asInterface(
180                     bundle.getBinder(KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER));
181             MAIN_EXECUTOR.execute(() -> {
182                 SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip,
183                         splitscreen, onehanded, shellTransitions, startingWindow,
184                         recentTasks, launcherUnlockAnimationController, backAnimation, desktopMode,
185                         unfoldTransition);
186                 TouchInteractionService.this.initInputMonitor("TISBinder#onInitialize()");
187                 preloadOverview(true /* fromInit */);
188             });
189             sIsInitialized = true;
190         }
191 
192         @BinderThread
onOverviewToggle()193         public void onOverviewToggle() {
194             TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle");
195             // If currently screen pinning, do not enter overview
196             if (mDeviceState.isScreenPinningActive()) {
197                 return;
198             }
199             TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
200             mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_TOGGLE);
201         }
202 
203         @BinderThread
204         @Override
onOverviewShown(boolean triggeredFromAltTab)205         public void onOverviewShown(boolean triggeredFromAltTab) {
206             if (triggeredFromAltTab) {
207                 TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
208                 mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_KEYBOARD_INPUT);
209             } else {
210                 mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW);
211             }
212         }
213 
214         @BinderThread
215         @Override
onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)216         public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
217             if (triggeredFromAltTab && !triggeredFromHomeKey) {
218                 // onOverviewShownFromAltTab hides the overview and ends at the target app
219                 mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HIDE);
220             }
221         }
222 
223         @BinderThread
224         @Override
onAssistantAvailable(boolean available, boolean longPressHomeEnabled)225         public void onAssistantAvailable(boolean available, boolean longPressHomeEnabled) {
226             MAIN_EXECUTOR.execute(() -> {
227                 mDeviceState.setAssistantAvailable(available);
228                 TouchInteractionService.this.onAssistantVisibilityChanged();
229                 executeForTaskbarManager(() -> mTaskbarManager
230                         .onLongPressHomeEnabled(longPressHomeEnabled));
231             });
232         }
233 
234         @BinderThread
235         @Override
onAssistantVisibilityChanged(float visibility)236         public void onAssistantVisibilityChanged(float visibility) {
237             MAIN_EXECUTOR.execute(() -> {
238                 mDeviceState.setAssistantVisibility(visibility);
239                 TouchInteractionService.this.onAssistantVisibilityChanged();
240             });
241         }
242 
243         @Override
onNavigationBarSurface(SurfaceControl surface)244         public void onNavigationBarSurface(SurfaceControl surface) {
245             // TODO: implement
246         }
247 
248         @BinderThread
onSystemUiStateChanged(int stateFlags)249         public void onSystemUiStateChanged(int stateFlags) {
250             MAIN_EXECUTOR.execute(() -> {
251                 int lastFlags = mDeviceState.getSystemUiStateFlags();
252                 mDeviceState.setSystemUiFlags(stateFlags);
253                 TouchInteractionService.this.onSystemUiFlagsChanged(lastFlags);
254             });
255         }
256 
257         @BinderThread
onActiveNavBarRegionChanges(Region region)258         public void onActiveNavBarRegionChanges(Region region) {
259             MAIN_EXECUTOR.execute(() -> mDeviceState.setDeferredGestureRegion(region));
260         }
261 
262         @BinderThread
263         @Override
onScreenTurnedOn()264         public void onScreenTurnedOn() {
265             MAIN_EXECUTOR.execute(ProxyScreenStatusProvider.INSTANCE::onScreenTurnedOn);
266         }
267 
268         @BinderThread
269         @Override
onScreenTurningOn()270         public void onScreenTurningOn() {
271             MAIN_EXECUTOR.execute(ProxyScreenStatusProvider.INSTANCE::onScreenTurningOn);
272         }
273 
274         @BinderThread
275         @Override
onScreenTurningOff()276         public void onScreenTurningOff() {
277             MAIN_EXECUTOR.execute(ProxyScreenStatusProvider.INSTANCE::onScreenTurningOff);
278         }
279 
280         @BinderThread
281         @Override
enterStageSplitFromRunningApp(boolean leftOrTop)282         public void enterStageSplitFromRunningApp(boolean leftOrTop) {
283             StatefulActivity activity =
284                     mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
285             if (activity != null) {
286                 activity.enterStageSplitFromRunningApp(leftOrTop);
287             }
288         }
289 
290         /**
291          * Preloads the Overview activity.
292          *
293          * This method should only be used when the All Set page of the SUW is reached to safely
294          * preload the Launcher for the SUW first reveal.
295          */
preloadOverviewForSUWAllSet()296         public void preloadOverviewForSUWAllSet() {
297             preloadOverview(false, true);
298         }
299 
300         @Override
onRotationProposal(int rotation, boolean isValid)301         public void onRotationProposal(int rotation, boolean isValid) {
302             executeForTaskbarManager(() -> mTaskbarManager.onRotationProposal(rotation, isValid));
303         }
304 
305         @Override
disable(int displayId, int state1, int state2, boolean animate)306         public void disable(int displayId, int state1, int state2, boolean animate) {
307             executeForTaskbarManager(() -> mTaskbarManager
308                     .disableNavBarElements(displayId, state1, state2, animate));
309         }
310 
311         @Override
onSystemBarAttributesChanged(int displayId, int behavior)312         public void onSystemBarAttributesChanged(int displayId, int behavior) {
313             executeForTaskbarManager(() -> mTaskbarManager
314                     .onSystemBarAttributesChanged(displayId, behavior));
315         }
316 
317         @Override
onNavButtonsDarkIntensityChanged(float darkIntensity)318         public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
319             executeForTaskbarManager(() -> mTaskbarManager
320                     .onNavButtonsDarkIntensityChanged(darkIntensity));
321         }
322 
executeForTaskbarManager(final Runnable r)323         private void executeForTaskbarManager(final Runnable r) {
324             MAIN_EXECUTOR.execute(() -> {
325                 if (mTaskbarManager == null) {
326                     return;
327                 }
328                 r.run();
329             });
330         }
331 
getTaskbarManager()332         public TaskbarManager getTaskbarManager() {
333             return mTaskbarManager;
334         }
335 
getOverviewCommandHelper()336         public OverviewCommandHelper getOverviewCommandHelper() {
337             return mOverviewCommandHelper;
338         }
339 
340         /**
341          * Sets a proxy to bypass swipe up behavior
342          */
setSwipeUpProxy(Function<GestureState, AnimatedFloat> proxy)343         public void setSwipeUpProxy(Function<GestureState, AnimatedFloat> proxy) {
344             mSwipeUpProxyProvider = proxy != null ? proxy : (i -> null);
345         }
346 
347         /**
348          * Sets the task id where gestures should be blocked
349          */
setGestureBlockedTaskId(int taskId)350         public void setGestureBlockedTaskId(int taskId) {
351             mDeviceState.setGestureBlockingTaskId(taskId);
352         }
353 
354         /** Sets a listener to be run on Overview Target updates. */
setOverviewTargetChangeListener(@ullable Runnable listener)355         public void setOverviewTargetChangeListener(@Nullable Runnable listener) {
356             mOnOverviewTargetChangeListener = listener;
357         }
358 
onOverviewTargetChange()359         protected void onOverviewTargetChange() {
360             if (mOnOverviewTargetChangeListener != null) {
361                 mOnOverviewTargetChangeListener.run();
362                 mOnOverviewTargetChangeListener = null;
363             }
364         }
365     }
366 
367     private static boolean sConnected = false;
368     private static boolean sIsInitialized = false;
369     private RotationTouchHelper mRotationTouchHelper;
370 
isConnected()371     public static boolean isConnected() {
372         return sConnected;
373     }
374 
isInitialized()375     public static boolean isInitialized() {
376         return sIsInitialized;
377     }
378 
379     private final AbsSwipeUpHandler.Factory mLauncherSwipeHandlerFactory =
380             this::createLauncherSwipeHandler;
381     private final AbsSwipeUpHandler.Factory mFallbackSwipeHandlerFactory =
382             this::createFallbackSwipeHandler;
383 
384     private ActivityManagerWrapper mAM;
385     private OverviewCommandHelper mOverviewCommandHelper;
386     private OverviewComponentObserver mOverviewComponentObserver;
387     private InputConsumerController mInputConsumer;
388     private RecentsAnimationDeviceState mDeviceState;
389     private TaskAnimationManager mTaskAnimationManager;
390 
391     private @NonNull InputConsumer mUncheckedConsumer = InputConsumer.NO_OP;
392     private @NonNull InputConsumer mConsumer = InputConsumer.NO_OP;
393     private Choreographer mMainChoreographer;
394     private @Nullable ResetGestureInputConsumer mResetGestureInputConsumer;
395     private GestureState mGestureState = DEFAULT_STATE;
396 
397     private InputMonitorCompat mInputMonitorCompat;
398     private InputEventReceiver mInputEventReceiver;
399 
400     private TaskbarManager mTaskbarManager;
401     private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = i -> null;
402 
403     @Override
onCreate()404     public void onCreate() {
405         super.onCreate();
406         // Initialize anything here that is needed in direct boot mode.
407         // Everything else should be initialized in onUserUnlocked() below.
408         mMainChoreographer = Choreographer.getInstance();
409         mAM = ActivityManagerWrapper.getInstance();
410         mDeviceState = new RecentsAnimationDeviceState(this, true);
411         mTaskbarManager = new TaskbarManager(this);
412         mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
413         BootAwarePreloader.start(this);
414 
415         // Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
416         mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
417         mDeviceState.runOnUserUnlocked(mTaskbarManager::onUserUnlocked);
418         mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
419 
420         ProtoTracer.INSTANCE.get(this).add(this);
421         sConnected = true;
422     }
423 
disposeEventHandlers(String reason)424     private void disposeEventHandlers(String reason) {
425         Log.d(TAG, "disposeEventHandlers: Reason: " + reason);
426         if (mInputEventReceiver != null) {
427             mInputEventReceiver.dispose();
428             mInputEventReceiver = null;
429         }
430         if (mInputMonitorCompat != null) {
431             mInputMonitorCompat.dispose();
432             mInputMonitorCompat = null;
433         }
434     }
435 
initInputMonitor(String reason)436     private void initInputMonitor(String reason) {
437         disposeEventHandlers("Initializing input monitor due to: " + reason);
438 
439         if (mDeviceState.isButtonNavMode()) {
440             return;
441         }
442 
443         mInputMonitorCompat = new InputMonitorCompat("swipe-up", mDeviceState.getDisplayId());
444         mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
445                 mMainChoreographer, this::onInputEvent);
446 
447         mRotationTouchHelper.updateGestureTouchRegions();
448     }
449 
450     /**
451      * Called when the navigation mode changes, guaranteed to be after the device state has updated.
452      */
onNavigationModeChanged()453     private void onNavigationModeChanged() {
454         initInputMonitor("onNavigationModeChanged()");
455         resetHomeBounceSeenOnQuickstepEnabledFirstTime();
456     }
457 
458     @UiThread
onUserUnlocked()459     public void onUserUnlocked() {
460         mTaskAnimationManager = new TaskAnimationManager(this);
461         mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
462         mOverviewCommandHelper = new OverviewCommandHelper(this,
463                 mOverviewComponentObserver, mTaskAnimationManager);
464         mResetGestureInputConsumer = new ResetGestureInputConsumer(
465                 mTaskAnimationManager, mTaskbarManager::getCurrentActivityContext);
466         mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
467         mInputConsumer.registerInputConsumer();
468         onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags());
469         onAssistantVisibilityChanged();
470 
471         // Initialize the task tracker
472         TopTaskTracker.INSTANCE.get(this);
473 
474         // Temporarily disable model preload
475         // new ModelPreload().start(this);
476         resetHomeBounceSeenOnQuickstepEnabledFirstTime();
477 
478         mOverviewComponentObserver.setOverviewChangeListener(this::onOverviewTargetChange);
479         onOverviewTargetChange(mOverviewComponentObserver.isHomeAndOverviewSame());
480     }
481 
getOverviewCommandHelper()482     public OverviewCommandHelper getOverviewCommandHelper() {
483         return mOverviewCommandHelper;
484     }
485 
resetHomeBounceSeenOnQuickstepEnabledFirstTime()486     private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
487         if (!mDeviceState.isUserUnlocked() || mDeviceState.isButtonNavMode()) {
488             // Skip if not yet unlocked (can't read user shared prefs) or if the current navigation
489             // mode doesn't have gestures
490             return;
491         }
492 
493         // Reset home bounce seen on quick step enabled for first time
494         SharedPreferences sharedPrefs = LauncherPrefs.getPrefs(this);
495         if (!sharedPrefs.getBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)) {
496             sharedPrefs.edit()
497                     .putBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)
498                     .putBoolean(OnboardingPrefs.HOME_BOUNCE_SEEN, false)
499                     .apply();
500         }
501     }
502 
onOverviewTargetChange(boolean isHomeAndOverviewSame)503     private void onOverviewTargetChange(boolean isHomeAndOverviewSame) {
504         AccessibilityManager am = getSystemService(AccessibilityManager.class);
505 
506         if (isHomeAndOverviewSame) {
507             Intent intent = new Intent(mOverviewComponentObserver.getHomeIntent())
508                     .setAction(Intent.ACTION_ALL_APPS);
509             RemoteAction allAppsAction = new RemoteAction(
510                     Icon.createWithResource(this, R.drawable.ic_apps),
511                     getString(R.string.all_apps_label),
512                     getString(R.string.all_apps_label),
513                     PendingIntent.getActivity(this, GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS, intent,
514                             PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE));
515             am.registerSystemAction(allAppsAction, GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
516         } else {
517             am.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
518         }
519 
520         StatefulActivity newOverviewActivity = mOverviewComponentObserver.getActivityInterface()
521                 .getCreatedActivity();
522         if (newOverviewActivity != null) {
523             mTaskbarManager.setActivity(newOverviewActivity);
524         }
525         mTISBinder.onOverviewTargetChange();
526     }
527 
528     @UiThread
onSystemUiFlagsChanged(int lastSysUIFlags)529     private void onSystemUiFlagsChanged(int lastSysUIFlags) {
530         if (mDeviceState.isUserUnlocked()) {
531             int systemUiStateFlags = mDeviceState.getSystemUiStateFlags();
532             SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags);
533             mOverviewComponentObserver.onSystemUiStateChanged();
534             mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags);
535 
536             boolean wasFreeformActive =
537                     (lastSysUIFlags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0;
538             boolean isFreeformActive =
539                     (systemUiStateFlags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0;
540             if (wasFreeformActive != isFreeformActive) {
541                 DesktopVisibilityController controller =
542                         LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
543                 if (controller != null) {
544                     controller.setFreeformTasksVisible(isFreeformActive);
545                 }
546             }
547 
548             int isShadeExpandedFlag =
549                     SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
550             boolean wasExpanded = (lastSysUIFlags & isShadeExpandedFlag) != 0;
551             boolean isExpanded = (systemUiStateFlags & isShadeExpandedFlag) != 0;
552             if (wasExpanded != isExpanded && isExpanded) {
553                 // End live tile when expanding the notification panel for the first time from
554                 // overview.
555                 mTaskAnimationManager.endLiveTile();
556             }
557 
558             if ((lastSysUIFlags & SYSUI_STATE_TRACING_ENABLED) !=
559                     (systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED)) {
560                 // Update the tracing state
561                 if ((systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED) != 0) {
562                     Log.d(TAG, "Starting tracing.");
563                     ProtoTracer.INSTANCE.get(this).start();
564                 } else {
565                     Log.d(TAG, "Stopping tracing. Dumping to file="
566                             + ProtoTracer.INSTANCE.get(this).getTraceFile());
567                     ProtoTracer.INSTANCE.get(this).stop();
568                 }
569             }
570         }
571     }
572 
573     @UiThread
onAssistantVisibilityChanged()574     private void onAssistantVisibilityChanged() {
575         if (mDeviceState.isUserUnlocked()) {
576             mOverviewComponentObserver.getActivityInterface().onAssistantVisibilityChanged(
577                     mDeviceState.getAssistantVisibility());
578         }
579     }
580 
581     @Override
onDestroy()582     public void onDestroy() {
583         Log.d(TAG, "Touch service destroyed: user=" + getUserId());
584         sIsInitialized = false;
585         if (mDeviceState.isUserUnlocked()) {
586             mInputConsumer.unregisterInputConsumer();
587             mOverviewComponentObserver.onDestroy();
588         }
589         disposeEventHandlers("TouchInteractionService onDestroy()");
590         mDeviceState.destroy();
591         SystemUiProxy.INSTANCE.get(this).clearProxy();
592         ProtoTracer.INSTANCE.get(this).stop();
593         ProtoTracer.INSTANCE.get(this).remove(this);
594 
595         getSystemService(AccessibilityManager.class)
596                 .unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
597 
598         mTaskbarManager.destroy();
599         sConnected = false;
600         super.onDestroy();
601     }
602 
603     @Override
onBind(Intent intent)604     public IBinder onBind(Intent intent) {
605         Log.d(TAG, "Touch service connected: user=" + getUserId());
606         return mTISBinder;
607     }
608 
onInputEvent(InputEvent ev)609     private void onInputEvent(InputEvent ev) {
610         if (!(ev instanceof MotionEvent)) {
611             Log.e(TAG, "Unknown event " + ev);
612             return;
613         }
614         MotionEvent event = (MotionEvent) ev;
615 
616         TestLogging.recordMotionEvent(
617                 TestProtocol.SEQUENCE_TIS, "TouchInteractionService.onInputEvent", event);
618 
619         if (!mDeviceState.isUserUnlocked()) {
620             return;
621         }
622 
623         Object traceToken = TraceHelper.INSTANCE.beginFlagsOverride(
624                 TraceHelper.FLAG_ALLOW_BINDER_TRACKING);
625 
626         final int action = event.getAction();
627         if (action == ACTION_DOWN) {
628             mRotationTouchHelper.setOrientationTransformIfNeeded(event);
629 
630             if (!mDeviceState.isOneHandedModeActive()
631                     && mRotationTouchHelper.isInSwipeUpTouchRegion(event)) {
632                 // Clone the previous gesture state since onConsumerAboutToBeSwitched might trigger
633                 // onConsumerInactive and wipe the previous gesture state
634                 GestureState prevGestureState = new GestureState(mGestureState);
635                 GestureState newGestureState = createGestureState(mGestureState);
636                 newGestureState.setSwipeUpStartTimeMs(SystemClock.uptimeMillis());
637                 mConsumer.onConsumerAboutToBeSwitched();
638                 mGestureState = newGestureState;
639                 mConsumer = newConsumer(prevGestureState, mGestureState, event);
640                 mUncheckedConsumer = mConsumer;
641             } else if (mDeviceState.isUserUnlocked() && mDeviceState.isFullyGesturalNavMode()
642                     && mDeviceState.canTriggerAssistantAction(event)) {
643                 mGestureState = createGestureState(mGestureState);
644                 // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
645                 // should not interrupt it. QuickSwitch assumes that interruption can only
646                 // happen if the next gesture is also quick switch.
647                 mUncheckedConsumer = tryCreateAssistantInputConsumer(mGestureState, event);
648             } else if (mDeviceState.canTriggerOneHandedAction(event)) {
649                 // Consume gesture event for triggering one handed feature.
650                 mUncheckedConsumer = new OneHandedModeInputConsumer(this, mDeviceState,
651                         InputConsumer.NO_OP, mInputMonitorCompat);
652             } else {
653                 mUncheckedConsumer = InputConsumer.NO_OP;
654             }
655         } else {
656             // Other events
657             if (mUncheckedConsumer != InputConsumer.NO_OP) {
658                 // Only transform the event if we are handling it in a proper consumer
659                 mRotationTouchHelper.setOrientationTransformIfNeeded(event);
660             }
661         }
662 
663         if (mUncheckedConsumer != InputConsumer.NO_OP) {
664             switch (event.getActionMasked()) {
665                 case ACTION_DOWN:
666                 case ACTION_UP:
667                     ActiveGestureLog.INSTANCE.addLog(
668                             /* event= */ "onMotionEvent(" + (int) event.getRawX() + ", "
669                                     + (int) event.getRawY() + "): "
670                                     + MotionEvent.actionToString(event.getActionMasked()),
671                             /* gestureEvent= */ event.getActionMasked() == ACTION_DOWN
672                                     ? MOTION_DOWN
673                                     : MOTION_UP);
674                     break;
675                 default:
676                     ActiveGestureLog.INSTANCE.addLog("onMotionEvent: "
677                             + MotionEvent.actionToString(event.getActionMasked()));
678                     break;
679             }
680         }
681 
682         boolean cancelGesture = mGestureState.getActivityInterface() != null
683                 && mGestureState.getActivityInterface().shouldCancelCurrentGesture();
684         boolean cleanUpConsumer = (action == ACTION_UP || action == ACTION_CANCEL || cancelGesture)
685                 && mConsumer != null
686                 && !mConsumer.getActiveConsumerInHierarchy().isConsumerDetachedFromGesture();
687         if (cancelGesture) {
688             event.setAction(ACTION_CANCEL);
689         }
690         mUncheckedConsumer.onMotionEvent(event);
691 
692         if (cleanUpConsumer) {
693             reset();
694         }
695         TraceHelper.INSTANCE.endFlagsOverride(traceToken);
696         ProtoTracer.INSTANCE.get(this).scheduleFrameUpdate();
697     }
698 
tryCreateAssistantInputConsumer( GestureState gestureState, MotionEvent motionEvent)699     private InputConsumer tryCreateAssistantInputConsumer(
700             GestureState gestureState, MotionEvent motionEvent) {
701         return tryCreateAssistantInputConsumer(
702                 InputConsumer.NO_OP, gestureState, motionEvent, CompoundString.NO_OP);
703     }
704 
tryCreateAssistantInputConsumer( InputConsumer base, GestureState gestureState, MotionEvent motionEvent, CompoundString reasonString)705     private InputConsumer tryCreateAssistantInputConsumer(
706             InputConsumer base,
707             GestureState gestureState,
708             MotionEvent motionEvent,
709             CompoundString reasonString) {
710         if (mDeviceState.isGestureBlockedTask(gestureState.getRunningTask())) {
711             reasonString.append(SUBSTRING_PREFIX)
712                     .append("is gesture-blocked task, using base input consumer");
713             return base;
714         } else {
715             reasonString.append(SUBSTRING_PREFIX).append("using AssistantInputConsumer");
716             return new AssistantInputConsumer(
717                     this, gestureState, base, mInputMonitorCompat, mDeviceState, motionEvent);
718         }
719     }
720 
createGestureState(GestureState previousGestureState)721     public GestureState createGestureState(GestureState previousGestureState) {
722         final GestureState gestureState;
723         TopTaskTracker.CachedTaskInfo taskInfo;
724         if (mTaskAnimationManager.isRecentsAnimationRunning()) {
725             gestureState = new GestureState(mOverviewComponentObserver,
726                     ActiveGestureLog.INSTANCE.getLogId());
727             taskInfo = previousGestureState.getRunningTask();
728             gestureState.updateRunningTask(taskInfo);
729             gestureState.updateLastStartedTaskId(previousGestureState.getLastStartedTaskId());
730             gestureState.updatePreviouslyAppearedTaskIds(
731                     previousGestureState.getPreviouslyAppearedTaskIds());
732         } else {
733             gestureState = new GestureState(mOverviewComponentObserver,
734                     ActiveGestureLog.INSTANCE.incrementLogId());
735             taskInfo = TopTaskTracker.INSTANCE.get(this).getCachedTopTask(false);
736             gestureState.updateRunningTask(taskInfo);
737         }
738         // Log initial state for the gesture.
739         ActiveGestureLog.INSTANCE.addLog(new CompoundString("Current running task package name=")
740                 .append(taskInfo == null ? "no running task" : taskInfo.getPackageName()));
741         ActiveGestureLog.INSTANCE.addLog(new CompoundString("Current SystemUi state flags=")
742                 .append(mDeviceState.getSystemUiStateString()));
743         return gestureState;
744     }
745 
newConsumer( GestureState previousGestureState, GestureState newGestureState, MotionEvent event)746     private InputConsumer newConsumer(
747             GestureState previousGestureState, GestureState newGestureState, MotionEvent event) {
748         AnimatedFloat progressProxy = mSwipeUpProxyProvider.apply(mGestureState);
749         if (progressProxy != null) {
750             InputConsumer consumer = new ProgressDelegateInputConsumer(
751                     this, mTaskAnimationManager, mGestureState, mInputMonitorCompat, progressProxy);
752 
753             logInputConsumerSelectionReason(consumer, newCompoundString(
754                     "mSwipeUpProxyProvider has been set, using ProgressDelegateInputConsumer"));
755 
756             return consumer;
757         }
758 
759         boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
760 
761         if (!mDeviceState.isUserUnlocked()) {
762             CompoundString reasonString = newCompoundString("device locked");
763             InputConsumer consumer;
764             if (canStartSystemGesture) {
765                 // This handles apps launched in direct boot mode (e.g. dialer) as well as apps
766                 // launched while device is locked even after exiting direct boot mode (e.g. camera).
767                 consumer = createDeviceLockedInputConsumer(
768                         newGestureState, reasonString.append(SUBSTRING_PREFIX)
769                                 .append("can start system gesture"));
770             } else {
771                 consumer = getDefaultInputConsumer(
772                         reasonString.append(SUBSTRING_PREFIX)
773                                 .append("cannot start system gesture"));
774             }
775             logInputConsumerSelectionReason(consumer, reasonString);
776             return consumer;
777         }
778 
779         CompoundString reasonString;
780         InputConsumer base;
781         // When there is an existing recents animation running, bypass systemState check as this is
782         // a followup gesture and the first gesture started in a valid system state.
783         if (canStartSystemGesture || previousGestureState.isRecentsAnimationRunning()) {
784             reasonString = newCompoundString(canStartSystemGesture
785                     ? "can start system gesture" : "recents animation was running")
786                     .append(", trying to use base consumer");
787             base = newBaseConsumer(previousGestureState, newGestureState, event, reasonString);
788         } else {
789             reasonString = newCompoundString(
790                     "cannot start system gesture and recents animation was not running")
791                     .append(", trying to use default input consumer");
792             base = getDefaultInputConsumer(reasonString);
793         }
794         if (mDeviceState.isGesturalNavMode()) {
795             handleOrientationSetup(base);
796         }
797         if (mDeviceState.isFullyGesturalNavMode()) {
798             String reasonPrefix = "device is in gesture navigation mode";
799             if (mDeviceState.canTriggerAssistantAction(event)) {
800                 reasonString.append(NEWLINE_PREFIX)
801                         .append(reasonPrefix)
802                         .append(SUBSTRING_PREFIX)
803                         .append("gesture can trigger the assistant")
804                         .append(", trying to use assistant input consumer");
805                 base = tryCreateAssistantInputConsumer(base, newGestureState, event, reasonString);
806             }
807 
808             // If Taskbar is present, we listen for long press to unstash it.
809             TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
810             if (tac != null && canStartSystemGesture) {
811                 reasonString.append(NEWLINE_PREFIX)
812                         .append(reasonPrefix)
813                         .append(SUBSTRING_PREFIX)
814                         .append("TaskbarActivityContext != null, using TaskbarStashInputConsumer");
815                 base = new TaskbarStashInputConsumer(this, base, mInputMonitorCompat, tac);
816             }
817 
818             if (mDeviceState.isBubblesExpanded()) {
819                 reasonString = newCompoundString(reasonPrefix)
820                         .append(SUBSTRING_PREFIX)
821                         .append("bubbles expanded, trying to use default input consumer");
822                 // Bubbles can handle home gesture itself.
823                 base = getDefaultInputConsumer(reasonString);
824             }
825 
826             if (mDeviceState.isSystemUiDialogShowing()) {
827                 reasonString = newCompoundString(reasonPrefix)
828                         .append(SUBSTRING_PREFIX)
829                         .append("system dialog is showing, using SysUiOverlayInputConsumer");
830                 base = new SysUiOverlayInputConsumer(
831                         getBaseContext(), mDeviceState, mInputMonitorCompat);
832             }
833 
834 
835 
836             if (mDeviceState.isScreenPinningActive()) {
837                 reasonString = newCompoundString(reasonPrefix)
838                         .append(SUBSTRING_PREFIX)
839                         .append("screen pinning is active, using ScreenPinnedInputConsumer");
840                 // Note: we only allow accessibility to wrap this, and it replaces the previous
841                 // base input consumer (which should be NO_OP anyway since topTaskLocked == true).
842                 base = new ScreenPinnedInputConsumer(this, newGestureState);
843             }
844 
845             if (mDeviceState.canTriggerOneHandedAction(event)) {
846                 reasonString.append(NEWLINE_PREFIX)
847                         .append(reasonPrefix)
848                         .append(SUBSTRING_PREFIX)
849                         .append("gesture can trigger one handed mode")
850                         .append(", using OneHandedModeInputConsumer");
851                 base = new OneHandedModeInputConsumer(
852                         this, mDeviceState, base, mInputMonitorCompat);
853             }
854 
855             if (mDeviceState.isAccessibilityMenuAvailable()) {
856                 reasonString.append(NEWLINE_PREFIX)
857                         .append(reasonPrefix)
858                         .append(SUBSTRING_PREFIX)
859                         .append("accessibility menu is available")
860                         .append(", using AccessibilityInputConsumer");
861                 base = new AccessibilityInputConsumer(
862                         this, mDeviceState, base, mInputMonitorCompat);
863             }
864         } else {
865             String reasonPrefix = "device is not in gesture navigation mode";
866             if (mDeviceState.isScreenPinningActive()) {
867                 reasonString = newCompoundString(reasonPrefix)
868                         .append(SUBSTRING_PREFIX)
869                         .append("screen pinning is active, trying to use default input consumer");
870                 base = getDefaultInputConsumer(reasonString);
871             }
872 
873             if (mDeviceState.canTriggerOneHandedAction(event)) {
874                 reasonString.append(NEWLINE_PREFIX)
875                         .append(reasonPrefix)
876                         .append(SUBSTRING_PREFIX)
877                         .append("gesture can trigger one handed mode")
878                         .append(", using OneHandedModeInputConsumer");
879                 base = new OneHandedModeInputConsumer(
880                         this, mDeviceState, base, mInputMonitorCompat);
881             }
882         }
883         logInputConsumerSelectionReason(base, reasonString);
884         return base;
885     }
886 
newCompoundString(String substring)887     private CompoundString newCompoundString(String substring) {
888         return new CompoundString(NEWLINE_PREFIX).append(substring);
889     }
890 
logInputConsumerSelectionReason( InputConsumer consumer, CompoundString reasonString)891     private void logInputConsumerSelectionReason(
892             InputConsumer consumer, CompoundString reasonString) {
893         if (!FeatureFlags.ENABLE_INPUT_CONSUMER_REASON_LOGGING.get()) {
894             ActiveGestureLog.INSTANCE.addLog("setInputConsumer: " + consumer.getName());
895             return;
896         }
897         ActiveGestureLog.INSTANCE.addLog(new CompoundString("setInputConsumer: ")
898                 .append(consumer.getName())
899                 .append(". reason(s):")
900                 .append(reasonString));
901         if ((consumer.getType() & InputConsumer.TYPE_OTHER_ACTIVITY) != 0) {
902             ActiveGestureLog.INSTANCE.trackEvent(FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER);
903         }
904     }
905 
handleOrientationSetup(InputConsumer baseInputConsumer)906     private void handleOrientationSetup(InputConsumer baseInputConsumer) {
907         baseInputConsumer.notifyOrientationSetup();
908     }
909 
newBaseConsumer( GestureState previousGestureState, GestureState gestureState, MotionEvent event, CompoundString reasonString)910     private InputConsumer newBaseConsumer(
911             GestureState previousGestureState,
912             GestureState gestureState,
913             MotionEvent event,
914             CompoundString reasonString) {
915         if (mDeviceState.isKeyguardShowingOccluded()) {
916             // This handles apps showing over the lockscreen (e.g. camera)
917             return createDeviceLockedInputConsumer(
918                     gestureState,
919                     reasonString.append(SUBSTRING_PREFIX)
920                             .append("keyguard is showing occluded")
921                             .append(", trying to use device locked input consumer"));
922         }
923 
924         reasonString.append(SUBSTRING_PREFIX).append("keyguard is not showing occluded");
925         // Use overview input consumer for sharesheets on top of home.
926         boolean forceOverviewInputConsumer = gestureState.getActivityInterface().isStarted()
927                 && gestureState.getRunningTask() != null
928                 && gestureState.getRunningTask().isRootChooseActivity();
929         if (gestureState.getRunningTask() != null
930                 && gestureState.getRunningTask().isExcludedAssistant()) {
931             // In the case where we are in the excluded assistant state, ignore it and treat the
932             // running activity as the task behind the assistant
933             gestureState.updateRunningTask(TopTaskTracker.INSTANCE.get(this)
934                     .getCachedTopTask(true /* filterOnlyVisibleRecents */));
935             forceOverviewInputConsumer = gestureState.getRunningTask().isHomeTask();
936         }
937 
938         boolean previousGestureAnimatedToLauncher =
939                 previousGestureState.isRunningAnimationToLauncher();
940         // with shell-transitions, home is resumed during recents animation, so
941         // explicitly check against recents animation too.
942         boolean launcherResumedThroughShellTransition =
943                 gestureState.getActivityInterface().isResumed()
944                         && !previousGestureState.isRecentsAnimationRunning();
945         if (gestureState.getActivityInterface().isInLiveTileMode()) {
946             return createOverviewInputConsumer(
947                     previousGestureState,
948                     gestureState,
949                     event,
950                     forceOverviewInputConsumer,
951                     reasonString.append(SUBSTRING_PREFIX)
952                             .append("is in live tile mode, trying to use overview input consumer"));
953         } else if (gestureState.getRunningTask() == null) {
954             return getDefaultInputConsumer(reasonString.append(SUBSTRING_PREFIX)
955                     .append("running task == null"));
956         } else if (previousGestureAnimatedToLauncher
957                 || launcherResumedThroughShellTransition
958                 || forceOverviewInputConsumer) {
959             return createOverviewInputConsumer(
960                     previousGestureState,
961                     gestureState,
962                     event,
963                     forceOverviewInputConsumer,
964                     reasonString.append(SUBSTRING_PREFIX)
965                             .append(previousGestureAnimatedToLauncher
966                                     ? "previous gesture animated to launcher"
967                                     : (launcherResumedThroughShellTransition
968                                             ? "launcher resumed through a shell transition"
969                                             : "forceOverviewInputConsumer == true"))
970                             .append(", trying to use overview input consumer"));
971         } else if (mDeviceState.isGestureBlockedTask(gestureState.getRunningTask())) {
972             return getDefaultInputConsumer(reasonString.append(SUBSTRING_PREFIX)
973                     .append("is gesture-blocked task, trying to use default input consumer"));
974         } else {
975             reasonString.append(SUBSTRING_PREFIX)
976                     .append("using OtherActivityInputConsumer");
977             return createOtherActivityInputConsumer(gestureState, event);
978         }
979     }
980 
getSwipeUpHandlerFactory()981     public AbsSwipeUpHandler.Factory getSwipeUpHandlerFactory() {
982         return !mOverviewComponentObserver.isHomeAndOverviewSame()
983                 ? mFallbackSwipeHandlerFactory : mLauncherSwipeHandlerFactory;
984     }
985 
createOtherActivityInputConsumer(GestureState gestureState, MotionEvent event)986     private InputConsumer createOtherActivityInputConsumer(GestureState gestureState,
987             MotionEvent event) {
988 
989         final AbsSwipeUpHandler.Factory factory = getSwipeUpHandlerFactory();
990         final boolean shouldDefer = !mOverviewComponentObserver.isHomeAndOverviewSame()
991                 || gestureState.getActivityInterface().deferStartingActivity(mDeviceState, event);
992         final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
993         return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
994                 gestureState, shouldDefer, this::onConsumerInactive,
995                 mInputMonitorCompat, mInputEventReceiver, disableHorizontalSwipe, factory);
996     }
997 
createDeviceLockedInputConsumer( GestureState gestureState, CompoundString reasonString)998     private InputConsumer createDeviceLockedInputConsumer(
999             GestureState gestureState, CompoundString reasonString) {
1000         if (mDeviceState.isFullyGesturalNavMode() && gestureState.getRunningTask() != null) {
1001             reasonString.append(SUBSTRING_PREFIX)
1002                     .append("device is in gesture nav mode and running task != null")
1003                     .append(", using DeviceLockedInputConsumer");
1004             return new DeviceLockedInputConsumer(
1005                     this, mDeviceState, mTaskAnimationManager, gestureState, mInputMonitorCompat);
1006         } else {
1007             return getDefaultInputConsumer(reasonString
1008                     .append(SUBSTRING_PREFIX)
1009                     .append(mDeviceState.isFullyGesturalNavMode()
1010                         ? "running task == null" : "device is not in gesture nav mode")
1011                     .append(", trying to use default input consumer"));
1012         }
1013     }
1014 
createOverviewInputConsumer( GestureState previousGestureState, GestureState gestureState, MotionEvent event, boolean forceOverviewInputConsumer, CompoundString reasonString)1015     public InputConsumer createOverviewInputConsumer(
1016             GestureState previousGestureState,
1017             GestureState gestureState,
1018             MotionEvent event,
1019             boolean forceOverviewInputConsumer,
1020             CompoundString reasonString) {
1021         StatefulActivity activity = gestureState.getActivityInterface().getCreatedActivity();
1022         if (activity == null) {
1023             return getDefaultInputConsumer(
1024                     reasonString.append(SUBSTRING_PREFIX)
1025                             .append("activity == null, trying to use default input consumer"));
1026         }
1027 
1028         boolean hasWindowFocus = activity.getRootView().hasWindowFocus();
1029         boolean isPreviousGestureAnimatingToLauncher =
1030                 previousGestureState.isRunningAnimationToLauncher();
1031         boolean forcingOverviewInputConsumer =
1032                 ASSISTANT_GIVES_LAUNCHER_FOCUS.get() && forceOverviewInputConsumer;
1033         boolean isInLiveTileMode = gestureState.getActivityInterface().isInLiveTileMode();
1034         reasonString.append(SUBSTRING_PREFIX)
1035                 .append(hasWindowFocus
1036                         ? "activity has window focus"
1037                         : (isPreviousGestureAnimatingToLauncher
1038                                 ? "previous gesture is still animating to launcher"
1039                                 : (forcingOverviewInputConsumer
1040                                         ? "assistant gives launcher focus and forcing focus"
1041                                         : (isInLiveTileMode
1042                                                 ? "device is in live mode"
1043                                                 : "all overview focus conditions failed"))));
1044         if (hasWindowFocus
1045                 || isPreviousGestureAnimatingToLauncher
1046                 || forcingOverviewInputConsumer
1047                 || isInLiveTileMode) {
1048             reasonString.append(SUBSTRING_PREFIX)
1049                     .append("overview should have focus, using OverviewInputConsumer");
1050             return new OverviewInputConsumer(gestureState, activity, mInputMonitorCompat,
1051                     false /* startingInActivityBounds */);
1052         } else {
1053             reasonString.append(SUBSTRING_PREFIX).append(
1054                     "overview shouldn't have focus, using OverviewWithoutFocusInputConsumer");
1055             final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
1056             return new OverviewWithoutFocusInputConsumer(activity, mDeviceState, gestureState,
1057                     mInputMonitorCompat, disableHorizontalSwipe);
1058         }
1059     }
1060 
1061     /**
1062      * To be called by the consumer when it's no longer active. This can be called by any consumer
1063      * in the hierarchy at any point during the gesture (ie. if a delegate consumer starts
1064      * intercepting touches, the base consumer can try to call this).
1065      */
onConsumerInactive(InputConsumer caller)1066     private void onConsumerInactive(InputConsumer caller) {
1067         if (mConsumer != null && mConsumer.getActiveConsumerInHierarchy() == caller) {
1068             reset();
1069         }
1070     }
1071 
reset()1072     private void reset() {
1073         mConsumer = mUncheckedConsumer = getDefaultInputConsumer();
1074         mGestureState = DEFAULT_STATE;
1075         // By default, use batching of the input events, but check receiver before using in the rare
1076         // case that the monitor was disposed before the swipe settled
1077         if (mInputEventReceiver != null) {
1078             mInputEventReceiver.setBatchingEnabled(true);
1079         }
1080     }
1081 
getDefaultInputConsumer()1082     private @NonNull InputConsumer getDefaultInputConsumer() {
1083         return getDefaultInputConsumer(CompoundString.NO_OP);
1084     }
1085 
1086     /**
1087      * Returns the {@link ResetGestureInputConsumer} if user is unlocked, else NO_OP.
1088      */
getDefaultInputConsumer(@onNull CompoundString reasonString)1089     private @NonNull InputConsumer getDefaultInputConsumer(@NonNull CompoundString reasonString) {
1090         if (mResetGestureInputConsumer != null) {
1091             reasonString.append(SUBSTRING_PREFIX).append(
1092                     "mResetGestureInputConsumer initialized, using ResetGestureInputConsumer");
1093             return mResetGestureInputConsumer;
1094         } else {
1095             reasonString.append(SUBSTRING_PREFIX).append(
1096                     "mResetGestureInputConsumer not initialized, using no-op input consumer");
1097             // mResetGestureInputConsumer isn't initialized until onUserUnlocked(), so reset to
1098             // NO_OP until then (we never want these to be null).
1099             return InputConsumer.NO_OP;
1100         }
1101     }
1102 
preloadOverview(boolean fromInit)1103     private void preloadOverview(boolean fromInit) {
1104         preloadOverview(fromInit, false);
1105     }
1106 
preloadOverview(boolean fromInit, boolean forSUWAllSet)1107     private void preloadOverview(boolean fromInit, boolean forSUWAllSet) {
1108         if (!mDeviceState.isUserUnlocked()) {
1109             return;
1110         }
1111 
1112         if (mDeviceState.isButtonNavMode() && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
1113             // Prevent the overview from being started before the real home on first boot.
1114             return;
1115         }
1116 
1117         if ((RestoreDbTask.isPending(this) && !forSUWAllSet)
1118                 || !mDeviceState.isUserSetupComplete()) {
1119             // Preloading while a restore is pending may cause launcher to start the restore
1120             // too early.
1121             return;
1122         }
1123 
1124         final BaseActivityInterface activityInterface =
1125                 mOverviewComponentObserver.getActivityInterface();
1126         final Intent overviewIntent = new Intent(
1127                 mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState());
1128         if (activityInterface.getCreatedActivity() != null && fromInit) {
1129             // The activity has been created before the initialization of overview service. It is
1130             // usually happens when booting or launcher is the top activity, so we should already
1131             // have the latest state.
1132             return;
1133         }
1134 
1135         // TODO(b/258022658): Remove temporary logging.
1136         Log.i(TAG, "preloadOverview: forSUWAllSet=" + forSUWAllSet
1137                 + ", isHomeAndOverviewSame=" + mOverviewComponentObserver.isHomeAndOverviewSame());
1138 
1139         mTaskAnimationManager.preloadRecentsAnimation(overviewIntent);
1140     }
1141 
1142     @Override
onConfigurationChanged(Configuration newConfig)1143     public void onConfigurationChanged(Configuration newConfig) {
1144         if (!mDeviceState.isUserUnlocked()) {
1145             return;
1146         }
1147         final BaseActivityInterface activityInterface =
1148                 mOverviewComponentObserver.getActivityInterface();
1149         final BaseDraggingActivity activity = activityInterface.getCreatedActivity();
1150         if (activity == null || activity.isStarted()) {
1151             // We only care about the existing background activity.
1152             return;
1153         }
1154         if (mOverviewComponentObserver.canHandleConfigChanges(activity.getComponentName(),
1155                 activity.getResources().getConfiguration().diff(newConfig))) {
1156             // Since navBar gestural height are different between portrait and landscape,
1157             // can handle orientation changes and refresh navigation gestural region through
1158             // onOneHandedModeChanged()
1159             int newGesturalHeight = ResourceUtils.getNavbarSize(
1160                     ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE,
1161                     getApplicationContext().getResources());
1162             mDeviceState.onOneHandedModeChanged(newGesturalHeight);
1163             return;
1164         }
1165 
1166         preloadOverview(false /* fromInit */);
1167     }
1168 
1169     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs)1170     protected void dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs) {
1171         if (rawArgs.length > 0 && Utilities.IS_DEBUG_DEVICE) {
1172             LinkedList<String> args = new LinkedList(Arrays.asList(rawArgs));
1173             switch (args.pollFirst()) {
1174                 case "cmd":
1175                     if (args.peekFirst() == null) {
1176                         printAvailableCommands(pw);
1177                     } else {
1178                         onCommand(pw, args);
1179                     }
1180                     break;
1181             }
1182         } else {
1183             // Dump everything
1184             FlagsFactory.dump(pw);
1185             if (mDeviceState.isUserUnlocked()) {
1186                 PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw);
1187             }
1188             mDeviceState.dump(pw);
1189             if (mOverviewComponentObserver != null) {
1190                 mOverviewComponentObserver.dump(pw);
1191             }
1192             if (mOverviewCommandHelper != null) {
1193                 mOverviewCommandHelper.dump(pw);
1194             }
1195             if (mGestureState != null) {
1196                 mGestureState.dump(pw);
1197             }
1198             pw.println("Input state:");
1199             pw.println("  mInputMonitorCompat=" + mInputMonitorCompat);
1200             pw.println("  mInputEventReceiver=" + mInputEventReceiver);
1201             DisplayController.INSTANCE.get(this).dump(pw);
1202             pw.println("TouchState:");
1203             BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null
1204                     : mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
1205             boolean resumed = mOverviewComponentObserver != null
1206                     && mOverviewComponentObserver.getActivityInterface().isResumed();
1207             pw.println("  createdOverviewActivity=" + createdOverviewActivity);
1208             pw.println("  resumed=" + resumed);
1209             pw.println("  mConsumer=" + mConsumer.getName());
1210             ActiveGestureLog.INSTANCE.dump("", pw);
1211             RecentsModel.INSTANCE.get(this).dump("", pw);
1212             pw.println("ProtoTrace:");
1213             pw.println("  file=" + ProtoTracer.INSTANCE.get(this).getTraceFile());
1214             if (createdOverviewActivity != null) {
1215                 createdOverviewActivity.getDeviceProfile().dump(this, "", pw);
1216             }
1217             mTaskbarManager.dumpLogs("", pw);
1218 
1219             if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
1220                 SettingsAwareViewCapture.getInstance(this).dump(pw, fd, this);
1221             }
1222         }
1223     }
1224 
printAvailableCommands(PrintWriter pw)1225     private void printAvailableCommands(PrintWriter pw) {
1226         pw.println("Available commands:");
1227         pw.println("  clear-touch-log: Clears the touch interaction log");
1228         pw.println("  print-gesture-log: only prints the ActiveGestureLog dump");
1229     }
1230 
onCommand(PrintWriter pw, LinkedList<String> args)1231     private void onCommand(PrintWriter pw, LinkedList<String> args) {
1232         String cmd = args.pollFirst();
1233         if (cmd == null) {
1234             pw.println("Command missing");
1235             printAvailableCommands(pw);
1236             return;
1237         }
1238         switch (cmd) {
1239             case "clear-touch-log":
1240                 ActiveGestureLog.INSTANCE.clear();
1241                 break;
1242             case "print-gesture-log":
1243                 ActiveGestureLog.INSTANCE.dump("", pw);
1244                 break;
1245             default:
1246                 pw.println("Command does not exist: " + cmd);
1247                 printAvailableCommands(pw);
1248         }
1249     }
1250 
createLauncherSwipeHandler( GestureState gestureState, long touchTimeMs)1251     private AbsSwipeUpHandler createLauncherSwipeHandler(
1252             GestureState gestureState, long touchTimeMs) {
1253         return new LauncherSwipeHandlerV2(this, mDeviceState, mTaskAnimationManager,
1254                 gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(),
1255                 mInputConsumer);
1256     }
1257 
createFallbackSwipeHandler( GestureState gestureState, long touchTimeMs)1258     private AbsSwipeUpHandler createFallbackSwipeHandler(
1259             GestureState gestureState, long touchTimeMs) {
1260         return new FallbackSwipeHandler(this, mDeviceState, mTaskAnimationManager,
1261                 gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(),
1262                 mInputConsumer);
1263     }
1264 
1265     @Override
writeToProto(LauncherTraceProto.Builder proto)1266     public void writeToProto(LauncherTraceProto.Builder proto) {
1267         TouchInteractionServiceProto.Builder serviceProto =
1268             TouchInteractionServiceProto.newBuilder();
1269         serviceProto.setServiceConnected(true);
1270 
1271         if (mOverviewComponentObserver != null) {
1272             mOverviewComponentObserver.writeToProto(serviceProto);
1273         }
1274         mConsumer.writeToProto(serviceProto);
1275 
1276         proto.setTouchInteractionService(serviceProto);
1277     }
1278 }
1279