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