• 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 
17 package com.android.systemui.shared.system;
18 
19 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON;
20 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
21 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
22 
23 import static com.android.systemui.shared.Flags.shadeAllowBackGesture;
24 
25 import android.annotation.LongDef;
26 import android.content.Context;
27 import android.content.res.Resources;
28 import android.os.Bundle;
29 import android.os.IBinder;
30 import android.os.IInterface;
31 import android.os.RemoteException;
32 import android.util.Log;
33 import android.view.ViewConfiguration;
34 import android.view.WindowManagerPolicyConstants;
35 
36 import androidx.annotation.NonNull;
37 import androidx.annotation.Nullable;
38 
39 import com.android.internal.policy.ScreenDecorationsUtils;
40 
41 import java.lang.annotation.Retention;
42 import java.lang.annotation.RetentionPolicy;
43 import java.util.StringJoiner;
44 
45 /**
46  * Various shared constants between Launcher and SysUI as part of quickstep
47  */
48 public class QuickStepContract {
49 
50     private static final String TAG = "QuickStepContract";
51 
52     public static final String NAV_BAR_MODE_3BUTTON_OVERLAY =
53             WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
54     public static final String NAV_BAR_MODE_GESTURAL_OVERLAY =
55             WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
56 
57     // Overview is disabled, either because the device is in lock task mode, or because the device
58     // policy has disabled the feature
59     public static final long SYSUI_STATE_SCREEN_PINNING = 1L << 0;
60     // The navigation bar is hidden due to immersive mode
61     public static final long SYSUI_STATE_NAV_BAR_HIDDEN = 1L << 1;
62     // The notification panel is expanded and interactive (either locked or unlocked), and the
63     // quick settings is not expanded
64     public static final long SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED = 1L << 2;
65     // The keyguard bouncer is showing
66     public static final long SYSUI_STATE_BOUNCER_SHOWING = 1L << 3;
67     // The navigation bar a11y button should be shown
68     public static final long SYSUI_STATE_A11Y_BUTTON_CLICKABLE = 1L << 4;
69     // The navigation bar a11y button shortcut is available
70     public static final long SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE = 1L << 5;
71     // The keyguard is showing and not occluded
72     public static final long SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING = 1L << 6;
73     // The recents feature is disabled (either by SUW/SysUI/device policy)
74     public static final long SYSUI_STATE_OVERVIEW_DISABLED = 1L << 7;
75     // The home feature is disabled (either by SUW/SysUI/device policy)
76     public static final long SYSUI_STATE_HOME_DISABLED = 1L << 8;
77     // The keyguard is showing, but occluded
78     public static final long SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED = 1L << 9;
79     // The search feature is disabled (either by SUW/SysUI/device policy)
80     public static final long SYSUI_STATE_SEARCH_DISABLED = 1L << 10;
81     // The notification panel is expanded and interactive (either locked or unlocked), and quick
82     // settings is expanded.
83     public static final long SYSUI_STATE_QUICK_SETTINGS_EXPANDED = 1L << 11;
84     // Winscope tracing is enabled
85     public static final long SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION = 1L << 12;
86     // The Assistant gesture should be constrained. It is up to the launcher implementation to
87     // decide how to constrain it
88     public static final long SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED = 1L << 13;
89     // The bubble stack is expanded. This means that the home gesture should be ignored, since a
90     // swipe up is an attempt to close the bubble stack, but that the back gesture should remain
91     // enabled (since it's used to navigate back within the bubbled app, or to collapse the bubble
92     // stack.
93     public static final long SYSUI_STATE_BUBBLES_EXPANDED = 1L << 14;
94     // A SysUI dialog is showing.
95     public static final long SYSUI_STATE_DIALOG_SHOWING = 1L << 15;
96     // The one-handed mode is active
97     public static final long SYSUI_STATE_ONE_HANDED_ACTIVE = 1L << 16;
98     // Allow system gesture no matter the system bar(s) is visible or not
99     public static final long SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY = 1L << 17;
100     // The IME is visible.
101     public static final long SYSUI_STATE_IME_VISIBLE = 1L << 18;
102     // The window magnification is overlapped with system gesture insets at the bottom.
103     public static final long SYSUI_STATE_MAGNIFICATION_OVERLAP = 1L << 19;
104     // The IME Switcher button is visible.
105     public static final long SYSUI_STATE_IME_SWITCHER_BUTTON_VISIBLE = 1L << 20;
106     // Device dozing/AOD state
107     public static final long SYSUI_STATE_DEVICE_DOZING = 1L << 21;
108     // The home feature is disabled (either by SUW/SysUI/device policy)
109     public static final long SYSUI_STATE_BACK_DISABLED = 1L << 22;
110     // The bubble stack is expanded AND the mange menu for bubbles is expanded on top of it.
111     public static final long SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED = 1L << 23;
112     // The voice interaction session window is showing
113     public static final long SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING = 1L << 25;
114     // Freeform windows are showing in desktop mode
115     public static final long SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE = 1L << 26;
116     // Device dreaming state
117     public static final long SYSUI_STATE_DEVICE_DREAMING = 1L << 27;
118     // Whether the device is currently awake (as opposed to asleep, see WakefulnessLifecycle).
119     // Note that the device is awake on while waking up on, but not while going to sleep.
120     public static final long SYSUI_STATE_AWAKE = 1L << 28;
121     // Whether the device is currently transitioning between awake/asleep indicated by
122     // SYSUI_STATE_AWAKE.
123     public static final long SYSUI_STATE_WAKEFULNESS_TRANSITION = 1L << 29;
124     // The notification panel expansion fraction is > 0
125     public static final long SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE = 1L << 30;
126     // When keyguard will be dismissed but didn't start animation yet
127     public static final long SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY = 1L << 31;
128     // Physical keyboard shortcuts helper is showing
129     public static final long SYSUI_STATE_SHORTCUT_HELPER_SHOWING = 1L << 32;
130     // Touchpad gestures are disabled
131     public static final long SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED = 1L << 33;
132     // PiP animation is running
133     public static final long SYSUI_STATE_DISABLE_GESTURE_PIP_ANIMATING = 1L << 34;
134     // Communal hub is showing
135     public static final long SYSUI_STATE_COMMUNAL_HUB_SHOWING = 1L << 35;
136     // The back button is visually adjusted to indicate that it will dismiss the IME when pressed.
137     // This only takes effect while the IME is visible. By default, it is set while the IME is
138     // visible, but may be overridden by the backDispositionMode set by the IME.
139     public static final long SYSUI_STATE_BACK_DISMISS_IME = 1L << 36;
140 
141     // Mask for SystemUiStateFlags to isolate SYSUI_STATE_AWAKE and
142     // SYSUI_STATE_WAKEFULNESS_TRANSITION, to match WAKEFULNESS_* constants
143     public static final long SYSUI_STATE_WAKEFULNESS_MASK =
144             SYSUI_STATE_AWAKE | SYSUI_STATE_WAKEFULNESS_TRANSITION;
145     // Mirroring the WakefulnessLifecycle#Wakefulness states
146     public static final long WAKEFULNESS_ASLEEP = 0;
147     public static final long WAKEFULNESS_AWAKE = SYSUI_STATE_AWAKE;
148     public static final long WAKEFULNESS_GOING_TO_SLEEP = SYSUI_STATE_WAKEFULNESS_TRANSITION;
149     public static final long WAKEFULNESS_WAKING =
150             SYSUI_STATE_WAKEFULNESS_TRANSITION | SYSUI_STATE_AWAKE;
151 
152     // Whether the back gesture is allowed (or ignored) by the Shade
153     public static final boolean ALLOW_BACK_GESTURE_IN_SHADE = shadeAllowBackGesture();
154 
155     @Retention(RetentionPolicy.SOURCE)
156     @LongDef({SYSUI_STATE_SCREEN_PINNING,
157             SYSUI_STATE_NAV_BAR_HIDDEN,
158             SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
159             SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
160             SYSUI_STATE_BOUNCER_SHOWING,
161             SYSUI_STATE_A11Y_BUTTON_CLICKABLE,
162             SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE,
163             SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
164             SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED,
165             SYSUI_STATE_OVERVIEW_DISABLED,
166             SYSUI_STATE_HOME_DISABLED,
167             SYSUI_STATE_SEARCH_DISABLED,
168             SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION,
169             SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED,
170             SYSUI_STATE_BUBBLES_EXPANDED,
171             SYSUI_STATE_DIALOG_SHOWING,
172             SYSUI_STATE_ONE_HANDED_ACTIVE,
173             SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY,
174             SYSUI_STATE_IME_VISIBLE,
175             SYSUI_STATE_MAGNIFICATION_OVERLAP,
176             SYSUI_STATE_IME_SWITCHER_BUTTON_VISIBLE,
177             SYSUI_STATE_DEVICE_DOZING,
178             SYSUI_STATE_BACK_DISABLED,
179             SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED,
180             SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING,
181             SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE,
182             SYSUI_STATE_DEVICE_DREAMING,
183             SYSUI_STATE_AWAKE,
184             SYSUI_STATE_WAKEFULNESS_TRANSITION,
185             SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE,
186             SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY,
187             SYSUI_STATE_SHORTCUT_HELPER_SHOWING,
188             SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED,
189             SYSUI_STATE_DISABLE_GESTURE_PIP_ANIMATING,
190             SYSUI_STATE_COMMUNAL_HUB_SHOWING,
191             SYSUI_STATE_BACK_DISMISS_IME,
192     })
193     public @interface SystemUiStateFlags {}
194 
getSystemUiStateString(long flags)195     public static String getSystemUiStateString(long flags) {
196         StringJoiner str = new StringJoiner("|");
197         if ((flags & SYSUI_STATE_SCREEN_PINNING) != 0) {
198             str.add("screen_pinned");
199         }
200         if ((flags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) {
201             str.add("overview_disabled");
202         }
203         if ((flags & SYSUI_STATE_HOME_DISABLED) != 0) {
204             str.add("home_disabled");
205         }
206         if ((flags & SYSUI_STATE_SEARCH_DISABLED) != 0) {
207             str.add("search_disabled");
208         }
209         if ((flags & SYSUI_STATE_NAV_BAR_HIDDEN) != 0) {
210             str.add("navbar_hidden");
211         }
212         if ((flags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) != 0) {
213             str.add("notif_expanded");
214         }
215         if ((flags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) != 0) {
216             str.add("qs_visible");
217         }
218         if ((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING) != 0) {
219             str.add("keygrd_visible");
220         }
221         if ((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0) {
222             str.add("keygrd_occluded");
223         }
224         if ((flags & SYSUI_STATE_BOUNCER_SHOWING) != 0) {
225             str.add("bouncer_visible");
226         }
227         if ((flags & SYSUI_STATE_DIALOG_SHOWING) != 0) {
228             str.add("dialog_showing");
229         }
230         if ((flags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0) {
231             str.add("a11y_click");
232         }
233         if ((flags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0) {
234             str.add("a11y_long_click");
235         }
236         if ((flags & SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION) != 0) {
237             str.add("disable_gesture_split_invocation");
238         }
239         if ((flags & SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED) != 0) {
240             str.add("asst_gesture_constrain");
241         }
242         if ((flags & SYSUI_STATE_BUBBLES_EXPANDED) != 0) {
243             str.add("bubbles_expanded");
244         }
245         if ((flags & SYSUI_STATE_ONE_HANDED_ACTIVE) != 0) {
246             str.add("one_handed_active");
247         }
248         if ((flags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0) {
249             str.add("allow_gesture");
250         }
251         if ((flags & SYSUI_STATE_IME_VISIBLE) != 0) {
252             str.add("ime_visible");
253         }
254         if ((flags & SYSUI_STATE_MAGNIFICATION_OVERLAP) != 0) {
255             str.add("magnification_overlap");
256         }
257         if ((flags & SYSUI_STATE_IME_SWITCHER_BUTTON_VISIBLE) != 0) {
258             str.add("ime_switcher_button_visible");
259         }
260         if ((flags & SYSUI_STATE_DEVICE_DOZING) != 0) {
261             str.add("device_dozing");
262         }
263         if ((flags & SYSUI_STATE_BACK_DISABLED) != 0) {
264             str.add("back_disabled");
265         }
266         if ((flags & SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0) {
267             str.add("bubbles_mange_menu_expanded");
268         }
269         if ((flags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0) {
270             str.add("vis_win_showing");
271         }
272         if ((flags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0) {
273             str.add("freeform_active_in_desktop_mode");
274         }
275         if ((flags & SYSUI_STATE_DEVICE_DREAMING) != 0) {
276             str.add("device_dreaming");
277         }
278         if ((flags & SYSUI_STATE_WAKEFULNESS_TRANSITION) != 0) {
279             str.add("wakefulness_transition");
280         }
281         if ((flags & SYSUI_STATE_AWAKE) != 0) {
282             str.add("awake");
283         }
284         if ((flags & SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE) != 0) {
285             str.add("notif_visible");
286         }
287         if ((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY) != 0) {
288             str.add("keygrd_going_away");
289         }
290         if ((flags & SYSUI_STATE_SHORTCUT_HELPER_SHOWING) != 0) {
291             str.add("shortcut_helper_showing");
292         }
293         if ((flags & SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED) != 0) {
294             str.add("touchpad_gestures_disabled");
295         }
296         if ((flags & SYSUI_STATE_DISABLE_GESTURE_PIP_ANIMATING) != 0) {
297             str.add("disable_gesture_pip_animating");
298         }
299         if ((flags & SYSUI_STATE_COMMUNAL_HUB_SHOWING) != 0) {
300             str.add("communal_hub_showing");
301         }
302         if ((flags & SYSUI_STATE_BACK_DISMISS_IME) != 0) {
303             str.add("back_dismiss_ime");
304         }
305 
306         return str.toString();
307     }
308 
309     /**
310      * Ratio of quickstep touch slop (when system takes over the touch) to view touch slop
311      */
312     public static final float QUICKSTEP_TOUCH_SLOP_RATIO = 3;
313 
314     /**
315      * Touch slop for quickstep gesture
316      */
getQuickStepTouchSlopPx(Context context)317     public static final float getQuickStepTouchSlopPx(Context context) {
318         return QUICKSTEP_TOUCH_SLOP_RATIO * ViewConfiguration.get(context).getScaledTouchSlop();
319     }
320 
321     /**
322      * Returns whether the specified sysui state is such that the assistant gesture should be
323      * disabled.
324      */
isAssistantGestureDisabled(long sysuiStateFlags)325     public static boolean isAssistantGestureDisabled(long sysuiStateFlags) {
326         if ((sysuiStateFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0) {
327             sysuiStateFlags &= ~SYSUI_STATE_NAV_BAR_HIDDEN;
328         }
329         // Disable when in quick settings, screen pinning, immersive, the bouncer is showing,
330         // or search is disabled
331         long disableFlags = SYSUI_STATE_SCREEN_PINNING
332                 | SYSUI_STATE_NAV_BAR_HIDDEN
333                 | SYSUI_STATE_BOUNCER_SHOWING
334                 | SYSUI_STATE_SEARCH_DISABLED
335                 | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
336         if ((sysuiStateFlags & disableFlags) != 0) {
337             return true;
338         }
339 
340         // Disable when notifications are showing (only if unlocked)
341         if ((sysuiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) != 0
342                 && (sysuiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING) == 0) {
343             return true;
344         }
345 
346         return false;
347     }
348 
349     /**
350      * Returns whether the specified sysui state is such that the back gesture should be
351      * disabled.
352      */
isBackGestureDisabled(long sysuiStateFlags, boolean forTrackpad)353     public static boolean isBackGestureDisabled(long sysuiStateFlags, boolean forTrackpad) {
354         // Always allow when the bouncer/global actions/voice session is showing (even on top of
355         // the keyguard)
356         if ((sysuiStateFlags & SYSUI_STATE_BOUNCER_SHOWING) != 0
357                 || (sysuiStateFlags & SYSUI_STATE_DIALOG_SHOWING) != 0
358                 || (sysuiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0) {
359             return false;
360         }
361         // Disable back gesture on the hub, but not when the shade is showing.
362         if ((sysuiStateFlags & SYSUI_STATE_COMMUNAL_HUB_SHOWING) != 0) {
363             // Use QS expanded signal as the notification panel is always considered visible
364             // expanded when on the lock screen and when opening hub over lock screen. This does
365             // mean that back gesture is disabled when opening shade over hub while in portrait
366             // mode, since QS is not expanded.
367             // TODO(b/370108274): allow back gesture on shade over hub in portrait
368             return (sysuiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0;
369         }
370         if ((sysuiStateFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0) {
371             sysuiStateFlags &= ~SYSUI_STATE_NAV_BAR_HIDDEN;
372         }
373 
374         return (sysuiStateFlags & getBackGestureDisabledMask(forTrackpad)) != 0;
375     }
376 
getBackGestureDisabledMask(boolean forTrackpad)377     private static long getBackGestureDisabledMask(boolean forTrackpad) {
378         // Disable when in immersive, or the notifications are interactive
379         long disableFlags = SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
380         if (!forTrackpad) {
381             disableFlags |= SYSUI_STATE_NAV_BAR_HIDDEN;
382         }
383 
384         // EdgeBackGestureHandler ignores Back gesture when SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED.
385         // To allow Shade to respond to Back, we're bypassing this check (behind a flag).
386         if (!ALLOW_BACK_GESTURE_IN_SHADE) {
387             disableFlags |= SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
388         }
389         return disableFlags;
390     }
391 
392     /**
393      * @return whether this nav bar mode is edge to edge
394      */
isGesturalMode(int mode)395     public static boolean isGesturalMode(int mode) {
396         return mode == NAV_BAR_MODE_GESTURAL;
397     }
398 
399     /**
400      * @return whether this nav bar mode is swipe up
401      */
isSwipeUpMode(int mode)402     public static boolean isSwipeUpMode(int mode) {
403         return mode == NAV_BAR_MODE_2BUTTON;
404     }
405 
406     /**
407      * @return whether this nav bar mode is 3 button
408      */
isLegacyMode(int mode)409     public static boolean isLegacyMode(int mode) {
410         return mode == NAV_BAR_MODE_3BUTTON;
411     }
412 
413     /**
414      * Corner radius that should be used on windows in order to cover the display.
415      * These values are expressed in pixels because they should not respect display or font
416      * scaling. The corner radius may change when folding/unfolding the device.
417      */
getWindowCornerRadius(Context context)418     public static float getWindowCornerRadius(Context context) {
419         return ScreenDecorationsUtils.getWindowCornerRadius(context);
420     }
421 
422     /**
423      * If live rounded corners are supported on windows.
424      */
supportsRoundedCornersOnWindows(Resources resources)425     public static boolean supportsRoundedCornersOnWindows(Resources resources) {
426         return ScreenDecorationsUtils.supportsRoundedCornersOnWindows(resources);
427     }
428 
429     /**
430      * Adds the provided interface to the bundle using the interface descriptor as the key
431      */
addInterface(@ullable IInterface iInterface, @NonNull Bundle out)432     public static void addInterface(@Nullable IInterface iInterface, @NonNull Bundle out) {
433         if (iInterface != null) {
434             IBinder binder = iInterface.asBinder();
435             if (binder != null) {
436                 try {
437                     out.putIBinder(binder.getInterfaceDescriptor(), binder);
438                 } catch (RemoteException e) {
439                     Log.d(TAG, "Invalid interface description " + binder, e);
440                 }
441             }
442         }
443     }
444 }
445