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