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.view.MotionEvent.ACTION_DOWN; 19 20 import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM; 21 import static com.android.launcher3.config.FeatureFlags.APPLY_CONFIG_AT_RUNTIME; 22 import static com.android.launcher3.config.FeatureFlags.ENABLE_HINTS_IN_OVERVIEW; 23 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; 24 import static com.android.launcher3.config.FeatureFlags.FAKE_LANDSCAPE_UI; 25 import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS; 26 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR; 27 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; 28 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE; 29 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE; 30 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED; 31 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN; 32 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; 33 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; 34 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; 35 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED; 36 37 import android.annotation.TargetApi; 38 import android.app.ActivityManager; 39 import android.app.ActivityManager.RunningTaskInfo; 40 import android.app.Service; 41 import android.content.BroadcastReceiver; 42 import android.content.ComponentName; 43 import android.content.Context; 44 import android.content.Intent; 45 import android.content.IntentFilter; 46 import android.graphics.Point; 47 import android.graphics.RectF; 48 import android.graphics.Region; 49 import android.hardware.display.DisplayManager; 50 import android.hardware.display.DisplayManager.DisplayListener; 51 import android.os.Build; 52 import android.os.Bundle; 53 import android.os.IBinder; 54 import android.os.Looper; 55 import android.os.Process; 56 import android.os.RemoteException; 57 import android.text.TextUtils; 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.WindowManager; 65 66 import androidx.annotation.BinderThread; 67 import androidx.annotation.UiThread; 68 69 import com.android.launcher3.BaseDraggingActivity; 70 import com.android.launcher3.MainThreadExecutor; 71 import com.android.launcher3.R; 72 import com.android.launcher3.ResourceUtils; 73 import com.android.launcher3.Utilities; 74 import com.android.launcher3.compat.UserManagerCompat; 75 import com.android.launcher3.logging.EventLogArray; 76 import com.android.launcher3.logging.UserEventDispatcher; 77 import com.android.launcher3.util.LooperExecutor; 78 import com.android.launcher3.util.UiThreadHelper; 79 import com.android.quickstep.SysUINavigationMode.Mode; 80 import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener; 81 import com.android.quickstep.inputconsumers.AccessibilityInputConsumer; 82 import com.android.quickstep.inputconsumers.AssistantTouchConsumer; 83 import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer; 84 import com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer; 85 import com.android.quickstep.inputconsumers.InputConsumer; 86 import com.android.quickstep.inputconsumers.OtherActivityInputConsumer; 87 import com.android.quickstep.inputconsumers.OverviewInputConsumer; 88 import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer; 89 import com.android.quickstep.inputconsumers.ResetGestureInputConsumer; 90 import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer; 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.system.QuickStepContract; 98 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; 99 import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat; 100 101 import java.io.FileDescriptor; 102 import java.io.PrintWriter; 103 import java.util.Arrays; 104 import java.util.LinkedList; 105 import java.util.List; 106 107 /** 108 * Wrapper around a list for processing arguments. 109 */ 110 class ArgList extends LinkedList<String> { ArgList(List<String> l)111 public ArgList(List<String> l) { 112 super(l); 113 } 114 peekArg()115 public String peekArg() { 116 return peekFirst(); 117 } 118 nextArg()119 public String nextArg() { 120 return pollFirst().toLowerCase(); 121 } 122 nextArgExact()123 public String nextArgExact() { 124 return pollFirst(); 125 } 126 } 127 128 /** 129 * Service connected by system-UI for handling touch interaction. 130 */ 131 @TargetApi(Build.VERSION_CODES.Q) 132 public class TouchInteractionService extends Service implements 133 NavigationModeChangeListener, DisplayListener { 134 135 public static final MainThreadExecutor MAIN_THREAD_EXECUTOR = new MainThreadExecutor(); 136 public static final LooperExecutor BACKGROUND_EXECUTOR = 137 new LooperExecutor(UiThreadHelper.getBackgroundLooper()); 138 139 public static final EventLogArray TOUCH_INTERACTION_LOG = 140 new EventLogArray("touch_interaction_log", 40); 141 142 private static final String TAG = "TouchInteractionService"; 143 144 private final IBinder mMyBinder = new IOverviewProxy.Stub() { 145 146 public void onActiveNavBarRegionChanges(Region region) { 147 mActiveNavBarRegion = region; 148 } 149 150 public void onInitialize(Bundle bundle) { 151 mISystemUiProxy = ISystemUiProxy.Stub 152 .asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY)); 153 MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::initInputMonitor); 154 MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::onSystemUiProxySet); 155 } 156 157 @Override 158 public void onOverviewToggle() { 159 mOverviewCommandHelper.onOverviewToggle(); 160 } 161 162 @Override 163 public void onOverviewShown(boolean triggeredFromAltTab) { 164 mOverviewCommandHelper.onOverviewShown(triggeredFromAltTab); 165 } 166 167 @Override 168 public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 169 if (triggeredFromAltTab && !triggeredFromHomeKey) { 170 // onOverviewShownFromAltTab hides the overview and ends at the target app 171 mOverviewCommandHelper.onOverviewHidden(); 172 } 173 } 174 175 @Override 176 public void onTip(int actionType, int viewType) { 177 mOverviewCommandHelper.onTip(actionType, viewType); 178 } 179 180 @Override 181 public void onAssistantAvailable(boolean available) { 182 mAssistantAvailable = available; 183 } 184 185 @Override 186 public void onAssistantVisibilityChanged(float visibility) { 187 mLastAssistantVisibility = visibility; 188 MAIN_THREAD_EXECUTOR.execute( 189 TouchInteractionService.this::onAssistantVisibilityChanged); 190 } 191 192 public void onBackAction(boolean completed, int downX, int downY, boolean isButton, 193 boolean gestureSwipeLeft) { 194 if (mOverviewComponentObserver == null) { 195 return; 196 } 197 198 final ActivityControlHelper activityControl = 199 mOverviewComponentObserver.getActivityControlHelper(); 200 UserEventDispatcher.newInstance(getBaseContext()).logActionBack(completed, downX, downY, 201 isButton, gestureSwipeLeft, activityControl.getContainerType()); 202 } 203 204 public void onSystemUiStateChanged(int stateFlags) { 205 mSystemUiStateFlags = stateFlags; 206 MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::onSystemUiFlagsChanged); 207 } 208 209 /** Deprecated methods **/ 210 public void onQuickStep(MotionEvent motionEvent) { } 211 212 public void onQuickScrubEnd() { } 213 214 public void onQuickScrubProgress(float progress) { } 215 216 public void onQuickScrubStart() { } 217 218 public void onPreMotionEvent(int downHitTarget) { } 219 220 public void onMotionEvent(MotionEvent ev) { 221 ev.recycle(); 222 } 223 224 public void onBind(ISystemUiProxy iSystemUiProxy) { } 225 }; 226 227 private static boolean sConnected = false; 228 private static final SwipeSharedState sSwipeSharedState = new SwipeSharedState(); 229 isConnected()230 public static boolean isConnected() { 231 return sConnected; 232 } 233 getSwipeSharedState()234 public static SwipeSharedState getSwipeSharedState() { 235 return sSwipeSharedState; 236 } 237 238 private final InputConsumer mResetGestureInputConsumer = 239 new ResetGestureInputConsumer(sSwipeSharedState); 240 241 private ActivityManagerWrapper mAM; 242 private RecentsModel mRecentsModel; 243 private ISystemUiProxy mISystemUiProxy; 244 private OverviewCommandHelper mOverviewCommandHelper; 245 private OverviewComponentObserver mOverviewComponentObserver; 246 private OverviewInteractionState mOverviewInteractionState; 247 private OverviewCallbacks mOverviewCallbacks; 248 private TaskOverlayFactory mTaskOverlayFactory; 249 private InputConsumerController mInputConsumer; 250 private boolean mAssistantAvailable; 251 private float mLastAssistantVisibility = 0; 252 private @SystemUiStateFlags int mSystemUiStateFlags; 253 254 private boolean mIsUserUnlocked; 255 private BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() { 256 @Override 257 public void onReceive(Context context, Intent intent) { 258 if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { 259 initWhenUserUnlocked(); 260 } 261 } 262 }; 263 264 private InputConsumer mUncheckedConsumer = InputConsumer.NO_OP; 265 private InputConsumer mConsumer = InputConsumer.NO_OP; 266 private Choreographer mMainChoreographer; 267 268 private Region mActiveNavBarRegion = new Region(); 269 270 private InputMonitorCompat mInputMonitorCompat; 271 private InputEventReceiver mInputEventReceiver; 272 private Mode mMode = Mode.THREE_BUTTONS; 273 private int mDefaultDisplayId; 274 private final RectF mSwipeTouchRegion = new RectF(); 275 private final RectF mAssistantLeftRegion = new RectF(); 276 private final RectF mAssistantRightRegion = new RectF(); 277 278 private ComponentName mGestureBlockingActivity; 279 280 private Region mExclusionRegion; 281 private SystemGestureExclusionListenerCompat mExclusionListener; 282 283 @Override onCreate()284 public void onCreate() { 285 super.onCreate(); 286 287 // Initialize anything here that is needed in direct boot mode. 288 // Everything else should be initialized in initWhenUserUnlocked() below. 289 mMainChoreographer = Choreographer.getInstance(); 290 mAM = ActivityManagerWrapper.getInstance(); 291 292 if (UserManagerCompat.getInstance(this).isUserUnlocked(Process.myUserHandle())) { 293 initWhenUserUnlocked(); 294 } else { 295 mIsUserUnlocked = false; 296 registerReceiver(mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED)); 297 } 298 299 mDefaultDisplayId = getSystemService(WindowManager.class).getDefaultDisplay() 300 .getDisplayId(); 301 String blockingActivity = getString(R.string.gesture_blocking_activity); 302 mGestureBlockingActivity = TextUtils.isEmpty(blockingActivity) ? null : 303 ComponentName.unflattenFromString(blockingActivity); 304 305 mExclusionListener = new SystemGestureExclusionListenerCompat(mDefaultDisplayId) { 306 @Override 307 @BinderThread 308 public void onExclusionChanged(Region region) { 309 // Assignments are atomic, it should be safe on binder thread 310 mExclusionRegion = region; 311 } 312 }; 313 314 onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this)); 315 sConnected = true; 316 } 317 disposeEventHandlers()318 private void disposeEventHandlers() { 319 if (mInputEventReceiver != null) { 320 mInputEventReceiver.dispose(); 321 mInputEventReceiver = null; 322 } 323 if (mInputMonitorCompat != null) { 324 mInputMonitorCompat.dispose(); 325 mInputMonitorCompat = null; 326 } 327 } 328 initInputMonitor()329 private void initInputMonitor() { 330 if (!mMode.hasGestures || mISystemUiProxy == null) { 331 return; 332 } 333 disposeEventHandlers(); 334 335 try { 336 mInputMonitorCompat = InputMonitorCompat.fromBundle(mISystemUiProxy 337 .monitorGestureInput("swipe-up", mDefaultDisplayId), KEY_EXTRA_INPUT_MONITOR); 338 mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(), 339 mMainChoreographer, this::onInputEvent); 340 } catch (RemoteException e) { 341 Log.e(TAG, "Unable to create input monitor", e); 342 } 343 initTouchBounds(); 344 } 345 getNavbarSize(String resName)346 private int getNavbarSize(String resName) { 347 return ResourceUtils.getNavbarSize(resName, getResources()); 348 } 349 initTouchBounds()350 private void initTouchBounds() { 351 if (!mMode.hasGestures) { 352 return; 353 } 354 355 Display defaultDisplay = getSystemService(WindowManager.class).getDefaultDisplay(); 356 Point realSize = new Point(); 357 defaultDisplay.getRealSize(realSize); 358 mSwipeTouchRegion.set(0, 0, realSize.x, realSize.y); 359 if (mMode == Mode.NO_BUTTON) { 360 int touchHeight = getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE); 361 mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - touchHeight; 362 363 final int assistantWidth = getResources() 364 .getDimensionPixelSize(R.dimen.gestures_assistant_width); 365 final float assistantHeight = Math.max(touchHeight, 366 QuickStepContract.getWindowCornerRadius(getResources())); 367 mAssistantLeftRegion.bottom = mAssistantRightRegion.bottom = mSwipeTouchRegion.bottom; 368 mAssistantLeftRegion.top = mAssistantRightRegion.top = 369 mSwipeTouchRegion.bottom - assistantHeight; 370 371 mAssistantLeftRegion.left = 0; 372 mAssistantLeftRegion.right = assistantWidth; 373 374 mAssistantRightRegion.right = mSwipeTouchRegion.right; 375 mAssistantRightRegion.left = mSwipeTouchRegion.right - assistantWidth; 376 } else { 377 mAssistantLeftRegion.setEmpty(); 378 mAssistantRightRegion.setEmpty(); 379 switch (defaultDisplay.getRotation()) { 380 case Surface.ROTATION_90: 381 mSwipeTouchRegion.left = mSwipeTouchRegion.right 382 - getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE); 383 break; 384 case Surface.ROTATION_270: 385 mSwipeTouchRegion.right = mSwipeTouchRegion.left 386 + getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE); 387 break; 388 default: 389 mSwipeTouchRegion.top = mSwipeTouchRegion.bottom 390 - getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE); 391 } 392 } 393 } 394 395 @Override onNavigationModeChanged(Mode newMode)396 public void onNavigationModeChanged(Mode newMode) { 397 if (mMode.hasGestures != newMode.hasGestures) { 398 if (newMode.hasGestures) { 399 getSystemService(DisplayManager.class).registerDisplayListener( 400 this, MAIN_THREAD_EXECUTOR.getHandler()); 401 } else { 402 getSystemService(DisplayManager.class).unregisterDisplayListener(this); 403 } 404 } 405 mMode = newMode; 406 407 disposeEventHandlers(); 408 initInputMonitor(); 409 410 if (mMode == Mode.NO_BUTTON) { 411 mExclusionListener.register(); 412 } else { 413 mExclusionListener.unregister(); 414 } 415 } 416 417 @Override onDisplayAdded(int i)418 public void onDisplayAdded(int i) { } 419 420 @Override onDisplayRemoved(int i)421 public void onDisplayRemoved(int i) { } 422 423 @Override onDisplayChanged(int displayId)424 public void onDisplayChanged(int displayId) { 425 if (displayId != mDefaultDisplayId) { 426 return; 427 } 428 429 initTouchBounds(); 430 } 431 initWhenUserUnlocked()432 private void initWhenUserUnlocked() { 433 mRecentsModel = RecentsModel.INSTANCE.get(this); 434 mOverviewComponentObserver = new OverviewComponentObserver(this); 435 436 mOverviewCommandHelper = new OverviewCommandHelper(this, mOverviewComponentObserver); 437 mOverviewInteractionState = OverviewInteractionState.INSTANCE.get(this); 438 mOverviewCallbacks = OverviewCallbacks.get(this); 439 mTaskOverlayFactory = TaskOverlayFactory.INSTANCE.get(this); 440 mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer(); 441 mIsUserUnlocked = true; 442 443 sSwipeSharedState.setOverviewComponentObserver(mOverviewComponentObserver); 444 mInputConsumer.registerInputConsumer(); 445 onSystemUiProxySet(); 446 onSystemUiFlagsChanged(); 447 onAssistantVisibilityChanged(); 448 449 // Temporarily disable model preload 450 // new ModelPreload().start(this); 451 452 Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver); 453 } 454 455 @UiThread onSystemUiProxySet()456 private void onSystemUiProxySet() { 457 if (mIsUserUnlocked) { 458 mRecentsModel.setSystemUiProxy(mISystemUiProxy); 459 mOverviewInteractionState.setSystemUiProxy(mISystemUiProxy); 460 } 461 } 462 463 @UiThread onSystemUiFlagsChanged()464 private void onSystemUiFlagsChanged() { 465 if (mIsUserUnlocked) { 466 mOverviewInteractionState.setSystemUiStateFlags(mSystemUiStateFlags); 467 mOverviewComponentObserver.onSystemUiStateChanged(mSystemUiStateFlags); 468 } 469 } 470 471 @UiThread onAssistantVisibilityChanged()472 private void onAssistantVisibilityChanged() { 473 if (mIsUserUnlocked) { 474 mOverviewComponentObserver.getActivityControlHelper().onAssistantVisibilityChanged( 475 mLastAssistantVisibility); 476 } 477 } 478 479 @Override onDestroy()480 public void onDestroy() { 481 if (mIsUserUnlocked) { 482 mInputConsumer.unregisterInputConsumer(); 483 mOverviewComponentObserver.onDestroy(); 484 } 485 disposeEventHandlers(); 486 if (mMode.hasGestures) { 487 getSystemService(DisplayManager.class).unregisterDisplayListener(this); 488 } 489 490 sConnected = false; 491 Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver); 492 SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this); 493 mExclusionListener.unregister(); 494 495 super.onDestroy(); 496 } 497 498 @Override onBind(Intent intent)499 public IBinder onBind(Intent intent) { 500 Log.d(TAG, "Touch service connected"); 501 return mMyBinder; 502 } 503 onInputEvent(InputEvent ev)504 private void onInputEvent(InputEvent ev) { 505 if (!(ev instanceof MotionEvent)) { 506 Log.e(TAG, "Unknown event " + ev); 507 return; 508 } 509 MotionEvent event = (MotionEvent) ev; 510 TOUCH_INTERACTION_LOG.addLog("onMotionEvent", event.getActionMasked()); 511 if (event.getAction() == ACTION_DOWN) { 512 if (mSwipeTouchRegion.contains(event.getX(), event.getY())) { 513 boolean useSharedState = mConsumer.useSharedSwipeState(); 514 mConsumer.onConsumerAboutToBeSwitched(); 515 mConsumer = newConsumer(useSharedState, event); 516 TOUCH_INTERACTION_LOG.addLog("setInputConsumer", mConsumer.getType()); 517 mUncheckedConsumer = mConsumer; 518 } else if (mIsUserUnlocked && mMode == Mode.NO_BUTTON 519 && canTriggerAssistantAction(event)) { 520 // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we should 521 // not interrupt it. QuickSwitch assumes that interruption can only happen if the 522 // next gesture is also quick switch. 523 mUncheckedConsumer = 524 new AssistantTouchConsumer(this, mISystemUiProxy, 525 mOverviewComponentObserver.getActivityControlHelper(), 526 InputConsumer.NO_OP, mInputMonitorCompat); 527 } else { 528 mUncheckedConsumer = InputConsumer.NO_OP; 529 } 530 } 531 mUncheckedConsumer.onMotionEvent(event); 532 } 533 validSystemUiFlags()534 private boolean validSystemUiFlags() { 535 return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0 536 && (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0 537 && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0 538 || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0); 539 } 540 canTriggerAssistantAction(MotionEvent ev)541 private boolean canTriggerAssistantAction(MotionEvent ev) { 542 return mAssistantAvailable 543 && !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags) 544 && (mAssistantLeftRegion.contains(ev.getX(), ev.getY()) || 545 mAssistantRightRegion.contains(ev.getX(), ev.getY())) 546 && !ActivityManagerWrapper.getInstance().isLockToAppActive(); 547 } 548 newConsumer(boolean useSharedState, MotionEvent event)549 private InputConsumer newConsumer(boolean useSharedState, MotionEvent event) { 550 boolean isInValidSystemUiState = validSystemUiFlags(); 551 552 if (!mIsUserUnlocked) { 553 if (isInValidSystemUiState) { 554 // This handles apps launched in direct boot mode (e.g. dialer) as well as apps 555 // launched while device is locked even after exiting direct boot mode (e.g. camera). 556 return createDeviceLockedInputConsumer(mAM.getRunningTask(0)); 557 } else { 558 return mResetGestureInputConsumer; 559 } 560 } 561 562 // When using sharedState, bypass systemState check as this is a followup gesture and the 563 // first gesture started in a valid system state. 564 InputConsumer base = isInValidSystemUiState || useSharedState 565 ? newBaseConsumer(useSharedState, event) : mResetGestureInputConsumer; 566 if (mMode == Mode.NO_BUTTON) { 567 final ActivityControlHelper activityControl = 568 mOverviewComponentObserver.getActivityControlHelper(); 569 if (canTriggerAssistantAction(event)) { 570 base = new AssistantTouchConsumer(this, mISystemUiProxy, activityControl, base, 571 mInputMonitorCompat); 572 } 573 574 if ((mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0) { 575 // Note: we only allow accessibility to wrap this, and it replaces the previous 576 // base input consumer (which should be NO_OP anyway since topTaskLocked == true). 577 base = new ScreenPinnedInputConsumer(this, mISystemUiProxy, activityControl); 578 } 579 580 if ((mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0) { 581 base = new AccessibilityInputConsumer(this, mISystemUiProxy, 582 (mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0, base, 583 mInputMonitorCompat, mSwipeTouchRegion); 584 } 585 } else { 586 if ((mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0) { 587 base = mResetGestureInputConsumer; 588 } 589 } 590 return base; 591 } 592 newBaseConsumer(boolean useSharedState, MotionEvent event)593 private InputConsumer newBaseConsumer(boolean useSharedState, MotionEvent event) { 594 final RunningTaskInfo runningTaskInfo = mAM.getRunningTask(0); 595 if (!useSharedState) { 596 sSwipeSharedState.clearAllState(false /* finishAnimation */); 597 } 598 if ((mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0) { 599 // This handles apps showing over the lockscreen (e.g. camera) 600 return createDeviceLockedInputConsumer(runningTaskInfo); 601 } 602 603 final ActivityControlHelper activityControl = 604 mOverviewComponentObserver.getActivityControlHelper(); 605 606 if (runningTaskInfo == null && !sSwipeSharedState.goingToLauncher 607 && !sSwipeSharedState.recentsAnimationFinishInterrupted) { 608 return mResetGestureInputConsumer; 609 } else if (sSwipeSharedState.recentsAnimationFinishInterrupted) { 610 // If the finish animation was interrupted, then continue using the other activity input 611 // consumer but with the next task as the running task 612 RunningTaskInfo info = new ActivityManager.RunningTaskInfo(); 613 info.id = sSwipeSharedState.nextRunningTaskId; 614 return createOtherActivityInputConsumer(event, info); 615 } else if (sSwipeSharedState.goingToLauncher || activityControl.isResumed()) { 616 return createOverviewInputConsumer(event); 617 } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityControl.isInLiveTileMode()) { 618 return createOverviewInputConsumer(event); 619 } else if (mGestureBlockingActivity != null && runningTaskInfo != null 620 && mGestureBlockingActivity.equals(runningTaskInfo.topActivity)) { 621 return mResetGestureInputConsumer; 622 } else if (mMode == Mode.NO_BUTTON && !mOverviewComponentObserver.isHomeAndOverviewSame()) { 623 return new FallbackNoButtonInputConsumer(this, activityControl, 624 mInputMonitorCompat, sSwipeSharedState, mSwipeTouchRegion, 625 mOverviewComponentObserver, disableHorizontalSwipe(event), runningTaskInfo); 626 } else { 627 return createOtherActivityInputConsumer(event, runningTaskInfo); 628 } 629 } 630 disableHorizontalSwipe(MotionEvent event)631 private boolean disableHorizontalSwipe(MotionEvent event) { 632 // mExclusionRegion can change on binder thread, use a local instance here. 633 Region exclusionRegion = mExclusionRegion; 634 return mMode == Mode.NO_BUTTON && exclusionRegion != null 635 && exclusionRegion.contains((int) event.getX(), (int) event.getY()); 636 } 637 createOtherActivityInputConsumer(MotionEvent event, RunningTaskInfo runningTaskInfo)638 private OtherActivityInputConsumer createOtherActivityInputConsumer(MotionEvent event, 639 RunningTaskInfo runningTaskInfo) { 640 final ActivityControlHelper activityControl = 641 mOverviewComponentObserver.getActivityControlHelper(); 642 boolean shouldDefer = activityControl.deferStartingActivity(mActiveNavBarRegion, event); 643 644 return new OtherActivityInputConsumer(this, runningTaskInfo, mRecentsModel, 645 mOverviewComponentObserver.getOverviewIntent(), activityControl, 646 shouldDefer, mOverviewCallbacks, mInputConsumer, this::onConsumerInactive, 647 sSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion, 648 disableHorizontalSwipe(event)); 649 } 650 createDeviceLockedInputConsumer(RunningTaskInfo taskInfo)651 private InputConsumer createDeviceLockedInputConsumer(RunningTaskInfo taskInfo) { 652 if (mMode == Mode.NO_BUTTON && taskInfo != null) { 653 return new DeviceLockedInputConsumer(this, sSwipeSharedState, mInputMonitorCompat, 654 mSwipeTouchRegion, taskInfo.taskId); 655 } else { 656 return mResetGestureInputConsumer; 657 } 658 } 659 createOverviewInputConsumer(MotionEvent event)660 public InputConsumer createOverviewInputConsumer(MotionEvent event) { 661 final ActivityControlHelper activityControl = 662 mOverviewComponentObserver.getActivityControlHelper(); 663 BaseDraggingActivity activity = activityControl.getCreatedActivity(); 664 if (activity == null) { 665 return mResetGestureInputConsumer; 666 } 667 668 if (activity.getRootView().hasWindowFocus() || sSwipeSharedState.goingToLauncher) { 669 return new OverviewInputConsumer(activity, mInputMonitorCompat, 670 false /* startingInActivityBounds */); 671 } else { 672 return new OverviewWithoutFocusInputConsumer(this, mInputMonitorCompat, 673 disableHorizontalSwipe(event)); 674 } 675 } 676 677 /** 678 * To be called by the consumer when it's no longer active. 679 */ onConsumerInactive(InputConsumer caller)680 private void onConsumerInactive(InputConsumer caller) { 681 if (mConsumer == caller) { 682 mConsumer = mResetGestureInputConsumer; 683 mUncheckedConsumer = mConsumer; 684 } 685 } 686 687 @Override dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs)688 protected void dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs) { 689 if (rawArgs.length > 0 && Utilities.IS_DEBUG_DEVICE) { 690 ArgList args = new ArgList(Arrays.asList(rawArgs)); 691 switch (args.nextArg()) { 692 case "cmd": 693 if (args.peekArg() == null) { 694 printAvailableCommands(pw); 695 } else { 696 onCommand(pw, args); 697 } 698 break; 699 } 700 } else { 701 // Dump everything 702 pw.println("TouchState:"); 703 pw.println(" navMode=" + mMode); 704 pw.println(" validSystemUiFlags=" + validSystemUiFlags()); 705 pw.println(" systemUiFlags=" + mSystemUiStateFlags); 706 pw.println(" systemUiFlagsDesc=" 707 + QuickStepContract.getSystemUiStateString(mSystemUiStateFlags)); 708 pw.println(" assistantAvailable=" + mAssistantAvailable); 709 pw.println(" assistantDisabled=" 710 + QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)); 711 pw.println(" resumed=" 712 + mOverviewComponentObserver.getActivityControlHelper().isResumed()); 713 pw.println(" useSharedState=" + mConsumer.useSharedSwipeState()); 714 if (mConsumer.useSharedSwipeState()) { 715 sSwipeSharedState.dump(" ", pw); 716 } 717 pw.println(" mConsumer=" + mConsumer.getName()); 718 pw.println("FeatureFlags:"); 719 pw.println(" APPLY_CONFIG_AT_RUNTIME=" + APPLY_CONFIG_AT_RUNTIME.get()); 720 pw.println(" QUICKSTEP_SPRINGS=" + QUICKSTEP_SPRINGS.get()); 721 pw.println(" ADAPTIVE_ICON_WINDOW_ANIM=" + ADAPTIVE_ICON_WINDOW_ANIM.get()); 722 pw.println(" ENABLE_QUICKSTEP_LIVE_TILE=" + ENABLE_QUICKSTEP_LIVE_TILE.get()); 723 pw.println(" ENABLE_HINTS_IN_OVERVIEW=" + ENABLE_HINTS_IN_OVERVIEW.get()); 724 pw.println(" FAKE_LANDSCAPE_UI=" + FAKE_LANDSCAPE_UI.get()); 725 TOUCH_INTERACTION_LOG.dump("", pw); 726 727 } 728 } 729 printAvailableCommands(PrintWriter pw)730 private void printAvailableCommands(PrintWriter pw) { 731 pw.println("Available commands:"); 732 pw.println(" clear-touch-log: Clears the touch interaction log"); 733 } 734 onCommand(PrintWriter pw, ArgList args)735 private void onCommand(PrintWriter pw, ArgList args) { 736 switch (args.nextArg()) { 737 case "clear-touch-log": 738 TOUCH_INTERACTION_LOG.clear(); 739 break; 740 } 741 } 742 } 743