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