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