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