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