1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.quickstep; 17 18 import static android.content.Intent.ACTION_CHOOSER; 19 import static android.view.MotionEvent.ACTION_CANCEL; 20 import static android.view.MotionEvent.ACTION_DOWN; 21 import static android.view.MotionEvent.ACTION_UP; 22 23 import static com.android.launcher3.config.FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS; 24 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; 25 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; 26 import static com.android.quickstep.GestureState.DEFAULT_STATE; 27 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; 28 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED; 29 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP; 30 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; 31 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN; 32 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW; 33 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER; 34 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; 35 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED; 36 37 import android.annotation.TargetApi; 38 import android.app.ActivityManager; 39 import android.app.PendingIntent; 40 import android.app.RemoteAction; 41 import android.app.Service; 42 import android.content.ComponentName; 43 import android.content.Context; 44 import android.content.Intent; 45 import android.content.SharedPreferences; 46 import android.content.res.Configuration; 47 import android.graphics.Point; 48 import android.graphics.Rect; 49 import android.graphics.Region; 50 import android.graphics.drawable.Icon; 51 import android.hardware.display.DisplayManager; 52 import android.os.Build; 53 import android.os.Bundle; 54 import android.os.IBinder; 55 import android.os.Looper; 56 import android.os.SystemClock; 57 import android.os.SystemProperties; 58 import android.util.Log; 59 import android.view.Choreographer; 60 import android.view.Display; 61 import android.view.InputEvent; 62 import android.view.MotionEvent; 63 import android.view.Surface; 64 import android.view.accessibility.AccessibilityManager; 65 66 import androidx.annotation.BinderThread; 67 import androidx.annotation.NonNull; 68 import androidx.annotation.Nullable; 69 import androidx.annotation.UiThread; 70 import androidx.annotation.WorkerThread; 71 72 import com.android.launcher3.BaseDraggingActivity; 73 import com.android.launcher3.R; 74 import com.android.launcher3.ResourceUtils; 75 import com.android.launcher3.Utilities; 76 import com.android.launcher3.config.FeatureFlags; 77 import com.android.launcher3.provider.RestoreDbTask; 78 import com.android.launcher3.statemanager.StatefulActivity; 79 import com.android.launcher3.taskbar.TaskbarManager; 80 import com.android.launcher3.testing.TestLogging; 81 import com.android.launcher3.testing.TestProtocol; 82 import com.android.launcher3.tracing.LauncherTraceProto; 83 import com.android.launcher3.tracing.TouchInteractionServiceProto; 84 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; 85 import com.android.launcher3.util.OnboardingPrefs; 86 import com.android.launcher3.util.TraceHelper; 87 import com.android.launcher3.util.WindowBounds; 88 import com.android.quickstep.inputconsumers.AccessibilityInputConsumer; 89 import com.android.quickstep.inputconsumers.AssistantInputConsumer; 90 import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer; 91 import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer; 92 import com.android.quickstep.inputconsumers.OtherActivityInputConsumer; 93 import com.android.quickstep.inputconsumers.OverscrollInputConsumer; 94 import com.android.quickstep.inputconsumers.OverviewInputConsumer; 95 import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer; 96 import com.android.quickstep.inputconsumers.ResetGestureInputConsumer; 97 import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer; 98 import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer; 99 import com.android.quickstep.util.ActiveGestureLog; 100 import com.android.quickstep.util.AssistantUtilities; 101 import com.android.quickstep.util.ProtoTracer; 102 import com.android.quickstep.util.SplitScreenBounds; 103 import com.android.systemui.plugins.OverscrollPlugin; 104 import com.android.systemui.plugins.PluginListener; 105 import com.android.systemui.shared.recents.IOverviewProxy; 106 import com.android.systemui.shared.recents.ISystemUiProxy; 107 import com.android.systemui.shared.system.ActivityManagerWrapper; 108 import com.android.systemui.shared.system.InputChannelCompat; 109 import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver; 110 import com.android.systemui.shared.system.InputConsumerController; 111 import com.android.systemui.shared.system.InputMonitorCompat; 112 import com.android.systemui.shared.system.smartspace.ISmartspaceTransitionController; 113 import com.android.systemui.shared.tracing.ProtoTraceable; 114 import com.android.wm.shell.onehanded.IOneHanded; 115 import com.android.wm.shell.pip.IPip; 116 import com.android.wm.shell.splitscreen.ISplitScreen; 117 import com.android.wm.shell.startingsurface.IStartingWindow; 118 import com.android.wm.shell.transition.IShellTransitions; 119 120 import java.io.FileDescriptor; 121 import java.io.PrintWriter; 122 import java.util.Arrays; 123 import java.util.LinkedList; 124 125 /** 126 * Service connected by system-UI for handling touch interaction. 127 */ 128 @TargetApi(Build.VERSION_CODES.R) 129 public class TouchInteractionService extends Service implements PluginListener<OverscrollPlugin>, 130 ProtoTraceable<LauncherTraceProto.Builder> { 131 132 private static final String TAG = "TouchInteractionService"; 133 134 private static final String KEY_BACK_NOTIFICATION_COUNT = "backNotificationCount"; 135 private static final String NOTIFY_ACTION_BACK = "com.android.quickstep.action.BACK_GESTURE"; 136 private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once"; 137 private static final int MAX_BACK_NOTIFICATION_COUNT = 3; 138 139 /** 140 * System Action ID to show all apps. 141 * TODO: Use AccessibilityService's corresponding global action constant in S 142 */ 143 private static final int SYSTEM_ACTION_ID_ALL_APPS = 14; 144 145 public static final boolean ENABLE_PER_WINDOW_INPUT_ROTATION = 146 SystemProperties.getBoolean("persist.debug.per_window_input_rotation", false); 147 148 private int mBackGestureNotificationCounter = -1; 149 @Nullable 150 private OverscrollPlugin mOverscrollPlugin; 151 152 /** 153 * Local IOverviewProxy implementation with some methods for local components 154 */ 155 public class TISBinder extends IOverviewProxy.Stub { 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 ISmartspaceTransitionController smartspaceTransitionController = 171 ISmartspaceTransitionController.Stub.asInterface( 172 bundle.getBinder(KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER)); 173 MAIN_EXECUTOR.execute(() -> { 174 SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip, 175 splitscreen, onehanded, shellTransitions, startingWindow, 176 smartspaceTransitionController); 177 TouchInteractionService.this.initInputMonitor(); 178 preloadOverview(true /* fromInit */); 179 mDeviceState.runOnUserUnlocked(() -> { 180 final BaseActivityInterface ai = 181 mOverviewComponentObserver.getActivityInterface(); 182 if (ai == null) return; 183 ai.onOverviewServiceBound(); 184 }); 185 }); 186 sIsInitialized = true; 187 } 188 189 @BinderThread onOverviewToggle()190 public void onOverviewToggle() { 191 TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle"); 192 // If currently screen pinning, do not enter overview 193 if (mDeviceState.isScreenPinningActive()) { 194 return; 195 } 196 TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); 197 mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_TOGGLE); 198 } 199 200 @BinderThread 201 @Override onOverviewShown(boolean triggeredFromAltTab)202 public void onOverviewShown(boolean triggeredFromAltTab) { 203 if (triggeredFromAltTab) { 204 TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); 205 mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW_NEXT_FOCUS); 206 } else { 207 mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW); 208 } 209 } 210 211 @BinderThread 212 @Override onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)213 public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 214 if (triggeredFromAltTab && !triggeredFromHomeKey) { 215 // onOverviewShownFromAltTab hides the overview and ends at the target app 216 mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HIDE); 217 } 218 } 219 220 @BinderThread 221 @Override onTip(int actionType, int viewType)222 public void onTip(int actionType, int viewType) { 223 // Please delete this method from the interface 224 } 225 226 @BinderThread 227 @Override onAssistantAvailable(boolean available)228 public void onAssistantAvailable(boolean available) { 229 MAIN_EXECUTOR.execute(() -> { 230 mDeviceState.setAssistantAvailable(available); 231 TouchInteractionService.this.onAssistantVisibilityChanged(); 232 }); 233 } 234 235 @BinderThread 236 @Override onAssistantVisibilityChanged(float visibility)237 public void onAssistantVisibilityChanged(float visibility) { 238 MAIN_EXECUTOR.execute(() -> { 239 mDeviceState.setAssistantVisibility(visibility); 240 TouchInteractionService.this.onAssistantVisibilityChanged(); 241 }); 242 } 243 244 @BinderThread onBackAction(boolean completed, int downX, int downY, boolean isButton, boolean gestureSwipeLeft)245 public void onBackAction(boolean completed, int downX, int downY, boolean isButton, 246 boolean gestureSwipeLeft) { 247 // Remove this method from the interface 248 } 249 250 @BinderThread onSystemUiStateChanged(int stateFlags)251 public void onSystemUiStateChanged(int stateFlags) { 252 MAIN_EXECUTOR.execute(() -> { 253 int lastFlags = mDeviceState.getSystemUiStateFlags(); 254 mDeviceState.setSystemUiFlags(stateFlags); 255 TouchInteractionService.this.onSystemUiFlagsChanged(lastFlags); 256 }); 257 } 258 259 @BinderThread onActiveNavBarRegionChanges(Region region)260 public void onActiveNavBarRegionChanges(Region region) { 261 MAIN_EXECUTOR.execute(() -> mDeviceState.setDeferredGestureRegion(region)); 262 } 263 264 @Override onSplitScreenSecondaryBoundsChanged(Rect bounds, Rect insets)265 public void onSplitScreenSecondaryBoundsChanged(Rect bounds, Rect insets) { 266 WindowBounds wb = new WindowBounds(bounds, insets); 267 MAIN_EXECUTOR.execute(() -> SplitScreenBounds.INSTANCE.setSecondaryWindowBounds(wb)); 268 } 269 270 @Override onImeWindowStatusChanged(int displayId, IBinder token, int vis, int backDisposition, boolean showImeSwitcher)271 public void onImeWindowStatusChanged(int displayId, IBinder token, int vis, 272 int backDisposition, boolean showImeSwitcher) { 273 MAIN_EXECUTOR.execute(() -> mTaskbarManager.updateImeStatus( 274 displayId, vis, backDisposition, showImeSwitcher)); 275 } 276 getTaskbarManager()277 public TaskbarManager getTaskbarManager() { 278 return mTaskbarManager; 279 } 280 getOverviewCommandHelper()281 public OverviewCommandHelper getOverviewCommandHelper() { 282 return mOverviewCommandHelper; 283 } 284 } 285 286 private static boolean sConnected = false; 287 private static boolean sIsInitialized = false; 288 private RotationTouchHelper mRotationTouchHelper; 289 isConnected()290 public static boolean isConnected() { 291 return sConnected; 292 } 293 294 isInitialized()295 public static boolean isInitialized() { 296 return sIsInitialized; 297 } 298 299 private final AbsSwipeUpHandler.Factory mLauncherSwipeHandlerFactory = 300 this::createLauncherSwipeHandler; 301 private final AbsSwipeUpHandler.Factory mFallbackSwipeHandlerFactory = 302 this::createFallbackSwipeHandler; 303 304 private ActivityManagerWrapper mAM; 305 private OverviewCommandHelper mOverviewCommandHelper; 306 private OverviewComponentObserver mOverviewComponentObserver; 307 private InputConsumerController mInputConsumer; 308 private RecentsAnimationDeviceState mDeviceState; 309 private TaskAnimationManager mTaskAnimationManager; 310 311 private @NonNull InputConsumer mUncheckedConsumer = InputConsumer.NO_OP; 312 private @NonNull InputConsumer mConsumer = InputConsumer.NO_OP; 313 private Choreographer mMainChoreographer; 314 private @Nullable ResetGestureInputConsumer mResetGestureInputConsumer; 315 private GestureState mGestureState = DEFAULT_STATE; 316 317 private InputMonitorCompat mInputMonitorCompat; 318 private InputEventReceiver mInputEventReceiver; 319 320 private DisplayManager mDisplayManager; 321 322 private TaskbarManager mTaskbarManager; 323 324 @Override onCreate()325 public void onCreate() { 326 super.onCreate(); 327 // Initialize anything here that is needed in direct boot mode. 328 // Everything else should be initialized in onUserUnlocked() below. 329 mMainChoreographer = Choreographer.getInstance(); 330 mAM = ActivityManagerWrapper.getInstance(); 331 mDeviceState = new RecentsAnimationDeviceState(this, true); 332 mDisplayManager = getSystemService(DisplayManager.class); 333 mTaskbarManager = new TaskbarManager(this); 334 335 mRotationTouchHelper = mDeviceState.getRotationTouchHelper(); 336 mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged); 337 mDeviceState.addOneHandedModeChangedCallback(this::onOneHandedModeOverlayChanged); 338 mDeviceState.runOnUserUnlocked(this::onUserUnlocked); 339 mDeviceState.runOnUserUnlocked(mTaskbarManager::onUserUnlocked); 340 ProtoTracer.INSTANCE.get(this).add(this); 341 sConnected = true; 342 } 343 disposeEventHandlers()344 private void disposeEventHandlers() { 345 if (mInputEventReceiver != null) { 346 mInputEventReceiver.dispose(); 347 mInputEventReceiver = null; 348 } 349 if (mInputMonitorCompat != null) { 350 mInputMonitorCompat.dispose(); 351 mInputMonitorCompat = null; 352 } 353 } 354 initInputMonitor()355 private void initInputMonitor() { 356 disposeEventHandlers(); 357 358 if (mDeviceState.isButtonNavMode()) { 359 return; 360 } 361 362 mInputMonitorCompat = new InputMonitorCompat("swipe-up", mDeviceState.getDisplayId()); 363 mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(), 364 mMainChoreographer, this::onInputEvent); 365 366 mRotationTouchHelper.updateGestureTouchRegions(); 367 } 368 369 /** 370 * Called when the navigation mode changes, guaranteed to be after the device state has updated. 371 */ onNavigationModeChanged(SysUINavigationMode.Mode mode)372 private void onNavigationModeChanged(SysUINavigationMode.Mode mode) { 373 initInputMonitor(); 374 resetHomeBounceSeenOnQuickstepEnabledFirstTime(); 375 } 376 377 /** 378 * Called when the one handed mode overlay package changes, to recreate touch region. 379 */ onOneHandedModeOverlayChanged(int newGesturalHeight)380 private void onOneHandedModeOverlayChanged(int newGesturalHeight) { 381 initInputMonitor(); 382 } 383 384 @UiThread onUserUnlocked()385 public void onUserUnlocked() { 386 mTaskAnimationManager = new TaskAnimationManager(this); 387 mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState); 388 mOverviewCommandHelper = new OverviewCommandHelper(this, 389 mOverviewComponentObserver, mTaskAnimationManager); 390 mResetGestureInputConsumer = new ResetGestureInputConsumer(mTaskAnimationManager); 391 mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer(); 392 mInputConsumer.registerInputConsumer(); 393 onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags()); 394 onAssistantVisibilityChanged(); 395 396 // Temporarily disable model preload 397 // new ModelPreload().start(this); 398 mBackGestureNotificationCounter = Math.max(0, Utilities.getDevicePrefs(this) 399 .getInt(KEY_BACK_NOTIFICATION_COUNT, MAX_BACK_NOTIFICATION_COUNT)); 400 resetHomeBounceSeenOnQuickstepEnabledFirstTime(); 401 402 PluginManagerWrapper.INSTANCE.get(getBaseContext()).addPluginListener(this, 403 OverscrollPlugin.class, false /* allowMultiple */); 404 405 mOverviewComponentObserver.setOverviewChangeListener(this::onOverviewTargetChange); 406 onOverviewTargetChange(mOverviewComponentObserver.isHomeAndOverviewSame()); 407 } 408 getOverviewCommandHelper()409 public OverviewCommandHelper getOverviewCommandHelper() { 410 return mOverviewCommandHelper; 411 } 412 resetHomeBounceSeenOnQuickstepEnabledFirstTime()413 private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() { 414 if (!mDeviceState.isUserUnlocked() || mDeviceState.isButtonNavMode()) { 415 // Skip if not yet unlocked (can't read user shared prefs) or if the current navigation 416 // mode doesn't have gestures 417 return; 418 } 419 420 // Reset home bounce seen on quick step enabled for first time 421 SharedPreferences sharedPrefs = Utilities.getPrefs(this); 422 if (!sharedPrefs.getBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)) { 423 sharedPrefs.edit() 424 .putBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true) 425 .putBoolean(OnboardingPrefs.HOME_BOUNCE_SEEN, false) 426 .apply(); 427 } 428 } 429 onOverviewTargetChange(boolean isHomeAndOverviewSame)430 private void onOverviewTargetChange(boolean isHomeAndOverviewSame) { 431 AccessibilityManager am = getSystemService(AccessibilityManager.class); 432 433 if (isHomeAndOverviewSame) { 434 Intent intent = new Intent(mOverviewComponentObserver.getHomeIntent()) 435 .setAction(Intent.ACTION_ALL_APPS); 436 RemoteAction allAppsAction = new RemoteAction( 437 Icon.createWithResource(this, R.drawable.ic_apps), 438 getString(R.string.all_apps_label), 439 getString(R.string.all_apps_label), 440 PendingIntent.getActivity(this, SYSTEM_ACTION_ID_ALL_APPS, intent, 441 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)); 442 am.registerSystemAction(allAppsAction, SYSTEM_ACTION_ID_ALL_APPS); 443 } else { 444 am.unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS); 445 } 446 } 447 448 @UiThread onSystemUiFlagsChanged(int lastSysUIFlags)449 private void onSystemUiFlagsChanged(int lastSysUIFlags) { 450 if (mDeviceState.isUserUnlocked()) { 451 int systemUiStateFlags = mDeviceState.getSystemUiStateFlags(); 452 SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags); 453 mOverviewComponentObserver.onSystemUiStateChanged(); 454 mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags); 455 456 if ((lastSysUIFlags & SYSUI_STATE_TRACING_ENABLED) != 457 (systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED)) { 458 // Update the tracing state 459 if ((systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED) != 0) { 460 Log.d(TAG, "Starting tracing."); 461 ProtoTracer.INSTANCE.get(this).start(); 462 } else { 463 Log.d(TAG, "Stopping tracing. Dumping to file=" 464 + ProtoTracer.INSTANCE.get(this).getTraceFile()); 465 ProtoTracer.INSTANCE.get(this).stop(); 466 } 467 } 468 } 469 } 470 471 @UiThread onAssistantVisibilityChanged()472 private void onAssistantVisibilityChanged() { 473 if (mDeviceState.isUserUnlocked()) { 474 mOverviewComponentObserver.getActivityInterface().onAssistantVisibilityChanged( 475 mDeviceState.getAssistantVisibility()); 476 } 477 } 478 479 @Override onDestroy()480 public void onDestroy() { 481 Log.d(TAG, "Touch service destroyed: user=" + getUserId()); 482 sIsInitialized = false; 483 if (mDeviceState.isUserUnlocked()) { 484 mInputConsumer.unregisterInputConsumer(); 485 mOverviewComponentObserver.onDestroy(); 486 PluginManagerWrapper.INSTANCE.get(getBaseContext()).removePluginListener(this); 487 } 488 disposeEventHandlers(); 489 mDeviceState.destroy(); 490 SystemUiProxy.INSTANCE.get(this).clearProxy(); 491 ProtoTracer.INSTANCE.get(this).stop(); 492 ProtoTracer.INSTANCE.get(this).remove(this); 493 494 getSystemService(AccessibilityManager.class) 495 .unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS); 496 497 mTaskbarManager.destroy(); 498 sConnected = false; 499 super.onDestroy(); 500 } 501 502 @Override onBind(Intent intent)503 public IBinder onBind(Intent intent) { 504 Log.d(TAG, "Touch service connected: user=" + getUserId()); 505 return new TISBinder(); 506 } 507 onInputEvent(InputEvent ev)508 private void onInputEvent(InputEvent ev) { 509 if (!(ev instanceof MotionEvent)) { 510 Log.e(TAG, "Unknown event " + ev); 511 return; 512 } 513 MotionEvent event = (MotionEvent) ev; 514 if (ENABLE_PER_WINDOW_INPUT_ROTATION) { 515 final Display display = mDisplayManager.getDisplay(mDeviceState.getDisplayId()); 516 int rotation = display.getRotation(); 517 Point sz = new Point(); 518 display.getRealSize(sz); 519 if (rotation != Surface.ROTATION_0) { 520 event.transform(InputChannelCompat.createRotationMatrix(rotation, sz.x, sz.y)); 521 } 522 } 523 524 TestLogging.recordMotionEvent( 525 TestProtocol.SEQUENCE_TIS, "TouchInteractionService.onInputEvent", event); 526 527 if (!mDeviceState.isUserUnlocked()) { 528 return; 529 } 530 531 Object traceToken = TraceHelper.INSTANCE.beginFlagsOverride( 532 TraceHelper.FLAG_ALLOW_BINDER_TRACKING); 533 534 final int action = event.getAction(); 535 if (action == ACTION_DOWN) { 536 mRotationTouchHelper.setOrientationTransformIfNeeded(event); 537 538 if (!mDeviceState.isOneHandedModeActive() 539 && mRotationTouchHelper.isInSwipeUpTouchRegion(event)) { 540 // Clone the previous gesture state since onConsumerAboutToBeSwitched might trigger 541 // onConsumerInactive and wipe the previous gesture state 542 GestureState prevGestureState = new GestureState(mGestureState); 543 GestureState newGestureState = createGestureState(mGestureState); 544 newGestureState.setSwipeUpStartTimeMs(SystemClock.uptimeMillis()); 545 mConsumer.onConsumerAboutToBeSwitched(); 546 mGestureState = newGestureState; 547 mConsumer = newConsumer(prevGestureState, mGestureState, event); 548 549 ActiveGestureLog.INSTANCE.addLog("setInputConsumer: " + mConsumer.getName()); 550 mUncheckedConsumer = mConsumer; 551 } else if (mDeviceState.isUserUnlocked() && mDeviceState.isFullyGesturalNavMode()) { 552 mGestureState = createGestureState(mGestureState); 553 ActivityManager.RunningTaskInfo runningTask = mGestureState.getRunningTask(); 554 if (mDeviceState.canTriggerAssistantAction(event, runningTask)) { 555 // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we 556 // should not interrupt it. QuickSwitch assumes that interruption can only 557 // happen if the next gesture is also quick switch. 558 mUncheckedConsumer = new AssistantInputConsumer( 559 this, 560 mGestureState, 561 InputConsumer.NO_OP, mInputMonitorCompat, 562 mDeviceState, 563 event); 564 } else if (mDeviceState.canTriggerOneHandedAction(event)) { 565 // Consume gesture event for triggering one handed feature. 566 mUncheckedConsumer = new OneHandedModeInputConsumer(this, mDeviceState, 567 InputConsumer.NO_OP, mInputMonitorCompat); 568 } else { 569 mUncheckedConsumer = InputConsumer.NO_OP; 570 } 571 } else if (mDeviceState.canTriggerOneHandedAction(event)) { 572 // Consume gesture event for triggering one handed feature. 573 mUncheckedConsumer = new OneHandedModeInputConsumer(this, mDeviceState, 574 InputConsumer.NO_OP, mInputMonitorCompat); 575 } else { 576 mUncheckedConsumer = InputConsumer.NO_OP; 577 } 578 } else { 579 // Other events 580 if (mUncheckedConsumer != InputConsumer.NO_OP) { 581 // Only transform the event if we are handling it in a proper consumer 582 mRotationTouchHelper.setOrientationTransformIfNeeded(event); 583 } 584 } 585 586 if (mUncheckedConsumer != InputConsumer.NO_OP) { 587 switch (event.getActionMasked()) { 588 case ACTION_DOWN: 589 case ACTION_UP: 590 ActiveGestureLog.INSTANCE.addLog("onMotionEvent(" 591 + (int) event.getRawX() + ", " + (int) event.getRawY() + ")", 592 event.getActionMasked()); 593 break; 594 default: 595 ActiveGestureLog.INSTANCE.addLog("onMotionEvent", event.getActionMasked()); 596 break; 597 } 598 } 599 600 boolean cancelGesture = mGestureState.getActivityInterface() != null 601 && mGestureState.getActivityInterface().shouldCancelCurrentGesture(); 602 boolean cleanUpConsumer = (action == ACTION_UP || action == ACTION_CANCEL || cancelGesture) 603 && mConsumer != null 604 && !mConsumer.getActiveConsumerInHierarchy().isConsumerDetachedFromGesture(); 605 if (cancelGesture) { 606 event.setAction(ACTION_CANCEL); 607 } 608 mUncheckedConsumer.onMotionEvent(event); 609 610 if (cleanUpConsumer) { 611 reset(); 612 } 613 TraceHelper.INSTANCE.endFlagsOverride(traceToken); 614 ProtoTracer.INSTANCE.get(this).scheduleFrameUpdate(); 615 } 616 createGestureState(GestureState previousGestureState)617 public GestureState createGestureState(GestureState previousGestureState) { 618 GestureState gestureState = new GestureState(mOverviewComponentObserver, 619 ActiveGestureLog.INSTANCE.generateAndSetLogId()); 620 if (mTaskAnimationManager.isRecentsAnimationRunning()) { 621 gestureState.updateRunningTask(previousGestureState.getRunningTask()); 622 gestureState.updateLastStartedTaskId(previousGestureState.getLastStartedTaskId()); 623 gestureState.updatePreviouslyAppearedTaskIds( 624 previousGestureState.getPreviouslyAppearedTaskIds()); 625 } else { 626 gestureState.updateRunningTask(TraceHelper.allowIpcs("getRunningTask.0", 627 () -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */))); 628 } 629 return gestureState; 630 } 631 newConsumer(GestureState previousGestureState, GestureState newGestureState, MotionEvent event)632 private InputConsumer newConsumer(GestureState previousGestureState, 633 GestureState newGestureState, MotionEvent event) { 634 boolean canStartSystemGesture = mDeviceState.canStartSystemGesture(); 635 636 if (!mDeviceState.isUserUnlocked()) { 637 if (canStartSystemGesture) { 638 // This handles apps launched in direct boot mode (e.g. dialer) as well as apps 639 // launched while device is locked even after exiting direct boot mode (e.g. camera). 640 return createDeviceLockedInputConsumer(newGestureState); 641 } else { 642 return getDefaultInputConsumer(); 643 } 644 } 645 646 // When there is an existing recents animation running, bypass systemState check as this is 647 // a followup gesture and the first gesture started in a valid system state. 648 InputConsumer base = canStartSystemGesture 649 || previousGestureState.isRecentsAnimationRunning() 650 ? newBaseConsumer(previousGestureState, newGestureState, event) 651 : getDefaultInputConsumer(); 652 if (mDeviceState.isGesturalNavMode()) { 653 handleOrientationSetup(base); 654 } 655 if (mDeviceState.isFullyGesturalNavMode()) { 656 if (mDeviceState.canTriggerAssistantAction(event, newGestureState.getRunningTask())) { 657 base = new AssistantInputConsumer(this, newGestureState, base, mInputMonitorCompat, 658 mDeviceState, event); 659 } 660 661 if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) { 662 OverscrollPlugin plugin = null; 663 if (FeatureFlags.FORCE_LOCAL_OVERSCROLL_PLUGIN.get()) { 664 plugin = OverscrollPluginFactory.INSTANCE.get( 665 getApplicationContext()).getLocalOverscrollPlugin(); 666 } 667 668 // If not local plugin was forced, use the actual overscroll plugin if available. 669 if (plugin == null && mOverscrollPlugin != null && mOverscrollPlugin.isActive()) { 670 plugin = mOverscrollPlugin; 671 } 672 673 if (plugin != null) { 674 // Put the overscroll gesture as higher priority than the Assistant or base 675 // gestures 676 base = new OverscrollInputConsumer(this, newGestureState, base, 677 mInputMonitorCompat, plugin); 678 } 679 } 680 681 // If Bubbles is expanded, use the overlay input consumer, which will close Bubbles 682 // instead of going all the way home when a swipe up is detected. 683 if (mDeviceState.isBubblesExpanded() || mDeviceState.isGlobalActionsShowing()) { 684 base = new SysUiOverlayInputConsumer( 685 getBaseContext(), mDeviceState, mInputMonitorCompat); 686 } 687 688 if (mDeviceState.isScreenPinningActive()) { 689 // Note: we only allow accessibility to wrap this, and it replaces the previous 690 // base input consumer (which should be NO_OP anyway since topTaskLocked == true). 691 base = new ScreenPinnedInputConsumer(this, newGestureState); 692 } 693 694 if (mDeviceState.canTriggerOneHandedAction(event)) { 695 base = new OneHandedModeInputConsumer(this, mDeviceState, base, 696 mInputMonitorCompat); 697 } 698 699 if (mDeviceState.isAccessibilityMenuAvailable()) { 700 base = new AccessibilityInputConsumer(this, mDeviceState, base, 701 mInputMonitorCompat); 702 } 703 } else { 704 if (mDeviceState.isScreenPinningActive()) { 705 base = getDefaultInputConsumer(); 706 } 707 708 if (mDeviceState.canTriggerOneHandedAction(event)) { 709 base = new OneHandedModeInputConsumer(this, mDeviceState, base, 710 mInputMonitorCompat); 711 } 712 } 713 return base; 714 } 715 handleOrientationSetup(InputConsumer baseInputConsumer)716 private void handleOrientationSetup(InputConsumer baseInputConsumer) { 717 baseInputConsumer.notifyOrientationSetup(); 718 } 719 newBaseConsumer(GestureState previousGestureState, GestureState gestureState, MotionEvent event)720 private InputConsumer newBaseConsumer(GestureState previousGestureState, 721 GestureState gestureState, MotionEvent event) { 722 if (mDeviceState.isKeyguardShowingOccluded()) { 723 // This handles apps showing over the lockscreen (e.g. camera) 724 return createDeviceLockedInputConsumer(gestureState); 725 } 726 727 // Use overview input consumer for sharesheets on top of home. 728 boolean forceOverviewInputConsumer = gestureState.getActivityInterface().isStarted() 729 && gestureState.getRunningTask() != null 730 && ACTION_CHOOSER.equals(gestureState.getRunningTask().baseIntent.getAction()); 731 if (AssistantUtilities.isExcludedAssistant(gestureState.getRunningTask())) { 732 // In the case where we are in the excluded assistant state, ignore it and treat the 733 // running activity as the task behind the assistant 734 gestureState.updateRunningTask(TraceHelper.allowIpcs("getRunningTask.assistant", 735 () -> mAM.getRunningTask(true /* filterOnlyVisibleRecents */))); 736 ComponentName homeComponent = mOverviewComponentObserver.getHomeIntent().getComponent(); 737 ComponentName runningComponent = 738 gestureState.getRunningTask().baseIntent.getComponent(); 739 forceOverviewInputConsumer = 740 runningComponent != null && runningComponent.equals(homeComponent); 741 } 742 743 if (ENABLE_QUICKSTEP_LIVE_TILE.get() 744 && gestureState.getActivityInterface().isInLiveTileMode()) { 745 return createOverviewInputConsumer( 746 previousGestureState, gestureState, event, forceOverviewInputConsumer); 747 } else if (gestureState.getRunningTask() == null) { 748 return getDefaultInputConsumer(); 749 } else if (previousGestureState.isRunningAnimationToLauncher() 750 || gestureState.getActivityInterface().isResumed() 751 || forceOverviewInputConsumer) { 752 return createOverviewInputConsumer( 753 previousGestureState, gestureState, event, forceOverviewInputConsumer); 754 } else if (mDeviceState.isGestureBlockedActivity(gestureState.getRunningTask())) { 755 return getDefaultInputConsumer(); 756 } else { 757 return createOtherActivityInputConsumer(gestureState, event); 758 } 759 } 760 getSwipeUpHandlerFactory()761 public AbsSwipeUpHandler.Factory getSwipeUpHandlerFactory() { 762 return !mOverviewComponentObserver.isHomeAndOverviewSame() 763 ? mFallbackSwipeHandlerFactory : mLauncherSwipeHandlerFactory; 764 } 765 createOtherActivityInputConsumer(GestureState gestureState, MotionEvent event)766 private InputConsumer createOtherActivityInputConsumer(GestureState gestureState, 767 MotionEvent event) { 768 769 final AbsSwipeUpHandler.Factory factory = getSwipeUpHandlerFactory(); 770 final boolean shouldDefer = !mOverviewComponentObserver.isHomeAndOverviewSame() 771 || gestureState.getActivityInterface().deferStartingActivity(mDeviceState, event); 772 final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event); 773 return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager, 774 gestureState, shouldDefer, this::onConsumerInactive, 775 mInputMonitorCompat, mInputEventReceiver, disableHorizontalSwipe, factory); 776 } 777 createDeviceLockedInputConsumer(GestureState gestureState)778 private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState) { 779 if (mDeviceState.isFullyGesturalNavMode() && gestureState.getRunningTask() != null) { 780 return new DeviceLockedInputConsumer(this, mDeviceState, mTaskAnimationManager, 781 gestureState, mInputMonitorCompat); 782 } else { 783 return getDefaultInputConsumer(); 784 } 785 } 786 createOverviewInputConsumer(GestureState previousGestureState, GestureState gestureState, MotionEvent event, boolean forceOverviewInputConsumer)787 public InputConsumer createOverviewInputConsumer(GestureState previousGestureState, 788 GestureState gestureState, MotionEvent event, 789 boolean forceOverviewInputConsumer) { 790 StatefulActivity activity = gestureState.getActivityInterface().getCreatedActivity(); 791 if (activity == null) { 792 return getDefaultInputConsumer(); 793 } 794 795 if (activity.getRootView().hasWindowFocus() 796 || previousGestureState.isRunningAnimationToLauncher() 797 || (ASSISTANT_GIVES_LAUNCHER_FOCUS.get() 798 && forceOverviewInputConsumer) 799 || (ENABLE_QUICKSTEP_LIVE_TILE.get() 800 && gestureState.getActivityInterface().isInLiveTileMode())) { 801 return new OverviewInputConsumer(gestureState, activity, mInputMonitorCompat, 802 false /* startingInActivityBounds */); 803 } else { 804 final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event); 805 return new OverviewWithoutFocusInputConsumer(activity, mDeviceState, gestureState, 806 mInputMonitorCompat, disableHorizontalSwipe); 807 } 808 } 809 810 /** 811 * To be called by the consumer when it's no longer active. This can be called by any consumer 812 * in the hierarchy at any point during the gesture (ie. if a delegate consumer starts 813 * intercepting touches, the base consumer can try to call this). 814 */ onConsumerInactive(InputConsumer caller)815 private void onConsumerInactive(InputConsumer caller) { 816 if (mConsumer != null && mConsumer.getActiveConsumerInHierarchy() == caller) { 817 reset(); 818 } 819 } 820 reset()821 private void reset() { 822 mConsumer = mUncheckedConsumer = getDefaultInputConsumer(); 823 mGestureState = DEFAULT_STATE; 824 // By default, use batching of the input events, but check receiver before using in the rare 825 // case that the monitor was disposed before the swipe settled 826 if (mInputEventReceiver != null) { 827 mInputEventReceiver.setBatchingEnabled(true); 828 } 829 } 830 831 /** 832 * Returns the {@link ResetGestureInputConsumer} if user is unlocked, else NO_OP. 833 */ getDefaultInputConsumer()834 private @NonNull InputConsumer getDefaultInputConsumer() { 835 if (mResetGestureInputConsumer != null) { 836 return mResetGestureInputConsumer; 837 } else { 838 // mResetGestureInputConsumer isn't initialized until onUserUnlocked(), so reset to 839 // NO_OP until then (we never want these to be null). 840 return InputConsumer.NO_OP; 841 } 842 } 843 preloadOverview(boolean fromInit)844 private void preloadOverview(boolean fromInit) { 845 if (!mDeviceState.isUserUnlocked()) { 846 return; 847 } 848 849 if (mDeviceState.isButtonNavMode() && !mOverviewComponentObserver.isHomeAndOverviewSame()) { 850 // Prevent the overview from being started before the real home on first boot. 851 return; 852 } 853 854 if (RestoreDbTask.isPending(this) || !mDeviceState.isUserSetupComplete()) { 855 // Preloading while a restore is pending may cause launcher to start the restore 856 // too early. 857 return; 858 } 859 860 final BaseActivityInterface activityInterface = 861 mOverviewComponentObserver.getActivityInterface(); 862 final Intent overviewIntent = new Intent( 863 mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState()); 864 if (activityInterface.getCreatedActivity() != null && fromInit) { 865 // The activity has been created before the initialization of overview service. It is 866 // usually happens when booting or launcher is the top activity, so we should already 867 // have the latest state. 868 return; 869 } 870 871 mTaskAnimationManager.preloadRecentsAnimation(overviewIntent); 872 } 873 874 @Override onConfigurationChanged(Configuration newConfig)875 public void onConfigurationChanged(Configuration newConfig) { 876 if (!mDeviceState.isUserUnlocked()) { 877 return; 878 } 879 final BaseActivityInterface activityInterface = 880 mOverviewComponentObserver.getActivityInterface(); 881 final BaseDraggingActivity activity = activityInterface.getCreatedActivity(); 882 if (activity == null || activity.isStarted()) { 883 // We only care about the existing background activity. 884 return; 885 } 886 if (mOverviewComponentObserver.canHandleConfigChanges(activity.getComponentName(), 887 activity.getResources().getConfiguration().diff(newConfig))) { 888 // Since navBar gestural height are different between portrait and landscape, 889 // can handle orientation changes and refresh navigation gestural region through 890 // onOneHandedModeChanged() 891 int newGesturalHeight = ResourceUtils.getNavbarSize( 892 ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, 893 getApplicationContext().getResources()); 894 mDeviceState.onOneHandedModeChanged(newGesturalHeight); 895 return; 896 } 897 898 preloadOverview(false /* fromInit */); 899 } 900 901 @Override dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs)902 protected void dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs) { 903 if (rawArgs.length > 0 && Utilities.IS_DEBUG_DEVICE) { 904 LinkedList<String> args = new LinkedList(Arrays.asList(rawArgs)); 905 switch (args.pollFirst()) { 906 case "cmd": 907 if (args.peekFirst() == null) { 908 printAvailableCommands(pw); 909 } else { 910 onCommand(pw, args); 911 } 912 break; 913 } 914 } else { 915 // Dump everything 916 FeatureFlags.dump(pw); 917 if (mDeviceState.isUserUnlocked()) { 918 PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw); 919 } 920 mDeviceState.dump(pw); 921 if (mOverviewComponentObserver != null) { 922 mOverviewComponentObserver.dump(pw); 923 } 924 if (mGestureState != null) { 925 mGestureState.dump(pw); 926 } 927 pw.println("Input state:"); 928 pw.println(" mInputMonitorCompat=" + mInputMonitorCompat); 929 pw.println(" mInputEventReceiver=" + mInputEventReceiver); 930 SysUINavigationMode.INSTANCE.get(this).dump(pw); 931 pw.println("TouchState:"); 932 BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null 933 : mOverviewComponentObserver.getActivityInterface().getCreatedActivity(); 934 boolean resumed = mOverviewComponentObserver != null 935 && mOverviewComponentObserver.getActivityInterface().isResumed(); 936 pw.println(" createdOverviewActivity=" + createdOverviewActivity); 937 pw.println(" resumed=" + resumed); 938 pw.println(" mConsumer=" + mConsumer.getName()); 939 ActiveGestureLog.INSTANCE.dump("", pw); 940 pw.println("ProtoTrace:"); 941 pw.println(" file=" + ProtoTracer.INSTANCE.get(this).getTraceFile()); 942 } 943 } 944 printAvailableCommands(PrintWriter pw)945 private void printAvailableCommands(PrintWriter pw) { 946 pw.println("Available commands:"); 947 pw.println(" clear-touch-log: Clears the touch interaction log"); 948 } 949 onCommand(PrintWriter pw, LinkedList<String> args)950 private void onCommand(PrintWriter pw, LinkedList<String> args) { 951 switch (args.pollFirst()) { 952 case "clear-touch-log": 953 ActiveGestureLog.INSTANCE.clear(); 954 break; 955 } 956 } 957 createLauncherSwipeHandler( GestureState gestureState, long touchTimeMs)958 private AbsSwipeUpHandler createLauncherSwipeHandler( 959 GestureState gestureState, long touchTimeMs) { 960 return new LauncherSwipeHandlerV2(this, mDeviceState, mTaskAnimationManager, 961 gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(), 962 mInputConsumer); 963 } 964 createFallbackSwipeHandler( GestureState gestureState, long touchTimeMs)965 private AbsSwipeUpHandler createFallbackSwipeHandler( 966 GestureState gestureState, long touchTimeMs) { 967 return new FallbackSwipeHandler(this, mDeviceState, mTaskAnimationManager, 968 gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(), 969 mInputConsumer); 970 } 971 shouldNotifyBackGesture()972 protected boolean shouldNotifyBackGesture() { 973 return mBackGestureNotificationCounter > 0 && 974 !mDeviceState.getGestureBlockedActivityPackages().isEmpty(); 975 } 976 977 @WorkerThread tryNotifyBackGesture()978 protected void tryNotifyBackGesture() { 979 if (shouldNotifyBackGesture()) { 980 mBackGestureNotificationCounter--; 981 Utilities.getDevicePrefs(this).edit() 982 .putInt(KEY_BACK_NOTIFICATION_COUNT, mBackGestureNotificationCounter).apply(); 983 mDeviceState.getGestureBlockedActivityPackages().forEach(blockedPackage -> 984 sendBroadcast(new Intent(NOTIFY_ACTION_BACK).setPackage(blockedPackage))); 985 } 986 } 987 988 @Override onPluginConnected(OverscrollPlugin overscrollPlugin, Context context)989 public void onPluginConnected(OverscrollPlugin overscrollPlugin, Context context) { 990 mOverscrollPlugin = overscrollPlugin; 991 } 992 993 @Override onPluginDisconnected(OverscrollPlugin overscrollPlugin)994 public void onPluginDisconnected(OverscrollPlugin overscrollPlugin) { 995 mOverscrollPlugin = null; 996 } 997 998 @Override writeToProto(LauncherTraceProto.Builder proto)999 public void writeToProto(LauncherTraceProto.Builder proto) { 1000 TouchInteractionServiceProto.Builder serviceProto = 1001 TouchInteractionServiceProto.newBuilder(); 1002 serviceProto.setServiceConnected(true); 1003 1004 if (mOverviewComponentObserver != null) { 1005 mOverviewComponentObserver.writeToProto(serviceProto); 1006 } 1007 mConsumer.writeToProto(serviceProto); 1008 1009 proto.setTouchInteractionService(serviceProto); 1010 } 1011 } 1012