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_MOVE; 22 import static android.view.MotionEvent.ACTION_POINTER_DOWN; 23 import static android.view.MotionEvent.ACTION_POINTER_UP; 24 import static android.view.MotionEvent.ACTION_UP; 25 26 import static com.android.launcher3.Flags.enableCursorHoverStates; 27 import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks; 28 import static com.android.launcher3.Flags.useActivityOverlay; 29 import static com.android.launcher3.Launcher.INTENT_ACTION_ALL_APPS_TOGGLE; 30 import static com.android.launcher3.LauncherPrefs.backedUpItem; 31 import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent; 32 import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe; 33 import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE; 34 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; 35 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; 36 import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN; 37 import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WIDTH; 38 import static com.android.quickstep.GestureState.DEFAULT_STATE; 39 import static com.android.quickstep.GestureState.TrackpadGestureType.getTrackpadGestureType; 40 import static com.android.quickstep.InputConsumer.TYPE_CURSOR_HOVER; 41 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER; 42 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_DOWN; 43 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_MOVE; 44 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_UP; 45 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENTS_ANIMATION_START_PENDING; 46 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; 47 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; 48 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER; 49 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER; 50 import static com.android.wm.shell.Flags.enableBubblesLongPressNavHandle; 51 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION; 52 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES; 53 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE; 54 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP; 55 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_ONE_HANDED; 56 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_PIP; 57 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS; 58 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; 59 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN; 60 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW; 61 62 import android.app.PendingIntent; 63 import android.app.Service; 64 import android.content.IIntentReceiver; 65 import android.content.IIntentSender; 66 import android.content.Intent; 67 import android.content.res.Configuration; 68 import android.graphics.Region; 69 import android.hardware.input.InputManager; 70 import android.os.Bundle; 71 import android.os.IBinder; 72 import android.os.Looper; 73 import android.os.SystemClock; 74 import android.os.Trace; 75 import android.util.ArraySet; 76 import android.util.Log; 77 import android.view.Choreographer; 78 import android.view.InputDevice; 79 import android.view.InputEvent; 80 import android.view.MotionEvent; 81 82 import androidx.annotation.BinderThread; 83 import androidx.annotation.NonNull; 84 import androidx.annotation.Nullable; 85 import androidx.annotation.UiThread; 86 import androidx.annotation.VisibleForTesting; 87 88 import com.android.launcher3.BaseDraggingActivity; 89 import com.android.launcher3.ConstantItem; 90 import com.android.launcher3.EncryptionType; 91 import com.android.launcher3.LauncherPrefs; 92 import com.android.launcher3.anim.AnimatedFloat; 93 import com.android.launcher3.config.FeatureFlags; 94 import com.android.launcher3.provider.RestoreDbTask; 95 import com.android.launcher3.statemanager.StatefulActivity; 96 import com.android.launcher3.taskbar.TaskbarActivityContext; 97 import com.android.launcher3.taskbar.TaskbarManager; 98 import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks; 99 import com.android.launcher3.testing.TestLogging; 100 import com.android.launcher3.testing.shared.ResourceUtils; 101 import com.android.launcher3.testing.shared.TestProtocol; 102 import com.android.launcher3.util.DisplayController; 103 import com.android.launcher3.util.LockedUserState; 104 import com.android.launcher3.util.PluginManagerWrapper; 105 import com.android.launcher3.util.SafeCloseable; 106 import com.android.launcher3.util.ScreenOnTracker; 107 import com.android.launcher3.util.TraceHelper; 108 import com.android.quickstep.inputconsumers.AccessibilityInputConsumer; 109 import com.android.quickstep.inputconsumers.AssistantInputConsumer; 110 import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer; 111 import com.android.quickstep.inputconsumers.NavHandleLongPressInputConsumer; 112 import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer; 113 import com.android.quickstep.inputconsumers.OtherActivityInputConsumer; 114 import com.android.quickstep.inputconsumers.OverviewInputConsumer; 115 import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer; 116 import com.android.quickstep.inputconsumers.ProgressDelegateInputConsumer; 117 import com.android.quickstep.inputconsumers.ResetGestureInputConsumer; 118 import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer; 119 import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer; 120 import com.android.quickstep.inputconsumers.TaskbarUnstashInputConsumer; 121 import com.android.quickstep.inputconsumers.TrackpadStatusBarInputConsumer; 122 import com.android.quickstep.util.ActiveGestureLog; 123 import com.android.quickstep.util.ActiveGestureLog.CompoundString; 124 import com.android.quickstep.util.AssistStateManager; 125 import com.android.quickstep.util.AssistUtils; 126 import com.android.quickstep.views.RecentsViewContainer; 127 import com.android.systemui.shared.recents.IOverviewProxy; 128 import com.android.systemui.shared.recents.ISystemUiProxy; 129 import com.android.systemui.shared.system.ActivityManagerWrapper; 130 import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver; 131 import com.android.systemui.shared.system.InputConsumerController; 132 import com.android.systemui.shared.system.InputMonitorCompat; 133 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; 134 import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController; 135 import com.android.systemui.unfold.progress.IUnfoldAnimation; 136 import com.android.wm.shell.back.IBackAnimation; 137 import com.android.wm.shell.bubbles.IBubbles; 138 import com.android.wm.shell.common.pip.IPip; 139 import com.android.wm.shell.desktopmode.IDesktopMode; 140 import com.android.wm.shell.draganddrop.IDragAndDrop; 141 import com.android.wm.shell.onehanded.IOneHanded; 142 import com.android.wm.shell.recents.IRecentTasks; 143 import com.android.wm.shell.shared.IShellTransitions; 144 import com.android.wm.shell.splitscreen.ISplitScreen; 145 import com.android.wm.shell.startingsurface.IStartingWindow; 146 147 import java.io.FileDescriptor; 148 import java.io.PrintWriter; 149 import java.lang.ref.WeakReference; 150 import java.util.Set; 151 import java.util.function.Consumer; 152 import java.util.function.Function; 153 154 /** 155 * Service connected by system-UI for handling touch interaction. 156 */ 157 public class TouchInteractionService extends Service { 158 159 private static final String SUBSTRING_PREFIX = "; "; 160 private static final String NEWLINE_PREFIX = "\n\t\t\t-> "; 161 162 private static final String TAG = "TouchInteractionService"; 163 164 private static final ConstantItem<Boolean> HAS_ENABLED_QUICKSTEP_ONCE = backedUpItem( 165 "launcher.has_enabled_quickstep_once", false, EncryptionType.ENCRYPTED); 166 167 private final TISBinder mTISBinder = new TISBinder(this); 168 169 /** 170 * Local IOverviewProxy implementation with some methods for local components 171 */ 172 public static class TISBinder extends IOverviewProxy.Stub { 173 174 private final WeakReference<TouchInteractionService> mTis; 175 176 @Nullable private Runnable mOnOverviewTargetChangeListener = null; 177 TISBinder(TouchInteractionService tis)178 private TISBinder(TouchInteractionService tis) { 179 mTis = new WeakReference<>(tis); 180 } 181 182 @BinderThread onInitialize(Bundle bundle)183 public void onInitialize(Bundle bundle) { 184 ISystemUiProxy proxy = ISystemUiProxy.Stub.asInterface( 185 bundle.getBinder(KEY_EXTRA_SYSUI_PROXY)); 186 IPip pip = IPip.Stub.asInterface(bundle.getBinder(KEY_EXTRA_SHELL_PIP)); 187 IBubbles bubbles = IBubbles.Stub.asInterface(bundle.getBinder(KEY_EXTRA_SHELL_BUBBLES)); 188 ISplitScreen splitscreen = ISplitScreen.Stub.asInterface(bundle.getBinder( 189 KEY_EXTRA_SHELL_SPLIT_SCREEN)); 190 IOneHanded onehanded = IOneHanded.Stub.asInterface( 191 bundle.getBinder(KEY_EXTRA_SHELL_ONE_HANDED)); 192 IShellTransitions shellTransitions = IShellTransitions.Stub.asInterface( 193 bundle.getBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS)); 194 IStartingWindow startingWindow = IStartingWindow.Stub.asInterface( 195 bundle.getBinder(KEY_EXTRA_SHELL_STARTING_WINDOW)); 196 ISysuiUnlockAnimationController launcherUnlockAnimationController = 197 ISysuiUnlockAnimationController.Stub.asInterface( 198 bundle.getBinder(KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER)); 199 IRecentTasks recentTasks = IRecentTasks.Stub.asInterface( 200 bundle.getBinder(KEY_EXTRA_SHELL_RECENT_TASKS)); 201 IBackAnimation backAnimation = IBackAnimation.Stub.asInterface( 202 bundle.getBinder(KEY_EXTRA_SHELL_BACK_ANIMATION)); 203 IDesktopMode desktopMode = IDesktopMode.Stub.asInterface( 204 bundle.getBinder(KEY_EXTRA_SHELL_DESKTOP_MODE)); 205 IUnfoldAnimation unfoldTransition = IUnfoldAnimation.Stub.asInterface( 206 bundle.getBinder(KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER)); 207 IDragAndDrop dragAndDrop = IDragAndDrop.Stub.asInterface( 208 bundle.getBinder(KEY_EXTRA_SHELL_DRAG_AND_DROP)); 209 MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> { 210 SystemUiProxy.INSTANCE.get(tis).setProxy(proxy, pip, 211 bubbles, splitscreen, onehanded, shellTransitions, startingWindow, 212 recentTasks, launcherUnlockAnimationController, backAnimation, desktopMode, 213 unfoldTransition, dragAndDrop); 214 tis.initInputMonitor("TISBinder#onInitialize()"); 215 tis.preloadOverview(true /* fromInit */); 216 })); 217 sIsInitialized = true; 218 } 219 220 @BinderThread 221 @Override onTaskbarToggled()222 public void onTaskbarToggled() { 223 if (!FeatureFlags.ENABLE_KEYBOARD_TASKBAR_TOGGLE.get()) return; 224 MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> { 225 TaskbarActivityContext activityContext = 226 tis.mTaskbarManager.getCurrentActivityContext(); 227 228 if (activityContext != null) { 229 activityContext.toggleTaskbarStash(); 230 } 231 })); 232 } 233 234 @BinderThread onOverviewToggle()235 public void onOverviewToggle() { 236 TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle"); 237 executeForTouchInteractionService(tis -> { 238 // If currently screen pinning, do not enter overview 239 if (tis.mDeviceState.isScreenPinningActive()) { 240 return; 241 } 242 TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); 243 tis.mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_TOGGLE); 244 }); 245 } 246 247 @BinderThread 248 @Override onOverviewShown(boolean triggeredFromAltTab)249 public void onOverviewShown(boolean triggeredFromAltTab) { 250 executeForTouchInteractionService(tis -> { 251 if (triggeredFromAltTab) { 252 TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); 253 tis.mOverviewCommandHelper.addCommand( 254 OverviewCommandHelper.TYPE_KEYBOARD_INPUT); 255 } else { 256 tis.mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW); 257 } 258 }); 259 } 260 261 @BinderThread 262 @Override onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)263 public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 264 executeForTouchInteractionService(tis -> { 265 if (triggeredFromAltTab && !triggeredFromHomeKey) { 266 // onOverviewShownFromAltTab hides the overview and ends at the target app 267 tis.mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HIDE); 268 } 269 }); 270 } 271 272 @BinderThread 273 @Override onAssistantAvailable(boolean available, boolean longPressHomeEnabled)274 public void onAssistantAvailable(boolean available, boolean longPressHomeEnabled) { 275 MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> { 276 tis.mDeviceState.setAssistantAvailable(available); 277 tis.onAssistantVisibilityChanged(); 278 executeForTaskbarManager(taskbarManager -> taskbarManager 279 .onLongPressHomeEnabled(longPressHomeEnabled)); 280 })); 281 } 282 283 @BinderThread 284 @Override onAssistantVisibilityChanged(float visibility)285 public void onAssistantVisibilityChanged(float visibility) { 286 MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> { 287 tis.mDeviceState.setAssistantVisibility(visibility); 288 tis.onAssistantVisibilityChanged(); 289 })); 290 } 291 292 /** 293 * Sent when the assistant has been invoked with the given type (defined in AssistManager) 294 * and should be shown. This method is used if SystemUiProxy#setAssistantOverridesRequested 295 * was previously called including this invocation type. 296 */ 297 @Override onAssistantOverrideInvoked(int invocationType)298 public void onAssistantOverrideInvoked(int invocationType) { 299 executeForTouchInteractionService(tis -> { 300 if (!AssistUtils.newInstance(tis).tryStartAssistOverride(invocationType)) { 301 Log.w(TAG, "Failed to invoke Assist override"); 302 } 303 }); 304 } 305 306 @BinderThread onSystemUiStateChanged(@ystemUiStateFlags long stateFlags)307 public void onSystemUiStateChanged(@SystemUiStateFlags long stateFlags) { 308 MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> { 309 long lastFlags = tis.mDeviceState.getSystemUiStateFlags(); 310 tis.mDeviceState.setSystemUiFlags(stateFlags); 311 tis.onSystemUiFlagsChanged(lastFlags); 312 })); 313 } 314 315 @BinderThread onActiveNavBarRegionChanges(Region region)316 public void onActiveNavBarRegionChanges(Region region) { 317 MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService( 318 tis -> tis.mDeviceState.setDeferredGestureRegion(region))); 319 } 320 321 @BinderThread 322 @Override enterStageSplitFromRunningApp(boolean leftOrTop)323 public void enterStageSplitFromRunningApp(boolean leftOrTop) { 324 executeForTouchInteractionService(tis -> { 325 StatefulActivity activity = 326 tis.mOverviewComponentObserver.getActivityInterface().getCreatedContainer(); 327 if (activity != null) { 328 activity.enterStageSplitFromRunningApp(leftOrTop); 329 } 330 }); 331 } 332 333 /** 334 * Preloads the Overview activity. 335 * <p> 336 * This method should only be used when the All Set page of the SUW is reached to safely 337 * preload the Launcher for the SUW first reveal. 338 */ preloadOverviewForSUWAllSet()339 public void preloadOverviewForSUWAllSet() { 340 executeForTouchInteractionService(tis -> tis.preloadOverview(false, true)); 341 } 342 343 @Override onRotationProposal(int rotation, boolean isValid)344 public void onRotationProposal(int rotation, boolean isValid) { 345 executeForTaskbarManager(taskbarManager -> 346 taskbarManager.onRotationProposal(rotation, isValid)); 347 } 348 349 @Override disable(int displayId, int state1, int state2, boolean animate)350 public void disable(int displayId, int state1, int state2, boolean animate) { 351 executeForTaskbarManager(taskbarManager -> 352 taskbarManager.disableNavBarElements(displayId, state1, state2, animate)); 353 } 354 355 @Override onSystemBarAttributesChanged(int displayId, int behavior)356 public void onSystemBarAttributesChanged(int displayId, int behavior) { 357 executeForTaskbarManager(taskbarManager -> 358 taskbarManager.onSystemBarAttributesChanged(displayId, behavior)); 359 } 360 361 @Override onNavButtonsDarkIntensityChanged(float darkIntensity)362 public void onNavButtonsDarkIntensityChanged(float darkIntensity) { 363 executeForTaskbarManager(taskbarManager -> 364 taskbarManager.onNavButtonsDarkIntensityChanged(darkIntensity)); 365 } 366 367 @Override onNavigationBarLumaSamplingEnabled(int displayId, boolean enable)368 public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) { 369 executeForTaskbarManager(taskbarManager -> 370 taskbarManager.onNavigationBarLumaSamplingEnabled(displayId, enable)); 371 } 372 executeForTouchInteractionService( @onNull Consumer<TouchInteractionService> tisConsumer)373 private void executeForTouchInteractionService( 374 @NonNull Consumer<TouchInteractionService> tisConsumer) { 375 TouchInteractionService tis = mTis.get(); 376 if (tis == null) return; 377 tisConsumer.accept(tis); 378 } 379 executeForTaskbarManager( @onNull Consumer<TaskbarManager> taskbarManagerConsumer)380 private void executeForTaskbarManager( 381 @NonNull Consumer<TaskbarManager> taskbarManagerConsumer) { 382 MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> { 383 TaskbarManager taskbarManager = tis.mTaskbarManager; 384 if (taskbarManager == null) return; 385 taskbarManagerConsumer.accept(taskbarManager); 386 })); 387 } 388 389 /** 390 * Returns the {@link TaskbarManager}. 391 * <p> 392 * Returns {@code null} if TouchInteractionService is not connected 393 */ 394 @Nullable getTaskbarManager()395 public TaskbarManager getTaskbarManager() { 396 TouchInteractionService tis = mTis.get(); 397 if (tis == null) return null; 398 return tis.mTaskbarManager; 399 } 400 401 @VisibleForTesting injectFakeTrackpadForTesting()402 public void injectFakeTrackpadForTesting() { 403 TouchInteractionService tis = mTis.get(); 404 if (tis == null) return; 405 tis.mTrackpadsConnected.add(1000); 406 tis.initInputMonitor("tapl testing"); 407 } 408 409 @VisibleForTesting ejectFakeTrackpadForTesting()410 public void ejectFakeTrackpadForTesting() { 411 TouchInteractionService tis = mTis.get(); 412 if (tis == null) return; 413 tis.mTrackpadsConnected.clear(); 414 // This method destroys the current input monitor if set up, and only init a new one 415 // in 3-button mode if {@code mTrackpadsConnected} is not empty. So in other words, 416 // it will destroy the input monitor. 417 tis.initInputMonitor("tapl testing"); 418 } 419 420 /** 421 * Sets whether a predictive back-to-home animation is in progress in the device state 422 */ setPredictiveBackToHomeInProgress(boolean isInProgress)423 public void setPredictiveBackToHomeInProgress(boolean isInProgress) { 424 executeForTouchInteractionService(tis -> 425 tis.mDeviceState.setPredictiveBackToHomeInProgress(isInProgress)); 426 } 427 428 /** 429 * Returns the {@link OverviewCommandHelper}. 430 * <p> 431 * Returns {@code null} if TouchInteractionService is not connected 432 */ 433 @Nullable getOverviewCommandHelper()434 public OverviewCommandHelper getOverviewCommandHelper() { 435 TouchInteractionService tis = mTis.get(); 436 if (tis == null) return null; 437 return tis.mOverviewCommandHelper; 438 } 439 440 /** 441 * Sets a proxy to bypass swipe up behavior 442 */ setSwipeUpProxy(Function<GestureState, AnimatedFloat> proxy)443 public void setSwipeUpProxy(Function<GestureState, AnimatedFloat> proxy) { 444 executeForTouchInteractionService( 445 tis -> tis.mSwipeUpProxyProvider = proxy != null ? proxy : (i -> null)); 446 } 447 448 /** 449 * Sets the task id where gestures should be blocked 450 */ setGestureBlockedTaskId(int taskId)451 public void setGestureBlockedTaskId(int taskId) { 452 executeForTouchInteractionService( 453 tis -> tis.mDeviceState.setGestureBlockingTaskId(taskId)); 454 } 455 456 /** Sets a listener to be run on Overview Target updates. */ setOverviewTargetChangeListener(@ullable Runnable listener)457 public void setOverviewTargetChangeListener(@Nullable Runnable listener) { 458 mOnOverviewTargetChangeListener = listener; 459 } 460 onOverviewTargetChange()461 protected void onOverviewTargetChange() { 462 if (mOnOverviewTargetChangeListener != null) { 463 mOnOverviewTargetChangeListener.run(); 464 mOnOverviewTargetChangeListener = null; 465 } 466 } 467 468 /** Refreshes the current overview target. */ refreshOverviewTarget()469 public void refreshOverviewTarget() { 470 executeForTouchInteractionService(tis -> { 471 tis.mAllAppsActionManager.onDestroy(); 472 tis.onOverviewTargetChange(tis.mOverviewComponentObserver.isHomeAndOverviewSame()); 473 }); 474 } 475 } 476 477 private final InputManager.InputDeviceListener mInputDeviceListener = 478 new InputManager.InputDeviceListener() { 479 @Override 480 public void onInputDeviceAdded(int deviceId) { 481 if (isTrackpadDevice(deviceId)) { 482 boolean wasEmpty = mTrackpadsConnected.isEmpty(); 483 mTrackpadsConnected.add(deviceId); 484 if (wasEmpty) { 485 update(); 486 } 487 } 488 } 489 490 @Override 491 public void onInputDeviceChanged(int deviceId) { 492 } 493 494 @Override 495 public void onInputDeviceRemoved(int deviceId) { 496 mTrackpadsConnected.remove(deviceId); 497 if (mTrackpadsConnected.isEmpty()) { 498 update(); 499 } 500 } 501 502 private void update() { 503 if (mInputMonitorCompat != null && !mTrackpadsConnected.isEmpty()) { 504 // Don't destroy and reinitialize input monitor due to trackpad 505 // connecting when it's already set up. 506 return; 507 } 508 initInputMonitor("onTrackpadConnected()"); 509 } 510 511 private boolean isTrackpadDevice(int deviceId) { 512 InputDevice inputDevice = mInputManager.getInputDevice(deviceId); 513 if (inputDevice == null) { 514 return false; 515 } 516 return inputDevice.getSources() == (InputDevice.SOURCE_MOUSE 517 | InputDevice.SOURCE_TOUCHPAD); 518 } 519 }; 520 521 private static boolean sConnected = false; 522 private static boolean sIsInitialized = false; 523 private RotationTouchHelper mRotationTouchHelper; 524 isConnected()525 public static boolean isConnected() { 526 return sConnected; 527 } 528 isInitialized()529 public static boolean isInitialized() { 530 return sIsInitialized; 531 } 532 533 private final AbsSwipeUpHandler.Factory mLauncherSwipeHandlerFactory = 534 this::createLauncherSwipeHandler; 535 private final AbsSwipeUpHandler.Factory mFallbackSwipeHandlerFactory = 536 this::createFallbackSwipeHandler; 537 538 private final ScreenOnTracker.ScreenOnListener mScreenOnListener = this::onScreenOnChanged; 539 540 private final TaskbarNavButtonCallbacks mNavCallbacks = new TaskbarNavButtonCallbacks() { 541 @Override 542 public void onNavigateHome() { 543 mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HOME); 544 } 545 546 @Override 547 public void onToggleOverview() { 548 mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_TOGGLE); 549 } 550 }; 551 552 private ActivityManagerWrapper mAM; 553 private OverviewCommandHelper mOverviewCommandHelper; 554 private OverviewComponentObserver mOverviewComponentObserver; 555 private InputConsumerController mInputConsumer; 556 private RecentsAnimationDeviceState mDeviceState; 557 private TaskAnimationManager mTaskAnimationManager; 558 559 private @NonNull InputConsumer mUncheckedConsumer = InputConsumer.NO_OP; 560 private @NonNull InputConsumer mConsumer = InputConsumer.NO_OP; 561 private Choreographer mMainChoreographer; 562 private @Nullable ResetGestureInputConsumer mResetGestureInputConsumer; 563 private GestureState mGestureState = DEFAULT_STATE; 564 565 private InputMonitorCompat mInputMonitorCompat; 566 private InputEventReceiver mInputEventReceiver; 567 568 private TaskbarManager mTaskbarManager; 569 private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = i -> null; 570 private AllAppsActionManager mAllAppsActionManager; 571 private InputManager mInputManager; 572 private final Set<Integer> mTrackpadsConnected = new ArraySet<>(); 573 574 @Override onCreate()575 public void onCreate() { 576 super.onCreate(); 577 // Initialize anything here that is needed in direct boot mode. 578 // Everything else should be initialized in onUserUnlocked() below. 579 mMainChoreographer = Choreographer.getInstance(); 580 mAM = ActivityManagerWrapper.getInstance(); 581 mDeviceState = new RecentsAnimationDeviceState(this, true); 582 mRotationTouchHelper = mDeviceState.getRotationTouchHelper(); 583 mAllAppsActionManager = new AllAppsActionManager( 584 this, UI_HELPER_EXECUTOR, this::createAllAppsPendingIntent); 585 mInputManager = getSystemService(InputManager.class); 586 if (ENABLE_TRACKPAD_GESTURE.get()) { 587 mInputManager.registerInputDeviceListener(mInputDeviceListener, 588 UI_HELPER_EXECUTOR.getHandler()); 589 int [] inputDevices = mInputManager.getInputDeviceIds(); 590 for (int inputDeviceId : inputDevices) { 591 mInputDeviceListener.onInputDeviceAdded(inputDeviceId); 592 } 593 } 594 mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager, mNavCallbacks); 595 mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer(); 596 597 // Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized. 598 LockedUserState.get(this).runOnUserUnlocked(this::onUserUnlocked); 599 LockedUserState.get(this).runOnUserUnlocked(mTaskbarManager::onUserUnlocked); 600 mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged); 601 sConnected = true; 602 603 ScreenOnTracker.INSTANCE.get(this).addListener(mScreenOnListener); 604 } 605 disposeEventHandlers(String reason)606 private void disposeEventHandlers(String reason) { 607 Log.d(TAG, "disposeEventHandlers: Reason: " + reason); 608 if (mInputEventReceiver != null) { 609 mInputEventReceiver.dispose(); 610 mInputEventReceiver = null; 611 } 612 if (mInputMonitorCompat != null) { 613 mInputMonitorCompat.dispose(); 614 mInputMonitorCompat = null; 615 } 616 } 617 initInputMonitor(String reason)618 private void initInputMonitor(String reason) { 619 disposeEventHandlers("Initializing input monitor due to: " + reason); 620 621 if (mDeviceState.isButtonNavMode() && (!ENABLE_TRACKPAD_GESTURE.get() 622 || mTrackpadsConnected.isEmpty())) { 623 return; 624 } 625 626 mInputMonitorCompat = new InputMonitorCompat("swipe-up", mDeviceState.getDisplayId()); 627 mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(), 628 mMainChoreographer, this::onInputEvent); 629 630 mRotationTouchHelper.updateGestureTouchRegions(); 631 } 632 633 /** 634 * Called when the navigation mode changes, guaranteed to be after the device state has updated. 635 */ onNavigationModeChanged()636 private void onNavigationModeChanged() { 637 initInputMonitor("onNavigationModeChanged()"); 638 resetHomeBounceSeenOnQuickstepEnabledFirstTime(); 639 } 640 641 @UiThread onUserUnlocked()642 public void onUserUnlocked() { 643 Log.d(TAG, "onUserUnlocked: userId=" + getUserId()); 644 mTaskAnimationManager = new TaskAnimationManager(this); 645 mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState); 646 mOverviewCommandHelper = new OverviewCommandHelper(this, 647 mOverviewComponentObserver, mTaskAnimationManager); 648 mResetGestureInputConsumer = new ResetGestureInputConsumer( 649 mTaskAnimationManager, mTaskbarManager::getCurrentActivityContext); 650 mInputConsumer.registerInputConsumer(); 651 onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags()); 652 onAssistantVisibilityChanged(); 653 654 // Initialize the task tracker 655 TopTaskTracker.INSTANCE.get(this); 656 657 // Temporarily disable model preload 658 // new ModelPreload().start(this); 659 resetHomeBounceSeenOnQuickstepEnabledFirstTime(); 660 661 mOverviewComponentObserver.setOverviewChangeListener(this::onOverviewTargetChange); 662 onOverviewTargetChange(mOverviewComponentObserver.isHomeAndOverviewSame()); 663 } 664 getOverviewCommandHelper()665 public OverviewCommandHelper getOverviewCommandHelper() { 666 return mOverviewCommandHelper; 667 } 668 resetHomeBounceSeenOnQuickstepEnabledFirstTime()669 private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() { 670 if (!LockedUserState.get(this).isUserUnlocked() || mDeviceState.isButtonNavMode()) { 671 // Skip if not yet unlocked (can't read user shared prefs) or if the current navigation 672 // mode doesn't have gestures 673 return; 674 } 675 676 // Reset home bounce seen on quick step enabled for first time 677 LauncherPrefs prefs = LauncherPrefs.get(this); 678 if (!prefs.get(HAS_ENABLED_QUICKSTEP_ONCE)) { 679 prefs.put( 680 HAS_ENABLED_QUICKSTEP_ONCE.to(true), 681 HOME_BOUNCE_SEEN.to(false)); 682 } 683 } 684 onOverviewTargetChange(boolean isHomeAndOverviewSame)685 private void onOverviewTargetChange(boolean isHomeAndOverviewSame) { 686 mAllAppsActionManager.setHomeAndOverviewSame(isHomeAndOverviewSame); 687 688 StatefulActivity newOverviewActivity = mOverviewComponentObserver.getActivityInterface() 689 .getCreatedContainer(); 690 if (newOverviewActivity != null) { 691 mTaskbarManager.setActivity(newOverviewActivity); 692 } 693 mTISBinder.onOverviewTargetChange(); 694 } 695 createAllAppsPendingIntent()696 private PendingIntent createAllAppsPendingIntent() { 697 if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) { 698 return new PendingIntent(new IIntentSender.Stub() { 699 @Override 700 public void send(int code, Intent intent, String resolvedType, 701 IBinder allowlistToken, IIntentReceiver finishedReceiver, 702 String requiredPermission, Bundle options) { 703 MAIN_EXECUTOR.execute(() -> mTaskbarManager.toggleAllApps()); 704 } 705 }); 706 } else { 707 return PendingIntent.getActivity( 708 this, 709 GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS, 710 new Intent(mOverviewComponentObserver.getHomeIntent()) 711 .setAction(INTENT_ACTION_ALL_APPS_TOGGLE), 712 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); 713 } 714 } 715 716 @UiThread 717 private void onSystemUiFlagsChanged(@SystemUiStateFlags long lastSysUIFlags) { 718 if (LockedUserState.get(this).isUserUnlocked()) { 719 long systemUiStateFlags = mDeviceState.getSystemUiStateFlags(); 720 SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags); 721 mOverviewComponentObserver.onSystemUiStateChanged(); 722 mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags); 723 mTaskAnimationManager.onSystemUiFlagsChanged(lastSysUIFlags, systemUiStateFlags); 724 } 725 } 726 727 @UiThread 728 private void onAssistantVisibilityChanged() { 729 if (LockedUserState.get(this).isUserUnlocked()) { 730 mOverviewComponentObserver.getActivityInterface().onAssistantVisibilityChanged( 731 mDeviceState.getAssistantVisibility()); 732 } 733 } 734 735 @Override 736 public void onDestroy() { 737 Log.d(TAG, "Touch service destroyed: user=" + getUserId()); 738 sIsInitialized = false; 739 if (LockedUserState.get(this).isUserUnlocked()) { 740 mInputConsumer.unregisterInputConsumer(); 741 mOverviewComponentObserver.onDestroy(); 742 } 743 disposeEventHandlers("TouchInteractionService onDestroy()"); 744 mDeviceState.destroy(); 745 SystemUiProxy.INSTANCE.get(this).clearProxy(); 746 747 mAllAppsActionManager.onDestroy(); 748 749 mInputManager.unregisterInputDeviceListener(mInputDeviceListener); 750 mTrackpadsConnected.clear(); 751 752 mTaskbarManager.destroy(); 753 sConnected = false; 754 755 ScreenOnTracker.INSTANCE.get(this).removeListener(mScreenOnListener); 756 super.onDestroy(); 757 } 758 759 @Override 760 public IBinder onBind(Intent intent) { 761 Log.d(TAG, "Touch service connected: user=" + getUserId()); 762 return mTISBinder; 763 } 764 765 protected void onScreenOnChanged(boolean isOn) { 766 if (isOn) { 767 return; 768 } 769 long currentTime = SystemClock.uptimeMillis(); 770 MotionEvent cancelEvent = MotionEvent.obtain( 771 currentTime, currentTime, ACTION_CANCEL, 0f, 0f, 0); 772 onInputEvent(cancelEvent); 773 cancelEvent.recycle(); 774 } 775 776 private void onInputEvent(InputEvent ev) { 777 if (!(ev instanceof MotionEvent)) { 778 ActiveGestureLog.INSTANCE.addLog(new CompoundString("TIS.onInputEvent: ") 779 .append("Cannot process input event: received unknown event ") 780 .append(ev.toString())); 781 return; 782 } 783 MotionEvent event = (MotionEvent) ev; 784 785 TestLogging.recordMotionEvent( 786 TestProtocol.SEQUENCE_TIS, "TouchInteractionService.onInputEvent", event); 787 788 boolean isUserUnlocked = LockedUserState.get(this).isUserUnlocked(); 789 if (!isUserUnlocked || (mDeviceState.isButtonNavMode() 790 && !isTrackpadMotionEvent(event))) { 791 ActiveGestureLog.INSTANCE.addLog(new CompoundString("TIS.onInputEvent: ") 792 .append("Cannot process input event: ") 793 .append(!isUserUnlocked 794 ? "user is locked" 795 : "using 3-button nav and event is not a trackpad event")); 796 return; 797 } 798 799 final int action = event.getActionMasked(); 800 // Note this will create a new consumer every mouse click, as after ACTION_UP from the click 801 // an ACTION_HOVER_ENTER will fire as well. 802 boolean isHoverActionWithoutConsumer = enableCursorHoverStates() 803 && isHoverActionWithoutConsumer(event); 804 805 if (enableHandleDelayedGestureCallbacks()) { 806 if (action == ACTION_DOWN || isHoverActionWithoutConsumer) { 807 mTaskAnimationManager.notifyNewGestureStart(); 808 } 809 if (mTaskAnimationManager.shouldIgnoreMotionEvents()) { 810 if (action == ACTION_DOWN || isHoverActionWithoutConsumer) { 811 ActiveGestureLog.INSTANCE.addLog( 812 new CompoundString("TIS.onMotionEvent: A new gesture has been ") 813 .append("started, but a previously-requested recents ") 814 .append("animation hasn't started. Ignoring all following ") 815 .append("motion events."), 816 RECENTS_ANIMATION_START_PENDING); 817 } 818 return; 819 } 820 } 821 822 SafeCloseable traceToken = TraceHelper.INSTANCE.allowIpcs("TIS.onInputEvent"); 823 824 CompoundString reasonString = action == ACTION_DOWN 825 ? new CompoundString("TIS.onMotionEvent: ") : CompoundString.NO_OP; 826 if (action == ACTION_DOWN || isHoverActionWithoutConsumer) { 827 mRotationTouchHelper.setOrientationTransformIfNeeded(event); 828 829 boolean isOneHandedModeActive = mDeviceState.isOneHandedModeActive(); 830 boolean isInSwipeUpTouchRegion = mRotationTouchHelper.isInSwipeUpTouchRegion(event); 831 TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext(); 832 if (isInSwipeUpTouchRegion && tac != null) { 833 tac.closeKeyboardQuickSwitchView(); 834 } 835 if ((!isOneHandedModeActive && isInSwipeUpTouchRegion) 836 || isHoverActionWithoutConsumer) { 837 reasonString.append(!isOneHandedModeActive && isInSwipeUpTouchRegion 838 ? "one handed mode is not active and event is in swipe up region" 839 : "isHoverActionWithoutConsumer == true") 840 .append(", creating new input consumer"); 841 // Clone the previous gesture state since onConsumerAboutToBeSwitched might trigger 842 // onConsumerInactive and wipe the previous gesture state 843 GestureState prevGestureState = new GestureState(mGestureState); 844 GestureState newGestureState = createGestureState(mGestureState, 845 getTrackpadGestureType(event)); 846 mConsumer.onConsumerAboutToBeSwitched(); 847 mGestureState = newGestureState; 848 mConsumer = newConsumer(prevGestureState, mGestureState, event); 849 mUncheckedConsumer = mConsumer; 850 } else if ((mDeviceState.isFullyGesturalNavMode() || isTrackpadMultiFingerSwipe(event)) 851 && mDeviceState.canTriggerAssistantAction(event)) { 852 reasonString.append(mDeviceState.isFullyGesturalNavMode() 853 ? "using fully gestural nav" 854 : "event is a trackpad multi-finger swipe") 855 .append(" and event can trigger assistant action") 856 .append(", consuming gesture for assistant action"); 857 mGestureState = createGestureState(mGestureState, 858 getTrackpadGestureType(event)); 859 // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we 860 // should not interrupt it. QuickSwitch assumes that interruption can only 861 // happen if the next gesture is also quick switch. 862 mUncheckedConsumer = tryCreateAssistantInputConsumer(mGestureState, event); 863 } else if (mDeviceState.canTriggerOneHandedAction(event)) { 864 reasonString.append("event can trigger one-handed action") 865 .append(", consuming gesture for one-handed action"); 866 // Consume gesture event for triggering one handed feature. 867 mUncheckedConsumer = new OneHandedModeInputConsumer(this, mDeviceState, 868 InputConsumer.NO_OP, mInputMonitorCompat); 869 } else { 870 mUncheckedConsumer = InputConsumer.NO_OP; 871 } 872 } else { 873 // Other events 874 if (mUncheckedConsumer != InputConsumer.NO_OP) { 875 // Only transform the event if we are handling it in a proper consumer 876 mRotationTouchHelper.setOrientationTransformIfNeeded(event); 877 } 878 } 879 880 if (mUncheckedConsumer != InputConsumer.NO_OP) { 881 switch (action) { 882 case ACTION_DOWN: 883 ActiveGestureLog.INSTANCE.addLog(reasonString); 884 // fall through 885 case ACTION_UP: 886 ActiveGestureLog.INSTANCE.addLog( 887 new CompoundString("onMotionEvent(") 888 .append((int) event.getRawX()) 889 .append(", ") 890 .append((int) event.getRawY()) 891 .append("): ") 892 .append(MotionEvent.actionToString(action)) 893 .append(", ") 894 .append(MotionEvent.classificationToString( 895 event.getClassification())), 896 /* gestureEvent= */ action == ACTION_DOWN 897 ? MOTION_DOWN 898 : MOTION_UP); 899 break; 900 case ACTION_MOVE: 901 ActiveGestureLog.INSTANCE.addLog( 902 new CompoundString("onMotionEvent: ") 903 .append(MotionEvent.actionToString(action)) 904 .append(",") 905 .append(MotionEvent.classificationToString( 906 event.getClassification())) 907 .append(", pointerCount: ") 908 .append(event.getPointerCount()), 909 MOTION_MOVE); 910 break; 911 default: { 912 ActiveGestureLog.INSTANCE.addLog( 913 new CompoundString("onMotionEvent: ") 914 .append(MotionEvent.actionToString(action)) 915 .append(",") 916 .append(MotionEvent.classificationToString( 917 event.getClassification()))); 918 } 919 } 920 } 921 922 boolean cancelGesture = mGestureState.getContainerInterface() != null 923 && mGestureState.getContainerInterface().shouldCancelCurrentGesture(); 924 boolean cleanUpConsumer = (action == ACTION_UP || action == ACTION_CANCEL || cancelGesture) 925 && mConsumer != null 926 && !mConsumer.getActiveConsumerInHierarchy().isConsumerDetachedFromGesture(); 927 if (cancelGesture) { 928 event.setAction(ACTION_CANCEL); 929 } 930 931 if (mGestureState.isTrackpadGesture() && (action == ACTION_POINTER_DOWN 932 || action == ACTION_POINTER_UP)) { 933 // Skip ACTION_POINTER_DOWN and ACTION_POINTER_UP events from trackpad. 934 } else if (isCursorHoverEvent(event)) { 935 mUncheckedConsumer.onHoverEvent(event); 936 } else { 937 mUncheckedConsumer.onMotionEvent(event); 938 } 939 940 if (cleanUpConsumer) { 941 reset(); 942 } 943 traceToken.close(); 944 } 945 946 private boolean isHoverActionWithoutConsumer(MotionEvent event) { 947 // Only process these events when taskbar is present. 948 TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext(); 949 boolean isTaskbarPresent = tac != null && tac.getDeviceProfile().isTaskbarPresent 950 && !tac.isPhoneMode(); 951 return event.isHoverEvent() && (mUncheckedConsumer.getType() & TYPE_CURSOR_HOVER) == 0 952 && isTaskbarPresent; 953 } 954 955 // Talkback generates hover events on touch, which we do not want to consume. 956 private boolean isCursorHoverEvent(MotionEvent event) { 957 return event.isHoverEvent() && event.getSource() == InputDevice.SOURCE_MOUSE; 958 } 959 960 private InputConsumer tryCreateAssistantInputConsumer( 961 GestureState gestureState, MotionEvent motionEvent) { 962 return tryCreateAssistantInputConsumer( 963 InputConsumer.NO_OP, gestureState, motionEvent, CompoundString.NO_OP); 964 } 965 966 private InputConsumer tryCreateAssistantInputConsumer( 967 InputConsumer base, 968 GestureState gestureState, 969 MotionEvent motionEvent, 970 CompoundString reasonString) { 971 if (mDeviceState.isGestureBlockedTask(gestureState.getRunningTask())) { 972 reasonString.append(SUBSTRING_PREFIX) 973 .append("is gesture-blocked task, using base input consumer"); 974 return base; 975 } else { 976 reasonString.append(SUBSTRING_PREFIX).append("using AssistantInputConsumer"); 977 return new AssistantInputConsumer( 978 this, gestureState, base, mInputMonitorCompat, mDeviceState, motionEvent); 979 } 980 } 981 982 public GestureState createGestureState(GestureState previousGestureState, 983 GestureState.TrackpadGestureType trackpadGestureType) { 984 final GestureState gestureState; 985 TopTaskTracker.CachedTaskInfo taskInfo; 986 if (mTaskAnimationManager.isRecentsAnimationRunning()) { 987 gestureState = new GestureState(mOverviewComponentObserver, 988 ActiveGestureLog.INSTANCE.getLogId()); 989 TopTaskTracker.CachedTaskInfo previousTaskInfo = previousGestureState.getRunningTask(); 990 // previousTaskInfo can be null iff previousGestureState == GestureState.DEFAULT_STATE 991 taskInfo = previousTaskInfo != null 992 ? previousTaskInfo 993 : TopTaskTracker.INSTANCE.get(this).getCachedTopTask(false); 994 gestureState.updateRunningTask(taskInfo); 995 gestureState.updateLastStartedTaskIds(previousGestureState.getLastStartedTaskIds()); 996 gestureState.updatePreviouslyAppearedTaskIds( 997 previousGestureState.getPreviouslyAppearedTaskIds()); 998 } else { 999 gestureState = new GestureState(mOverviewComponentObserver, 1000 ActiveGestureLog.INSTANCE.incrementLogId()); 1001 taskInfo = TopTaskTracker.INSTANCE.get(this).getCachedTopTask(false); 1002 gestureState.updateRunningTask(taskInfo); 1003 } 1004 gestureState.setTrackpadGestureType(trackpadGestureType); 1005 1006 // Log initial state for the gesture. 1007 ActiveGestureLog.INSTANCE.addLog(new CompoundString("Current running task package name=") 1008 .append(taskInfo.getPackageName())); 1009 ActiveGestureLog.INSTANCE.addLog(new CompoundString("Current SystemUi state flags=") 1010 .append(mDeviceState.getSystemUiStateString())); 1011 return gestureState; 1012 } 1013 1014 private InputConsumer newConsumer( 1015 GestureState previousGestureState, GestureState newGestureState, MotionEvent event) { 1016 AnimatedFloat progressProxy = mSwipeUpProxyProvider.apply(mGestureState); 1017 if (progressProxy != null) { 1018 InputConsumer consumer = new ProgressDelegateInputConsumer( 1019 this, mTaskAnimationManager, mGestureState, mInputMonitorCompat, progressProxy); 1020 1021 logInputConsumerSelectionReason(consumer, newCompoundString( 1022 "mSwipeUpProxyProvider has been set, using ProgressDelegateInputConsumer")); 1023 1024 return consumer; 1025 } 1026 1027 boolean canStartSystemGesture = 1028 mGestureState.isTrackpadGesture() ? mDeviceState.canStartTrackpadGesture() 1029 : mDeviceState.canStartSystemGesture(); 1030 1031 if (!LockedUserState.get(this).isUserUnlocked()) { 1032 CompoundString reasonString = newCompoundString("device locked"); 1033 InputConsumer consumer; 1034 if (canStartSystemGesture) { 1035 // This handles apps launched in direct boot mode (e.g. dialer) as well as apps 1036 // launched while device is locked even after exiting direct boot mode (e.g. camera). 1037 consumer = createDeviceLockedInputConsumer( 1038 newGestureState, reasonString.append(SUBSTRING_PREFIX) 1039 .append("can start system gesture")); 1040 } else { 1041 consumer = getDefaultInputConsumer( 1042 reasonString.append(SUBSTRING_PREFIX) 1043 .append("cannot start system gesture")); 1044 } 1045 logInputConsumerSelectionReason(consumer, reasonString); 1046 return consumer; 1047 } 1048 1049 CompoundString reasonString; 1050 InputConsumer base; 1051 // When there is an existing recents animation running, bypass systemState check as this is 1052 // a followup gesture and the first gesture started in a valid system state. 1053 if (canStartSystemGesture || previousGestureState.isRecentsAnimationRunning()) { 1054 reasonString = newCompoundString(canStartSystemGesture 1055 ? "can start system gesture" : "recents animation was running") 1056 .append(", trying to use base consumer"); 1057 base = newBaseConsumer(previousGestureState, newGestureState, event, reasonString); 1058 } else { 1059 reasonString = newCompoundString( 1060 "cannot start system gesture and recents animation was not running") 1061 .append(", trying to use default input consumer"); 1062 base = getDefaultInputConsumer(reasonString); 1063 } 1064 if (mDeviceState.isGesturalNavMode() || newGestureState.isTrackpadGesture()) { 1065 handleOrientationSetup(base); 1066 } 1067 if (mDeviceState.isFullyGesturalNavMode() || newGestureState.isTrackpadGesture()) { 1068 String reasonPrefix = 1069 "device is in gesture navigation mode or 3-button mode with a trackpad gesture"; 1070 if (mDeviceState.canTriggerAssistantAction(event)) { 1071 reasonString.append(NEWLINE_PREFIX) 1072 .append(reasonPrefix) 1073 .append(SUBSTRING_PREFIX) 1074 .append("gesture can trigger the assistant") 1075 .append(", trying to use assistant input consumer"); 1076 base = tryCreateAssistantInputConsumer(base, newGestureState, event, reasonString); 1077 } 1078 1079 // If Taskbar is present, we listen for swipe or cursor hover events to unstash it. 1080 TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext(); 1081 if (tac != null && !(base instanceof AssistantInputConsumer)) { 1082 // Present always on large screen or on small screen w/ flag 1083 boolean useTaskbarConsumer = tac.getDeviceProfile().isTaskbarPresent 1084 && !tac.isPhoneMode() 1085 && !tac.isInStashedLauncherState(); 1086 if (canStartSystemGesture && useTaskbarConsumer) { 1087 reasonString.append(NEWLINE_PREFIX) 1088 .append(reasonPrefix) 1089 .append(SUBSTRING_PREFIX) 1090 .append("TaskbarActivityContext != null, ") 1091 .append("using TaskbarUnstashInputConsumer"); 1092 base = new TaskbarUnstashInputConsumer(this, base, mInputMonitorCompat, tac, 1093 mOverviewCommandHelper, mGestureState); 1094 } 1095 } 1096 if (enableBubblesLongPressNavHandle()) { 1097 // Create bubbles input consumer before NavHandleLongPressInputConsumer. 1098 // This allows for nav handle to fall back to bubbles. 1099 if (mDeviceState.isBubblesExpanded()) { 1100 reasonString = newCompoundString(reasonPrefix) 1101 .append(SUBSTRING_PREFIX) 1102 .append("bubbles expanded, trying to use default input consumer"); 1103 // Bubbles can handle home gesture itself. 1104 base = getDefaultInputConsumer(reasonString); 1105 } 1106 } 1107 1108 NavHandle navHandle = tac != null ? tac.getNavHandle() 1109 : SystemUiProxy.INSTANCE.get(this); 1110 if (canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning() 1111 && navHandle.canNavHandleBeLongPressed()) { 1112 reasonString.append(NEWLINE_PREFIX) 1113 .append(reasonPrefix) 1114 .append(SUBSTRING_PREFIX) 1115 .append("Not running recents animation, "); 1116 if (tac != null && tac.getNavHandle().canNavHandleBeLongPressed()) { 1117 reasonString.append("stashed handle is long-pressable, "); 1118 } 1119 reasonString.append("using NavHandleLongPressInputConsumer"); 1120 base = new NavHandleLongPressInputConsumer(this, base, mInputMonitorCompat, 1121 mDeviceState, navHandle, mGestureState); 1122 } 1123 1124 if (!enableBubblesLongPressNavHandle()) { 1125 // Continue overriding nav handle input consumer with bubbles 1126 if (mDeviceState.isBubblesExpanded()) { 1127 reasonString = newCompoundString(reasonPrefix) 1128 .append(SUBSTRING_PREFIX) 1129 .append("bubbles expanded, trying to use default input consumer"); 1130 // Bubbles can handle home gesture itself. 1131 base = getDefaultInputConsumer(reasonString); 1132 } 1133 } 1134 1135 if (mDeviceState.isSystemUiDialogShowing()) { 1136 reasonString = newCompoundString(reasonPrefix) 1137 .append(SUBSTRING_PREFIX) 1138 .append("system dialog is showing, using SysUiOverlayInputConsumer"); 1139 base = new SysUiOverlayInputConsumer( 1140 getBaseContext(), mDeviceState, mInputMonitorCompat); 1141 } 1142 1143 if (ENABLE_TRACKPAD_GESTURE.get() && mGestureState.isTrackpadGesture() 1144 && canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning()) { 1145 reasonString = newCompoundString(reasonPrefix) 1146 .append(SUBSTRING_PREFIX) 1147 .append("Trackpad 3-finger gesture, using TrackpadStatusBarInputConsumer"); 1148 base = new TrackpadStatusBarInputConsumer(getBaseContext(), base, 1149 mInputMonitorCompat); 1150 } 1151 1152 if (mDeviceState.isScreenPinningActive()) { 1153 reasonString = newCompoundString(reasonPrefix) 1154 .append(SUBSTRING_PREFIX) 1155 .append("screen pinning is active, using ScreenPinnedInputConsumer"); 1156 // Note: we only allow accessibility to wrap this, and it replaces the previous 1157 // base input consumer (which should be NO_OP anyway since topTaskLocked == true). 1158 base = new ScreenPinnedInputConsumer(this, newGestureState); 1159 } 1160 1161 if (mDeviceState.canTriggerOneHandedAction(event)) { 1162 reasonString.append(NEWLINE_PREFIX) 1163 .append(reasonPrefix) 1164 .append(SUBSTRING_PREFIX) 1165 .append("gesture can trigger one handed mode") 1166 .append(", using OneHandedModeInputConsumer"); 1167 base = new OneHandedModeInputConsumer( 1168 this, mDeviceState, base, mInputMonitorCompat); 1169 } 1170 1171 if (mDeviceState.isAccessibilityMenuAvailable()) { 1172 reasonString.append(NEWLINE_PREFIX) 1173 .append(reasonPrefix) 1174 .append(SUBSTRING_PREFIX) 1175 .append("accessibility menu is available") 1176 .append(", using AccessibilityInputConsumer"); 1177 base = new AccessibilityInputConsumer( 1178 this, mDeviceState, mGestureState, base, mInputMonitorCompat); 1179 } 1180 } else { 1181 String reasonPrefix = "device is not in gesture navigation mode"; 1182 if (mDeviceState.isScreenPinningActive()) { 1183 reasonString = newCompoundString(reasonPrefix) 1184 .append(SUBSTRING_PREFIX) 1185 .append("screen pinning is active, trying to use default input consumer"); 1186 base = getDefaultInputConsumer(reasonString); 1187 } 1188 1189 if (mDeviceState.canTriggerOneHandedAction(event)) { 1190 reasonString.append(NEWLINE_PREFIX) 1191 .append(reasonPrefix) 1192 .append(SUBSTRING_PREFIX) 1193 .append("gesture can trigger one handed mode") 1194 .append(", using OneHandedModeInputConsumer"); 1195 base = new OneHandedModeInputConsumer( 1196 this, mDeviceState, base, mInputMonitorCompat); 1197 } 1198 } 1199 logInputConsumerSelectionReason(base, reasonString); 1200 return base; 1201 } 1202 1203 private CompoundString newCompoundString(String substring) { 1204 return new CompoundString(NEWLINE_PREFIX).append(substring); 1205 } 1206 1207 private void logInputConsumerSelectionReason( 1208 InputConsumer consumer, CompoundString reasonString) { 1209 ActiveGestureLog.INSTANCE.addLog(new CompoundString("setInputConsumer: ") 1210 .append(consumer.getName()) 1211 .append(". reason(s):") 1212 .append(reasonString)); 1213 if ((consumer.getType() & InputConsumer.TYPE_OTHER_ACTIVITY) != 0) { 1214 ActiveGestureLog.INSTANCE.trackEvent(FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER); 1215 } 1216 } 1217 1218 private void handleOrientationSetup(InputConsumer baseInputConsumer) { 1219 baseInputConsumer.notifyOrientationSetup(); 1220 } 1221 1222 private InputConsumer newBaseConsumer( 1223 GestureState previousGestureState, 1224 GestureState gestureState, 1225 MotionEvent event, 1226 CompoundString reasonString) { 1227 if (mDeviceState.isKeyguardShowingOccluded()) { 1228 // This handles apps showing over the lockscreen (e.g. camera) 1229 return createDeviceLockedInputConsumer( 1230 gestureState, 1231 reasonString.append(SUBSTRING_PREFIX) 1232 .append("keyguard is showing occluded") 1233 .append(", trying to use device locked input consumer")); 1234 } 1235 1236 reasonString.append(SUBSTRING_PREFIX).append("keyguard is not showing occluded"); 1237 1238 TopTaskTracker.CachedTaskInfo runningTask = gestureState.getRunningTask(); 1239 // Use overview input consumer for sharesheets on top of home. 1240 boolean forceOverviewInputConsumer = gestureState.getContainerInterface().isStarted() 1241 && runningTask != null 1242 && runningTask.isRootChooseActivity(); 1243 1244 // In the case where we are in an excluded, translucent overlay, ignore it and treat the 1245 // running activity as the task behind the overlay. 1246 TopTaskTracker.CachedTaskInfo otherVisibleTask = runningTask == null 1247 ? null 1248 : runningTask.getVisibleNonExcludedTask(); 1249 if (otherVisibleTask != null) { 1250 ActiveGestureLog.INSTANCE.addLog(new CompoundString("Changing active task to ") 1251 .append(otherVisibleTask.getPackageName()) 1252 .append(" because the previous task running on top of this one (") 1253 .append(runningTask.getPackageName()) 1254 .append(") was excluded from recents")); 1255 gestureState.updateRunningTask(otherVisibleTask); 1256 } 1257 1258 boolean previousGestureAnimatedToLauncher = 1259 previousGestureState.isRunningAnimationToLauncher() 1260 || mDeviceState.isPredictiveBackToHomeInProgress(); 1261 // with shell-transitions, home is resumed during recents animation, so 1262 // explicitly check against recents animation too. 1263 boolean launcherResumedThroughShellTransition = 1264 gestureState.getContainerInterface().isResumed() 1265 && !previousGestureState.isRecentsAnimationRunning(); 1266 // If a task fragment within Launcher is resumed 1267 boolean launcherChildActivityResumed = useActivityOverlay() 1268 && runningTask != null 1269 && runningTask.isHomeTask() 1270 && mOverviewComponentObserver.isHomeAndOverviewSame() 1271 && !launcherResumedThroughShellTransition 1272 && !previousGestureState.isRecentsAnimationRunning(); 1273 1274 if (gestureState.getContainerInterface().isInLiveTileMode()) { 1275 return createOverviewInputConsumer( 1276 previousGestureState, 1277 gestureState, 1278 event, 1279 forceOverviewInputConsumer, 1280 reasonString.append(SUBSTRING_PREFIX) 1281 .append("is in live tile mode, trying to use overview input consumer")); 1282 } else if (runningTask == null) { 1283 return getDefaultInputConsumer(reasonString.append(SUBSTRING_PREFIX) 1284 .append("running task == null")); 1285 } else if (previousGestureAnimatedToLauncher 1286 || launcherResumedThroughShellTransition 1287 || forceOverviewInputConsumer) { 1288 return createOverviewInputConsumer( 1289 previousGestureState, 1290 gestureState, 1291 event, 1292 forceOverviewInputConsumer, 1293 reasonString.append(SUBSTRING_PREFIX) 1294 .append(previousGestureAnimatedToLauncher 1295 ? "previous gesture animated to launcher" 1296 : (launcherResumedThroughShellTransition 1297 ? "launcher resumed through a shell transition" 1298 : "forceOverviewInputConsumer == true")) 1299 .append(", trying to use overview input consumer")); 1300 } else if (mDeviceState.isGestureBlockedTask(runningTask) || launcherChildActivityResumed) { 1301 return getDefaultInputConsumer(reasonString.append(SUBSTRING_PREFIX) 1302 .append(launcherChildActivityResumed 1303 ? "is launcher child-task, trying to use default input consumer" 1304 : "is gesture-blocked task, trying to use default input consumer")); 1305 } else { 1306 reasonString.append(SUBSTRING_PREFIX) 1307 .append("using OtherActivityInputConsumer"); 1308 return createOtherActivityInputConsumer(gestureState, event); 1309 } 1310 } 1311 1312 public AbsSwipeUpHandler.Factory getSwipeUpHandlerFactory() { 1313 return !mOverviewComponentObserver.isHomeAndOverviewSame() 1314 ? mFallbackSwipeHandlerFactory : mLauncherSwipeHandlerFactory; 1315 } 1316 1317 private InputConsumer createOtherActivityInputConsumer(GestureState gestureState, 1318 MotionEvent event) { 1319 1320 final AbsSwipeUpHandler.Factory factory = getSwipeUpHandlerFactory(); 1321 final boolean shouldDefer = !mOverviewComponentObserver.isHomeAndOverviewSame() 1322 || gestureState.getContainerInterface().deferStartingActivity(mDeviceState, event); 1323 final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event); 1324 return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager, 1325 gestureState, shouldDefer, this::onConsumerInactive, 1326 mInputMonitorCompat, mInputEventReceiver, disableHorizontalSwipe, factory); 1327 } 1328 1329 private InputConsumer createDeviceLockedInputConsumer( 1330 GestureState gestureState, CompoundString reasonString) { 1331 if ((mDeviceState.isFullyGesturalNavMode() || gestureState.isTrackpadGesture()) 1332 && gestureState.getRunningTask() != null) { 1333 reasonString.append(SUBSTRING_PREFIX) 1334 .append("device is in gesture nav mode or 3-button mode with a trackpad") 1335 .append(" gesture and running task != null") 1336 .append(", using DeviceLockedInputConsumer"); 1337 return new DeviceLockedInputConsumer( 1338 this, mDeviceState, mTaskAnimationManager, gestureState, mInputMonitorCompat); 1339 } else { 1340 return getDefaultInputConsumer(reasonString 1341 .append(SUBSTRING_PREFIX) 1342 .append((mDeviceState.isFullyGesturalNavMode() 1343 || gestureState.isTrackpadGesture()) 1344 ? "running task == null" 1345 : "device is not in gesture nav mode and it's not a trackpad gesture") 1346 .append(", trying to use default input consumer")); 1347 } 1348 } 1349 1350 public InputConsumer createOverviewInputConsumer( 1351 GestureState previousGestureState, 1352 GestureState gestureState, 1353 MotionEvent event, 1354 boolean forceOverviewInputConsumer, 1355 CompoundString reasonString) { 1356 RecentsViewContainer container = gestureState.getContainerInterface().getCreatedContainer(); 1357 if (container == null) { 1358 return getDefaultInputConsumer( 1359 reasonString.append(SUBSTRING_PREFIX) 1360 .append("activity == null, trying to use default input consumer")); 1361 } 1362 1363 boolean hasWindowFocus = container.getRootView().hasWindowFocus(); 1364 boolean isPreviousGestureAnimatingToLauncher = 1365 previousGestureState.isRunningAnimationToLauncher() 1366 || mDeviceState.isPredictiveBackToHomeInProgress(); 1367 boolean isInLiveTileMode = gestureState.getContainerInterface().isInLiveTileMode(); 1368 1369 reasonString.append(SUBSTRING_PREFIX) 1370 .append(hasWindowFocus 1371 ? "activity has window focus" 1372 : (isPreviousGestureAnimatingToLauncher 1373 ? "previous gesture is still animating to launcher" 1374 : isInLiveTileMode 1375 ? "device is in live mode" 1376 : "all overview focus conditions failed")); 1377 if (hasWindowFocus 1378 || isPreviousGestureAnimatingToLauncher 1379 || isInLiveTileMode) { 1380 reasonString.append(SUBSTRING_PREFIX) 1381 .append("overview should have focus, using OverviewInputConsumer"); 1382 return new OverviewInputConsumer(gestureState, container, mInputMonitorCompat, 1383 false /* startingInActivityBounds */); 1384 } else { 1385 reasonString.append(SUBSTRING_PREFIX).append( 1386 "overview shouldn't have focus, using OverviewWithoutFocusInputConsumer"); 1387 final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event); 1388 return new OverviewWithoutFocusInputConsumer(container.asContext(), mDeviceState, 1389 gestureState, mInputMonitorCompat, disableHorizontalSwipe); 1390 } 1391 } 1392 1393 /** 1394 * To be called by the consumer when it's no longer active. This can be called by any consumer 1395 * in the hierarchy at any point during the gesture (ie. if a delegate consumer starts 1396 * intercepting touches, the base consumer can try to call this). 1397 */ 1398 private void onConsumerInactive(InputConsumer caller) { 1399 if (mConsumer != null && mConsumer.getActiveConsumerInHierarchy() == caller) { 1400 reset(); 1401 } 1402 } 1403 1404 private void reset() { 1405 mConsumer = mUncheckedConsumer = getDefaultInputConsumer(); 1406 mGestureState = DEFAULT_STATE; 1407 // By default, use batching of the input events, but check receiver before using in the rare 1408 // case that the monitor was disposed before the swipe settled 1409 if (mInputEventReceiver != null) { 1410 mInputEventReceiver.setBatchingEnabled(true); 1411 } 1412 } 1413 1414 private @NonNull InputConsumer getDefaultInputConsumer() { 1415 return getDefaultInputConsumer(CompoundString.NO_OP); 1416 } 1417 1418 /** 1419 * Returns the {@link ResetGestureInputConsumer} if user is unlocked, else NO_OP. 1420 */ 1421 private @NonNull InputConsumer getDefaultInputConsumer(@NonNull CompoundString reasonString) { 1422 if (mResetGestureInputConsumer != null) { 1423 reasonString.append(SUBSTRING_PREFIX).append( 1424 "mResetGestureInputConsumer initialized, using ResetGestureInputConsumer"); 1425 return mResetGestureInputConsumer; 1426 } else { 1427 reasonString.append(SUBSTRING_PREFIX).append( 1428 "mResetGestureInputConsumer not initialized, using no-op input consumer"); 1429 // mResetGestureInputConsumer isn't initialized until onUserUnlocked(), so reset to 1430 // NO_OP until then (we never want these to be null). 1431 return InputConsumer.NO_OP; 1432 } 1433 } 1434 1435 private void preloadOverview(boolean fromInit) { 1436 Trace.beginSection("preloadOverview(fromInit=" + fromInit + ")"); 1437 preloadOverview(fromInit, false); 1438 Trace.endSection(); 1439 } 1440 1441 private void preloadOverview(boolean fromInit, boolean forSUWAllSet) { 1442 if (!LockedUserState.get(this).isUserUnlocked()) { 1443 return; 1444 } 1445 1446 if (mDeviceState.isButtonNavMode() && !mOverviewComponentObserver.isHomeAndOverviewSame()) { 1447 // Prevent the overview from being started before the real home on first boot. 1448 return; 1449 } 1450 1451 if ((RestoreDbTask.isPending(this) && !forSUWAllSet) 1452 || !mDeviceState.isUserSetupComplete()) { 1453 // Preloading while a restore is pending may cause launcher to start the restore 1454 // too early. 1455 return; 1456 } 1457 1458 final BaseActivityInterface activityInterface = 1459 mOverviewComponentObserver.getActivityInterface(); 1460 final Intent overviewIntent = new Intent( 1461 mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState()); 1462 if (activityInterface.getCreatedContainer() != null && fromInit) { 1463 // The activity has been created before the initialization of overview service. It is 1464 // usually happens when booting or launcher is the top activity, so we should already 1465 // have the latest state. 1466 return; 1467 } 1468 1469 // TODO(b/258022658): Remove temporary logging. 1470 Log.i(TAG, "preloadOverview: forSUWAllSet=" + forSUWAllSet 1471 + ", isHomeAndOverviewSame=" + mOverviewComponentObserver.isHomeAndOverviewSame()); 1472 1473 ActiveGestureLog.INSTANCE.addLog("preloadRecentsAnimation"); 1474 mTaskAnimationManager.preloadRecentsAnimation(overviewIntent); 1475 } 1476 1477 @Override 1478 public void onConfigurationChanged(Configuration newConfig) { 1479 if (!LockedUserState.get(this).isUserUnlocked()) { 1480 return; 1481 } 1482 final BaseActivityInterface activityInterface = 1483 mOverviewComponentObserver.getActivityInterface(); 1484 final BaseDraggingActivity activity = activityInterface.getCreatedContainer(); 1485 if (activity == null || activity.isStarted()) { 1486 // We only care about the existing background activity. 1487 return; 1488 } 1489 Configuration oldConfig = activity.getResources().getConfiguration(); 1490 boolean isFoldUnfold = isTablet(oldConfig) != isTablet(newConfig); 1491 if (!isFoldUnfold && mOverviewComponentObserver.canHandleConfigChanges( 1492 activity.getComponentName(), 1493 activity.getResources().getConfiguration().diff(newConfig))) { 1494 // Since navBar gestural height are different between portrait and landscape, 1495 // can handle orientation changes and refresh navigation gestural region through 1496 // onOneHandedModeChanged() 1497 int newGesturalHeight = ResourceUtils.getNavbarSize( 1498 ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, 1499 getApplicationContext().getResources()); 1500 mDeviceState.onOneHandedModeChanged(newGesturalHeight); 1501 return; 1502 } 1503 1504 preloadOverview(false /* fromInit */); 1505 } 1506 1507 private static boolean isTablet(Configuration config) { 1508 return config.smallestScreenWidthDp >= MIN_TABLET_WIDTH; 1509 } 1510 1511 @Override 1512 protected void dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs) { 1513 // Dump everything 1514 if (LockedUserState.get(this).isUserUnlocked()) { 1515 PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw); 1516 } 1517 mDeviceState.dump(pw); 1518 if (mOverviewComponentObserver != null) { 1519 mOverviewComponentObserver.dump(pw); 1520 } 1521 if (mOverviewCommandHelper != null) { 1522 mOverviewCommandHelper.dump(pw); 1523 } 1524 if (mGestureState != null) { 1525 mGestureState.dump("", pw); 1526 } 1527 pw.println("Input state:"); 1528 pw.println("\tmInputMonitorCompat=" + mInputMonitorCompat); 1529 pw.println("\tmInputEventReceiver=" + mInputEventReceiver); 1530 DisplayController.INSTANCE.get(this).dump(pw); 1531 pw.println("TouchState:"); 1532 BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null 1533 : mOverviewComponentObserver.getActivityInterface().getCreatedContainer(); 1534 boolean resumed = mOverviewComponentObserver != null 1535 && mOverviewComponentObserver.getActivityInterface().isResumed(); 1536 pw.println("\tcreatedOverviewActivity=" + createdOverviewActivity); 1537 pw.println("\tresumed=" + resumed); 1538 pw.println("\tmConsumer=" + mConsumer.getName()); 1539 ActiveGestureLog.INSTANCE.dump("", pw); 1540 RecentsModel.INSTANCE.get(this).dump("", pw); 1541 TopTaskTracker.INSTANCE.get(this).dump("", pw); 1542 if (mTaskAnimationManager != null) { 1543 mTaskAnimationManager.dump("", pw); 1544 } 1545 if (createdOverviewActivity != null) { 1546 createdOverviewActivity.getDeviceProfile().dump(this, "", pw); 1547 } 1548 mTaskbarManager.dumpLogs("", pw); 1549 pw.println("AssistStateManager:"); 1550 AssistStateManager.INSTANCE.get(this).dump("\t", pw); 1551 SystemUiProxy.INSTANCE.get(this).dump(pw); 1552 DeviceConfigWrapper.get().dump(" ", pw); 1553 } 1554 1555 private AbsSwipeUpHandler createLauncherSwipeHandler( 1556 GestureState gestureState, long touchTimeMs) { 1557 return new LauncherSwipeHandlerV2(this, mDeviceState, mTaskAnimationManager, 1558 gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(), 1559 mInputConsumer); 1560 } 1561 1562 private AbsSwipeUpHandler createFallbackSwipeHandler( 1563 GestureState gestureState, long touchTimeMs) { 1564 return new FallbackSwipeHandler(this, mDeviceState, mTaskAnimationManager, 1565 gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(), 1566 mInputConsumer); 1567 } 1568 } 1569