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