1 /* 2 * Copyright (C) 2019 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.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 19 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 20 import static android.view.Display.DEFAULT_DISPLAY; 21 22 import static com.android.launcher3.util.DisplayController.CHANGE_ALL; 23 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE; 24 import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION; 25 import static com.android.launcher3.util.NavigationMode.NO_BUTTON; 26 import static com.android.launcher3.util.NavigationMode.THREE_BUTTONS; 27 import static com.android.launcher3.util.SettingsCache.ONE_HANDED_ENABLED; 28 import static com.android.launcher3.util.SettingsCache.ONE_HANDED_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED; 29 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE; 30 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE; 31 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY; 32 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED; 33 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED; 34 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING; 35 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING; 36 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION; 37 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED; 38 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING; 39 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_MAGNIFICATION_OVERLAP; 40 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN; 41 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; 42 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE; 43 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; 44 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; 45 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; 46 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING; 47 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED; 48 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED; 49 50 import android.app.ActivityTaskManager; 51 import android.content.Context; 52 import android.graphics.Region; 53 import android.inputmethodservice.InputMethodService; 54 import android.net.Uri; 55 import android.os.RemoteException; 56 import android.os.SystemProperties; 57 import android.provider.Settings; 58 import android.view.MotionEvent; 59 import android.view.ViewConfiguration; 60 61 import androidx.annotation.NonNull; 62 import androidx.annotation.Nullable; 63 import androidx.annotation.VisibleForTesting; 64 65 import com.android.launcher3.util.DisplayController; 66 import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener; 67 import com.android.launcher3.util.DisplayController.Info; 68 import com.android.launcher3.util.NavigationMode; 69 import com.android.launcher3.util.SettingsCache; 70 import com.android.quickstep.TopTaskTracker.CachedTaskInfo; 71 import com.android.quickstep.util.ActiveGestureLog; 72 import com.android.quickstep.util.AssistStateManager; 73 import com.android.quickstep.util.GestureExclusionManager; 74 import com.android.quickstep.util.GestureExclusionManager.ExclusionListener; 75 import com.android.quickstep.util.NavBarPosition; 76 import com.android.systemui.shared.system.ActivityManagerWrapper; 77 import com.android.systemui.shared.system.QuickStepContract; 78 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; 79 import com.android.systemui.shared.system.TaskStackChangeListener; 80 import com.android.systemui.shared.system.TaskStackChangeListeners; 81 82 import java.io.PrintWriter; 83 import java.util.ArrayList; 84 85 /** 86 * Manages the state of the system during a swipe up gesture. 87 */ 88 public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, ExclusionListener { 89 90 private static final String TAG = "RecentsAnimationDeviceState"; 91 92 static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode"; 93 94 // TODO: Move to quickstep contract 95 private static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 3f; 96 private static final float QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL = 1.414f; 97 98 private final Context mContext; 99 private final DisplayController mDisplayController; 100 101 private final GestureExclusionManager mExclusionManager; 102 private final AssistStateManager mAssistStateManager; 103 104 private final RotationTouchHelper mRotationTouchHelper; 105 private final TaskStackChangeListener mPipListener; 106 // Cache for better performance since it doesn't change at runtime. 107 private final boolean mCanImeRenderGesturalNavButtons = 108 InputMethodService.canImeRenderGesturalNavButtons(); 109 110 private final ArrayList<Runnable> mOnDestroyActions = new ArrayList<>(); 111 112 private @SystemUiStateFlags long mSystemUiStateFlags = QuickStepContract.SYSUI_STATE_AWAKE; 113 private NavigationMode mMode = THREE_BUTTONS; 114 private NavBarPosition mNavBarPosition; 115 116 private final Region mDeferredGestureRegion = new Region(); 117 private boolean mAssistantAvailable; 118 private float mAssistantVisibility; 119 private boolean mIsUserSetupComplete; 120 private boolean mIsOneHandedModeEnabled; 121 private boolean mIsSwipeToNotificationEnabled; 122 private final boolean mIsOneHandedModeSupported; 123 private boolean mPipIsActive; 124 private boolean mIsPredictiveBackToHomeInProgress; 125 126 private int mGestureBlockingTaskId = -1; 127 private @NonNull Region mExclusionRegion = GestureExclusionManager.EMPTY_REGION; 128 private boolean mExclusionListenerRegistered; 129 RecentsAnimationDeviceState(Context context)130 public RecentsAnimationDeviceState(Context context) { 131 this(context, false, GestureExclusionManager.INSTANCE); 132 } 133 RecentsAnimationDeviceState(Context context, boolean isInstanceForTouches)134 public RecentsAnimationDeviceState(Context context, boolean isInstanceForTouches) { 135 this(context, isInstanceForTouches, GestureExclusionManager.INSTANCE); 136 } 137 138 @VisibleForTesting RecentsAnimationDeviceState(Context context, GestureExclusionManager exclusionManager)139 RecentsAnimationDeviceState(Context context, GestureExclusionManager exclusionManager) { 140 this(context, false, exclusionManager); 141 } 142 143 /** 144 * @param isInstanceForTouches {@code true} if this is the persistent instance being used for 145 * gesture touch handling 146 */ RecentsAnimationDeviceState( Context context, boolean isInstanceForTouches, GestureExclusionManager exclusionManager)147 RecentsAnimationDeviceState( 148 Context context, boolean isInstanceForTouches, 149 GestureExclusionManager exclusionManager) { 150 mContext = context; 151 mDisplayController = DisplayController.INSTANCE.get(context); 152 mExclusionManager = exclusionManager; 153 mAssistStateManager = AssistStateManager.INSTANCE.get(context); 154 mIsOneHandedModeSupported = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false); 155 mRotationTouchHelper = RotationTouchHelper.INSTANCE.get(context); 156 if (isInstanceForTouches) { 157 // rotationTouchHelper doesn't get initialized after being destroyed, so only destroy 158 // if primary TouchInteractionService instance needs to be destroyed. 159 mRotationTouchHelper.init(); 160 runOnDestroy(mRotationTouchHelper::destroy); 161 } 162 163 // Register for exclusion updates 164 runOnDestroy(() -> unregisterExclusionListener()); 165 166 // Register for display changes changes 167 mDisplayController.addChangeListener(this); 168 onDisplayInfoChanged(context, mDisplayController.getInfo(), CHANGE_ALL); 169 runOnDestroy(() -> mDisplayController.removeChangeListener(this)); 170 171 SettingsCache settingsCache = SettingsCache.INSTANCE.get(mContext); 172 if (mIsOneHandedModeSupported) { 173 Uri oneHandedUri = Settings.Secure.getUriFor(ONE_HANDED_ENABLED); 174 SettingsCache.OnChangeListener onChangeListener = 175 enabled -> mIsOneHandedModeEnabled = enabled; 176 settingsCache.register(oneHandedUri, onChangeListener); 177 mIsOneHandedModeEnabled = settingsCache.getValue(oneHandedUri); 178 runOnDestroy(() -> settingsCache.unregister(oneHandedUri, onChangeListener)); 179 } else { 180 mIsOneHandedModeEnabled = false; 181 } 182 183 Uri swipeBottomNotificationUri = 184 Settings.Secure.getUriFor(ONE_HANDED_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED); 185 SettingsCache.OnChangeListener onChangeListener = 186 enabled -> mIsSwipeToNotificationEnabled = enabled; 187 settingsCache.register(swipeBottomNotificationUri, onChangeListener); 188 mIsSwipeToNotificationEnabled = settingsCache.getValue(swipeBottomNotificationUri); 189 runOnDestroy(() -> settingsCache.unregister(swipeBottomNotificationUri, onChangeListener)); 190 191 Uri setupCompleteUri = Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE); 192 mIsUserSetupComplete = settingsCache.getValue(setupCompleteUri, 0); 193 if (!mIsUserSetupComplete) { 194 SettingsCache.OnChangeListener userSetupChangeListener = e -> mIsUserSetupComplete = e; 195 settingsCache.register(setupCompleteUri, userSetupChangeListener); 196 runOnDestroy(() -> settingsCache.unregister(setupCompleteUri, userSetupChangeListener)); 197 } 198 199 try { 200 mPipIsActive = ActivityTaskManager.getService().getRootTaskInfo( 201 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED) != null; 202 } catch (RemoteException e) { 203 // Do nothing 204 } 205 mPipListener = new TaskStackChangeListener() { 206 @Override 207 public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { 208 mPipIsActive = true; 209 } 210 211 @Override 212 public void onActivityUnpinned() { 213 mPipIsActive = false; 214 } 215 }; 216 TaskStackChangeListeners.getInstance().registerTaskStackListener(mPipListener); 217 runOnDestroy(() -> 218 TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mPipListener)); 219 } 220 runOnDestroy(Runnable action)221 private void runOnDestroy(Runnable action) { 222 mOnDestroyActions.add(action); 223 } 224 225 /** 226 * Cleans up all the registered listeners and receivers. 227 */ destroy()228 public void destroy() { 229 for (Runnable r : mOnDestroyActions) { 230 r.run(); 231 } 232 } 233 234 /** 235 * Adds a listener for the nav mode change, guaranteed to be called after the device state's 236 * mode has changed. 237 */ addNavigationModeChangedCallback(Runnable callback)238 public void addNavigationModeChangedCallback(Runnable callback) { 239 DisplayController.DisplayInfoChangeListener listener = (context, info, flags) -> { 240 if ((flags & CHANGE_NAVIGATION_MODE) != 0) { 241 callback.run(); 242 } 243 }; 244 mDisplayController.addChangeListener(listener); 245 callback.run(); 246 runOnDestroy(() -> mDisplayController.removeChangeListener(listener)); 247 } 248 249 @Override onDisplayInfoChanged(Context context, Info info, int flags)250 public void onDisplayInfoChanged(Context context, Info info, int flags) { 251 if ((flags & (CHANGE_ROTATION | CHANGE_NAVIGATION_MODE)) != 0) { 252 mMode = info.getNavigationMode(); 253 ActiveGestureLog.INSTANCE.setIsFullyGesturalNavMode(isFullyGesturalNavMode()); 254 mNavBarPosition = new NavBarPosition(mMode, info); 255 256 if (mMode == NO_BUTTON) { 257 registerExclusionListener(); 258 } else { 259 unregisterExclusionListener(); 260 } 261 } 262 } 263 264 @Override onGestureExclusionChanged(@ullable Region exclusionRegion, @Nullable Region unrestrictedOrNull)265 public void onGestureExclusionChanged(@Nullable Region exclusionRegion, 266 @Nullable Region unrestrictedOrNull) { 267 mExclusionRegion = exclusionRegion != null 268 ? exclusionRegion : GestureExclusionManager.EMPTY_REGION; 269 } 270 271 /** 272 * Registers itself for getting exclusion rect changes. 273 */ registerExclusionListener()274 public void registerExclusionListener() { 275 if (mExclusionListenerRegistered) { 276 return; 277 } 278 mExclusionManager.addListener(this); 279 mExclusionListenerRegistered = true; 280 } 281 282 /** 283 * Unregisters itself as gesture exclusion listener if previously registered. 284 */ unregisterExclusionListener()285 public void unregisterExclusionListener() { 286 if (!mExclusionListenerRegistered) { 287 return; 288 } 289 mExclusionManager.removeListener(this); 290 mExclusionListenerRegistered = false; 291 } 292 onOneHandedModeChanged(int newGesturalHeight)293 public void onOneHandedModeChanged(int newGesturalHeight) { 294 mRotationTouchHelper.setGesturalHeight(newGesturalHeight); 295 } 296 297 /** 298 * @return the nav bar position for the current nav bar mode and display rotation. 299 */ getNavBarPosition()300 public NavBarPosition getNavBarPosition() { 301 return mNavBarPosition; 302 } 303 304 /** 305 * @return whether the current nav mode is fully gestural. 306 */ isFullyGesturalNavMode()307 public boolean isFullyGesturalNavMode() { 308 return mMode == NO_BUTTON; 309 } 310 311 /** 312 * @return whether the current nav mode has some gestures (either 2 or 0 button mode). 313 */ isGesturalNavMode()314 public boolean isGesturalNavMode() { 315 return mMode.hasGestures; 316 } 317 318 /** 319 * @return whether the current nav mode is button-based. 320 */ isButtonNavMode()321 public boolean isButtonNavMode() { 322 return mMode == THREE_BUTTONS; 323 } 324 325 /** 326 * @return the display id for the display that Launcher is running on. 327 */ getDisplayId()328 public int getDisplayId() { 329 return DEFAULT_DISPLAY; 330 } 331 332 /** 333 * @return whether the user has completed setup wizard 334 */ isUserSetupComplete()335 public boolean isUserSetupComplete() { 336 return mIsUserSetupComplete; 337 } 338 339 /** 340 * Sets the task id where gestures should be blocked 341 */ setGestureBlockingTaskId(int taskId)342 public void setGestureBlockingTaskId(int taskId) { 343 mGestureBlockingTaskId = taskId; 344 } 345 346 /** 347 * @return whether the given running task info matches the gesture-blocked task. 348 */ isGestureBlockedTask(CachedTaskInfo taskInfo)349 public boolean isGestureBlockedTask(CachedTaskInfo taskInfo) { 350 return taskInfo != null && taskInfo.getTaskId() == mGestureBlockingTaskId; 351 } 352 353 /** 354 * Updates the system ui state flags from SystemUI. 355 */ setSystemUiFlags(@ystemUiStateFlags long stateFlags)356 public void setSystemUiFlags(@SystemUiStateFlags long stateFlags) { 357 mSystemUiStateFlags = stateFlags; 358 } 359 360 /** 361 * @return the system ui state flags. 362 */ 363 // TODO(141886704): See if we can remove this 364 @SystemUiStateFlags getSystemUiStateFlags()365 public long getSystemUiStateFlags() { 366 return mSystemUiStateFlags; 367 } 368 369 /** 370 * Sets the flag that indicates whether a predictive back-to-home animation is in progress 371 */ setPredictiveBackToHomeInProgress(boolean isInProgress)372 public void setPredictiveBackToHomeInProgress(boolean isInProgress) { 373 mIsPredictiveBackToHomeInProgress = isInProgress; 374 } 375 376 /** 377 * @return whether a predictive back-to-home animation is currently in progress 378 */ isPredictiveBackToHomeInProgress()379 public boolean isPredictiveBackToHomeInProgress() { 380 return mIsPredictiveBackToHomeInProgress; 381 } 382 383 /** 384 * @return whether SystemUI is in a state where we can start a system gesture. 385 */ canStartSystemGesture()386 public boolean canStartSystemGesture() { 387 boolean canStartWithNavHidden = (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0 388 || (mSystemUiStateFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0 389 || mRotationTouchHelper.isTaskListFrozen(); 390 return canStartWithNavHidden && canStartAnyGesture(); 391 } 392 393 /** 394 * @return whether SystemUI is in a state where we can start a system gesture from the trackpad. 395 * Trackpad gestures can start even when the nav bar / task bar is hidden in sticky immersive 396 * mode. 397 */ canStartTrackpadGesture()398 public boolean canStartTrackpadGesture() { 399 boolean trackpadGesturesEnabled = 400 (mSystemUiStateFlags & SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED) == 0; 401 return trackpadGesturesEnabled && canStartAnyGesture(); 402 } 403 404 /** 405 * Common logic to determine if either trackpad or finger gesture can be started 406 */ canStartAnyGesture()407 private boolean canStartAnyGesture() { 408 boolean homeOrOverviewEnabled = (mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0 409 || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0; 410 long gestureDisablingStates = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED 411 | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING 412 | SYSUI_STATE_QUICK_SETTINGS_EXPANDED 413 | SYSUI_STATE_MAGNIFICATION_OVERLAP 414 | SYSUI_STATE_DEVICE_DREAMING 415 | SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION; 416 return (gestureDisablingStates & mSystemUiStateFlags) == 0 && homeOrOverviewEnabled; 417 } 418 419 /** 420 * @return whether the keyguard is showing and is occluded by an app showing above the keyguard 421 * (like camera or maps) 422 */ isKeyguardShowingOccluded()423 public boolean isKeyguardShowingOccluded() { 424 return (mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0; 425 } 426 427 /** 428 * @return whether screen pinning is enabled and active 429 */ isScreenPinningActive()430 public boolean isScreenPinningActive() { 431 return (mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0; 432 } 433 434 /** 435 * @return whether assistant gesture is constraint 436 */ isAssistantGestureIsConstrained()437 public boolean isAssistantGestureIsConstrained() { 438 return (mSystemUiStateFlags & SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED) != 0; 439 } 440 441 /** 442 * @return whether the bubble stack is expanded 443 */ isBubblesExpanded()444 public boolean isBubblesExpanded() { 445 return (mSystemUiStateFlags & SYSUI_STATE_BUBBLES_EXPANDED) != 0; 446 } 447 448 /** 449 * @return whether the global actions dialog is showing 450 */ isSystemUiDialogShowing()451 public boolean isSystemUiDialogShowing() { 452 return (mSystemUiStateFlags & SYSUI_STATE_DIALOG_SHOWING) != 0; 453 } 454 455 /** 456 * @return whether lock-task mode is active 457 */ isLockToAppActive()458 public boolean isLockToAppActive() { 459 return ActivityManagerWrapper.getInstance().isLockToAppActive(); 460 } 461 462 /** 463 * @return whether the accessibility menu is available. 464 */ isAccessibilityMenuAvailable()465 public boolean isAccessibilityMenuAvailable() { 466 return (mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0; 467 } 468 469 /** 470 * @return whether the accessibility menu shortcut is available. 471 */ isAccessibilityMenuShortcutAvailable()472 public boolean isAccessibilityMenuShortcutAvailable() { 473 return (mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0; 474 } 475 476 /** 477 * @return whether home is disabled (either by SUW/SysUI/device policy) 478 */ isHomeDisabled()479 public boolean isHomeDisabled() { 480 return (mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) != 0; 481 } 482 483 /** 484 * @return whether overview is disabled (either by SUW/SysUI/device policy) 485 */ isOverviewDisabled()486 public boolean isOverviewDisabled() { 487 return (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0; 488 } 489 490 /** 491 * @return whether one-handed mode is enabled and active 492 */ isOneHandedModeActive()493 public boolean isOneHandedModeActive() { 494 return (mSystemUiStateFlags & SYSUI_STATE_ONE_HANDED_ACTIVE) != 0; 495 } 496 497 /** 498 * Sets the region in screen space where the gestures should be deferred (ie. due to specific 499 * nav bar ui). 500 */ setDeferredGestureRegion(Region deferredGestureRegion)501 public void setDeferredGestureRegion(Region deferredGestureRegion) { 502 mDeferredGestureRegion.set(deferredGestureRegion); 503 } 504 505 /** 506 * @return whether the given {@param event} is in the deferred gesture region indicating that 507 * the Launcher should not immediately start the recents animation until the gesture 508 * passes a certain threshold. 509 */ isInDeferredGestureRegion(MotionEvent event)510 public boolean isInDeferredGestureRegion(MotionEvent event) { 511 return mDeferredGestureRegion.contains((int) event.getX(), (int) event.getY()); 512 } 513 514 /** 515 * @return whether the given {@param event} is in the app-requested gesture-exclusion region. 516 * This is only used for quickswitch, and not swipe up. 517 */ isInExclusionRegion(MotionEvent event)518 public boolean isInExclusionRegion(MotionEvent event) { 519 return mMode == NO_BUTTON 520 && mExclusionRegion.contains((int) event.getX(), (int) event.getY()); 521 } 522 523 /** 524 * Sets whether the assistant is available. 525 */ setAssistantAvailable(boolean assistantAvailable)526 public void setAssistantAvailable(boolean assistantAvailable) { 527 mAssistantAvailable = assistantAvailable; 528 } 529 530 /** 531 * Sets the visibility fraction of the assistant. 532 */ setAssistantVisibility(float visibility)533 public void setAssistantVisibility(float visibility) { 534 mAssistantVisibility = visibility; 535 } 536 537 /** 538 * @return the visibility fraction of the assistant. 539 */ getAssistantVisibility()540 public float getAssistantVisibility() { 541 return mAssistantVisibility; 542 } 543 544 /** 545 * @param ev An ACTION_DOWN motion event 546 * @return whether the given motion event can trigger the assistant over the current task. 547 */ canTriggerAssistantAction(MotionEvent ev)548 public boolean canTriggerAssistantAction(MotionEvent ev) { 549 return mAssistantAvailable 550 && !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags) 551 && mRotationTouchHelper.touchInAssistantRegion(ev) 552 && !isLockToAppActive(); 553 } 554 555 /** 556 * One handed gestural in quickstep only active on NO_BUTTON, TWO_BUTTONS, and portrait mode 557 * 558 * @param ev The touch screen motion event. 559 * @return whether the given motion event can trigger the one handed mode. 560 */ canTriggerOneHandedAction(MotionEvent ev)561 public boolean canTriggerOneHandedAction(MotionEvent ev) { 562 if (!mIsOneHandedModeSupported) { 563 return false; 564 } 565 566 if (mIsOneHandedModeEnabled) { 567 final Info displayInfo = mDisplayController.getInfo(); 568 return (mRotationTouchHelper.touchInOneHandedModeRegion(ev) 569 && (displayInfo.currentSize.x < displayInfo.currentSize.y)); 570 } 571 return false; 572 } 573 isOneHandedModeEnabled()574 public boolean isOneHandedModeEnabled() { 575 return mIsOneHandedModeEnabled; 576 } 577 isSwipeToNotificationEnabled()578 public boolean isSwipeToNotificationEnabled() { 579 return mIsSwipeToNotificationEnabled; 580 } 581 isPipActive()582 public boolean isPipActive() { 583 return mPipIsActive; 584 } 585 getRotationTouchHelper()586 public RotationTouchHelper getRotationTouchHelper() { 587 return mRotationTouchHelper; 588 } 589 590 /** Returns whether IME is rendering nav buttons, and IME is currently showing. */ isImeRenderingNavButtons()591 public boolean isImeRenderingNavButtons() { 592 return mCanImeRenderGesturalNavButtons && mMode == NO_BUTTON 593 && ((mSystemUiStateFlags & SYSUI_STATE_IME_SHOWING) != 0); 594 } 595 596 /** 597 * Returns the touch slop for {@link InputConsumer}s to compare against before pilfering 598 * pointers. 599 */ getTouchSlop()600 public float getTouchSlop() { 601 float slopMultiplier = isFullyGesturalNavMode() 602 ? QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL 603 : QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON; 604 float touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); 605 606 if (mAssistStateManager.getLPNHCustomSlopMultiplier().isPresent()) { 607 float customSlopMultiplier = mAssistStateManager.getLPNHCustomSlopMultiplier().get(); 608 return customSlopMultiplier * slopMultiplier * touchSlop; 609 } else { 610 return slopMultiplier * touchSlop; 611 } 612 } 613 614 /** 615 * Returns the squared touch slop for {@link InputConsumer}s to compare against before pilfering 616 * pointers. Note that this is squared because it expects to be compared against 617 * {@link com.android.launcher3.Utilities#squaredHypot} (to avoid square root on each event). 618 */ getSquaredTouchSlop()619 public float getSquaredTouchSlop() { 620 float touchSlop = getTouchSlop(); 621 return touchSlop * touchSlop; 622 } 623 getSystemUiStateString()624 public String getSystemUiStateString() { 625 return QuickStepContract.getSystemUiStateString(mSystemUiStateFlags); 626 } 627 dump(PrintWriter pw)628 public void dump(PrintWriter pw) { 629 pw.println("DeviceState:"); 630 pw.println(" canStartSystemGesture=" + canStartSystemGesture()); 631 pw.println(" systemUiFlags=" + mSystemUiStateFlags); 632 pw.println(" systemUiFlagsDesc=" + getSystemUiStateString()); 633 pw.println(" assistantAvailable=" + mAssistantAvailable); 634 pw.println(" assistantDisabled=" 635 + QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)); 636 pw.println(" isOneHandedModeEnabled=" + mIsOneHandedModeEnabled); 637 pw.println(" isSwipeToNotificationEnabled=" + mIsSwipeToNotificationEnabled); 638 pw.println(" deferredGestureRegion=" + mDeferredGestureRegion.getBounds()); 639 pw.println(" exclusionRegion=" + mExclusionRegion.getBounds()); 640 pw.println(" pipIsActive=" + mPipIsActive); 641 pw.println(" predictiveBackToHomeInProgress=" + mIsPredictiveBackToHomeInProgress); 642 mRotationTouchHelper.dump(pw); 643 } 644 } 645