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