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