1 /* 2 * Copyright (C) 2017 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.statusbar.phone; 18 19 import static com.android.systemui.statusbar.phone.ScrimController.BUSY_SCRIM_ALPHA; 20 21 import android.graphics.Color; 22 23 import com.android.app.tracing.coroutines.TrackTracer; 24 import com.android.systemui.Flags; 25 import com.android.systemui.dock.DockManager; 26 import com.android.systemui.res.R; 27 import com.android.systemui.scrim.ScrimView; 28 import com.android.systemui.shade.ui.ShadeColors; 29 import com.android.systemui.statusbar.notification.stack.StackStateAnimator; 30 31 import java.util.function.Supplier; 32 33 import kotlinx.coroutines.ExperimentalCoroutinesApi; 34 35 /** 36 * Possible states of the ScrimController state machine. 37 */ 38 @ExperimentalCoroutinesApi 39 public enum ScrimState { 40 41 /** 42 * Initial state. 43 */ 44 UNINITIALIZED, 45 46 /** 47 * When turned off by sensors (prox, presence.) 48 */ 49 OFF { 50 @Override prepare(ScrimState previousState)51 public void prepare(ScrimState previousState) { 52 mFrontTint = mBackgroundColor; 53 mBehindTint = mBackgroundColor; 54 55 mFrontAlpha = 1f; 56 mBehindAlpha = 1f; 57 58 if (previousState == AOD) { 59 mAnimateChange = false; 60 } else { 61 mAnimationDuration = ScrimController.ANIMATION_DURATION_LONG; 62 } 63 } 64 65 @Override isLowPowerState()66 public boolean isLowPowerState() { 67 return true; 68 } 69 }, 70 71 /** 72 * On the lock screen. 73 */ 74 KEYGUARD { 75 @Override prepare(ScrimState previousState)76 public void prepare(ScrimState previousState) { 77 mBlankScreen = false; 78 if (previousState == ScrimState.AOD) { 79 mAnimationDuration = StackStateAnimator.ANIMATION_DURATION_WAKEUP_SCRIM; 80 if (mDisplayRequiresBlanking) { 81 // DisplayPowerManager will blank the screen, we'll just 82 // set our scrim to black in this frame to avoid flickering and 83 // fade it out afterwards. 84 mBlankScreen = true; 85 } 86 } else if (previousState == ScrimState.KEYGUARD) { 87 mAnimationDuration = StackStateAnimator.ANIMATION_DURATION_WAKEUP_SCRIM; 88 } else { 89 mAnimationDuration = ScrimController.ANIMATION_DURATION; 90 } 91 if (Flags.notificationShadeBlur()) { 92 mBehindTint = Color.TRANSPARENT; 93 mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources(), 94 mIsBlurSupported.get()); 95 mBehindAlpha = 0.0f; 96 mNotifAlpha = 0.0f; 97 mFrontAlpha = 0.0f; 98 } else { 99 mFrontTint = mBackgroundColor; 100 mBehindTint = mBackgroundColor; 101 mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT; 102 mFrontAlpha = 0; 103 mBehindAlpha = mClipQsScrim ? 1 : mScrimBehindAlphaKeyguard; 104 mNotifAlpha = mClipQsScrim ? mScrimBehindAlphaKeyguard : 0; 105 if (mClipQsScrim) { 106 updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor); 107 } 108 } 109 110 } 111 }, 112 113 /** 114 * Showing password challenge on the keyguard. 115 */ 116 BOUNCER { 117 @Override prepare(ScrimState previousState)118 public void prepare(ScrimState previousState) { 119 if (Flags.bouncerUiRevamp()) { 120 mBehindAlpha = mDefaultScrimAlpha; 121 mNotifAlpha = 0f; 122 mBehindTint = mNotifTint = mSurfaceColor; 123 mFrontAlpha = 0f; 124 return; 125 } 126 mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha; 127 mBehindTint = mClipQsScrim ? mBackgroundColor : mSurfaceColor; 128 mNotifAlpha = mClipQsScrim ? mDefaultScrimAlpha : 0; 129 mNotifTint = Color.TRANSPARENT; 130 mFrontAlpha = 0f; 131 } 132 133 @Override setSurfaceColor(int surfaceColor)134 public void setSurfaceColor(int surfaceColor) { 135 super.setSurfaceColor(surfaceColor); 136 if (Flags.bouncerUiRevamp()) { 137 mBehindTint = mNotifTint = mSurfaceColor; 138 return; 139 } 140 if (!mClipQsScrim) { 141 mBehindTint = mSurfaceColor; 142 } 143 } 144 }, 145 146 /** 147 * Showing password challenge on top of a FLAG_SHOW_WHEN_LOCKED activity. 148 */ 149 BOUNCER_SCRIMMED { 150 @ExperimentalCoroutinesApi 151 @Override prepare(ScrimState previousState)152 public void prepare(ScrimState previousState) { 153 if (Flags.bouncerUiRevamp()) { 154 // Add unlocked here because scrim state is unlocked when there is an app on top of 155 // the lockscreen and shade is pulled over it. 156 if (previousState == SHADE_LOCKED || previousState == UNLOCKED) { 157 mBehindAlpha = previousState.getBehindAlpha(); 158 mNotifAlpha = previousState.getNotifAlpha(); 159 } else { 160 mNotifAlpha = 0f; 161 mBehindAlpha = 0f; 162 } 163 mFrontAlpha = mDefaultScrimAlpha; 164 mFrontTint = mSurfaceColor; 165 return; 166 } 167 mBehindAlpha = 0; 168 mFrontAlpha = mDefaultScrimAlpha; 169 } 170 171 @Override shouldBlendWithMainColor()172 public boolean shouldBlendWithMainColor() { 173 return !Flags.bouncerUiRevamp(); 174 } 175 }, 176 177 SHADE_LOCKED { 178 @Override setDefaultScrimAlpha(float defaultScrimAlpha)179 public void setDefaultScrimAlpha(float defaultScrimAlpha) { 180 super.setDefaultScrimAlpha(defaultScrimAlpha); 181 if (!Flags.notificationShadeBlur()) { 182 // Temporary change that prevents the shade from being semi-transparent when 183 // bouncer blur is enabled but notification shade blur is not enabled. This is 184 // required to perf test these two flags independently. 185 mDefaultScrimAlpha = BUSY_SCRIM_ALPHA; 186 } 187 } 188 189 @Override prepare(ScrimState previousState)190 public void prepare(ScrimState previousState) { 191 if (Flags.notificationShadeBlur()) { 192 mBehindTint = ShadeColors.shadePanel(mScrimBehind.getResources(), 193 mIsBlurSupported.get()); 194 mBehindAlpha = Color.alpha(mBehindTint) / 255.0f; 195 mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources(), 196 mIsBlurSupported.get()); 197 mNotifAlpha = Color.alpha(mNotifTint) / 255.0f; 198 mFrontAlpha = 0.0f; 199 } else { 200 if (Flags.bouncerUiRevamp()) { 201 // This is only required until shade blur flag is fully enabled, shade is always 202 // opaque when shade blur is not enabled, and mClipQsScrim is always false. 203 mBehindAlpha = 1f; 204 mNotifAlpha = 1f; 205 mFrontAlpha = 0f; 206 mBehindTint = mBackgroundColor; 207 return; 208 } 209 mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha; 210 mNotifAlpha = 1f; 211 mFrontAlpha = 0f; 212 mBehindTint = mClipQsScrim ? Color.TRANSPARENT : mBackgroundColor; 213 214 if (mClipQsScrim) { 215 updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor); 216 } 217 } 218 } 219 }, 220 221 /** 222 * Changing screen brightness from quick settings. 223 */ 224 BRIGHTNESS_MIRROR { 225 @Override prepare(ScrimState previousState)226 public void prepare(ScrimState previousState) { 227 mBehindAlpha = 0; 228 mFrontAlpha = 0; 229 } 230 }, 231 232 /** 233 * Always on display or screen off. 234 */ 235 AOD { 236 @Override prepare(ScrimState previousState)237 public void prepare(ScrimState previousState) { 238 final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn(); 239 final boolean quickPickupEnabled = mDozeParameters.isQuickPickupEnabled(); 240 final boolean isDocked = mDockManager.isDocked(); 241 mBlankScreen = mDisplayRequiresBlanking; 242 243 mFrontTint = mBackgroundColor; 244 mFrontAlpha = (alwaysOnEnabled || isDocked || quickPickupEnabled) 245 ? mAodFrontScrimAlpha : 1f; 246 247 mBehindTint = mBackgroundColor; 248 mBehindAlpha = ScrimController.TRANSPARENT; 249 250 mAnimationDuration = ScrimController.ANIMATION_DURATION_LONG; 251 if (previousState == OFF) { 252 mAnimateChange = false; 253 } else { 254 // DisplayPowerManager may blank the screen for us, or we might blank it by 255 // animating the screen off via the LightRevelScrim. In either case we just need to 256 // set our state. 257 mAnimateChange = mDozeParameters.shouldControlScreenOff() 258 && !mDozeParameters.shouldShowLightRevealScrim(); 259 } 260 } 261 262 @Override isLowPowerState()263 public boolean isLowPowerState() { 264 return true; 265 } 266 267 @Override shouldBlendWithMainColor()268 public boolean shouldBlendWithMainColor() { 269 return false; 270 } 271 }, 272 273 /** 274 * When phone wakes up because you received a notification. 275 */ 276 PULSING { 277 @Override prepare(ScrimState previousState)278 public void prepare(ScrimState previousState) { 279 mFrontAlpha = mAodFrontScrimAlpha; 280 mBehindTint = mBackgroundColor; 281 mFrontTint = mBackgroundColor; 282 mBlankScreen = mDisplayRequiresBlanking; 283 mAnimationDuration = mWakeLockScreenSensorActive 284 ? ScrimController.ANIMATION_DURATION_LONG : ScrimController.ANIMATION_DURATION; 285 } 286 }, 287 288 /** 289 * Unlocked on top of an app (launcher or any other activity.) 290 */ 291 UNLOCKED { 292 @Override prepare(ScrimState previousState)293 public void prepare(ScrimState previousState) { 294 // State that UI will sync to. 295 mBehindAlpha = mClipQsScrim ? 1 : 0; 296 mNotifAlpha = 0; 297 mFrontAlpha = 0; 298 mAnimationDuration = mKeyguardFadingAway 299 ? mKeyguardFadingAwayDuration 300 : CentralSurfaces.FADE_KEYGUARD_DURATION; 301 302 boolean fromAod = previousState == AOD || previousState == PULSING; 303 // If launch/occlude animations were playing, they already animated the scrim 304 // alpha to 0f as part of the animation. If we animate it now, we'll set it back 305 // to 1f and animate it back to 0f, causing an unwanted scrim flash. 306 mAnimateChange = !mLaunchingAffordanceWithPreview 307 && !mOccludeAnimationPlaying 308 && !fromAod; 309 310 mFrontTint = Color.TRANSPARENT; 311 mBehindTint = mBackgroundColor; 312 mBlankScreen = false; 313 314 if (mDisplayRequiresBlanking && previousState == ScrimState.AOD) { 315 // Set all scrims black, before they fade transparent. 316 updateScrimColor(mScrimInFront, 1f /* alpha */, mBackgroundColor /* tint */); 317 updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor /* tint */); 318 319 // Scrims should still be black at the end of the transition. 320 mFrontTint = mBackgroundColor; 321 mBehindTint = mBackgroundColor; 322 mBlankScreen = true; 323 } else if (Flags.notificationShadeBlur()) { 324 mBehindTint = ShadeColors.shadePanel(mScrimBehind.getResources(), 325 mIsBlurSupported.get()); 326 mBehindAlpha = Color.alpha(mBehindTint) / 255.0f; 327 mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources(), 328 mIsBlurSupported.get()); 329 mNotifAlpha = Color.alpha(mNotifTint) / 255.0f; 330 mFrontAlpha = 0.0f; 331 return; 332 } 333 334 if (mClipQsScrim) { 335 updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor); 336 } 337 } 338 }, 339 340 DREAMING { 341 @Override prepare(ScrimState previousState)342 public void prepare(ScrimState previousState) { 343 mFrontTint = Color.TRANSPARENT; 344 mBehindTint = mBackgroundColor; 345 mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT; 346 347 mFrontAlpha = 0; 348 mBehindAlpha = mClipQsScrim ? 1 : 0; 349 mNotifAlpha = 0; 350 351 mBlankScreen = false; 352 353 if (mClipQsScrim) { 354 updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor); 355 } 356 } 357 }, 358 359 /** 360 * Device is on the lockscreen and user has swiped from the right edge to enter the glanceable 361 * hub UI. From this state, the user can swipe from the left edge to go back to the lock screen, 362 * as well as swipe down for the notifications and up for the bouncer. 363 */ 364 GLANCEABLE_HUB { 365 @Override prepare(ScrimState previousState)366 public void prepare(ScrimState previousState) { 367 // No scrims should be visible by default in this state. 368 mBehindAlpha = 0; 369 mNotifAlpha = 0; 370 mFrontAlpha = 0; 371 372 mFrontTint = Color.TRANSPARENT; 373 mBehindTint = mBackgroundColor; 374 mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT; 375 } 376 }, 377 378 /** 379 * Device is dreaming and user has swiped from the right edge to enter the glanceable hub UI. 380 * From this state, the user can swipe from the left edge to go back to the dream, as well as 381 * swipe down for the notifications and up for the bouncer. 382 * 383 * This is a separate state from {@link #GLANCEABLE_HUB} because the scrims behave differently 384 * when the dream is running. 385 */ 386 GLANCEABLE_HUB_OVER_DREAM { 387 @Override prepare(ScrimState previousState)388 public void prepare(ScrimState previousState) { 389 // No scrims should be visible by default in this state. 390 mBehindAlpha = 0; 391 mNotifAlpha = 0; 392 mFrontAlpha = 0; 393 394 mFrontTint = Color.TRANSPARENT; 395 mBehindTint = mBackgroundColor; 396 mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT; 397 } 398 }; 399 400 boolean mBlankScreen = false; 401 long mAnimationDuration = ScrimController.ANIMATION_DURATION; 402 int mFrontTint = Color.TRANSPARENT; 403 int mBehindTint = Color.TRANSPARENT; 404 int mNotifTint = Color.TRANSPARENT; 405 int mSurfaceColor = Color.TRANSPARENT; 406 407 boolean mAnimateChange = true; 408 float mAodFrontScrimAlpha; 409 float mFrontAlpha; 410 float mBehindAlpha; 411 float mNotifAlpha; 412 413 float mScrimBehindAlphaKeyguard; 414 float mDefaultScrimAlpha; 415 ScrimView mScrimInFront; 416 ScrimView mScrimBehind; 417 418 DozeParameters mDozeParameters; 419 DockManager mDockManager; 420 boolean mDisplayRequiresBlanking; 421 protected Supplier<Boolean> mIsBlurSupported; 422 boolean mLaunchingAffordanceWithPreview; 423 boolean mOccludeAnimationPlaying; 424 boolean mWakeLockScreenSensorActive; 425 boolean mKeyguardFadingAway; 426 long mKeyguardFadingAwayDuration; 427 boolean mClipQsScrim; 428 int mBackgroundColor; 429 430 // This is needed to blur the scrim behind the scrimmed bouncer to avoid showing 431 // the notification section border 432 protected float mNotifBlurRadius = 0.0f; 433 init(ScrimView scrimInFront, ScrimView scrimBehind, DozeParameters dozeParameters, DockManager dockManager, Supplier<Boolean> isBlurSupported)434 public void init(ScrimView scrimInFront, ScrimView scrimBehind, DozeParameters dozeParameters, 435 DockManager dockManager, Supplier<Boolean> isBlurSupported) { 436 mBackgroundColor = scrimBehind.getContext().getColor(R.color.shade_scrim_background_dark); 437 mScrimInFront = scrimInFront; 438 mScrimBehind = scrimBehind; 439 440 mDozeParameters = dozeParameters; 441 mDockManager = dockManager; 442 mDisplayRequiresBlanking = dozeParameters.getDisplayNeedsBlanking(); 443 mIsBlurSupported = isBlurSupported; 444 } 445 446 /** Prepare state for transition. */ prepare(ScrimState previousState)447 public void prepare(ScrimState previousState) { 448 } 449 450 /** 451 * Whether a particular state should enable blending with extracted theme colors. 452 */ shouldBlendWithMainColor()453 public boolean shouldBlendWithMainColor() { 454 return true; 455 } 456 getFrontAlpha()457 public float getFrontAlpha() { 458 return mFrontAlpha; 459 } 460 getBehindAlpha()461 public float getBehindAlpha() { 462 return mBehindAlpha; 463 } 464 getNotifAlpha()465 public float getNotifAlpha() { 466 return mNotifAlpha; 467 } 468 getFrontTint()469 public int getFrontTint() { 470 return mFrontTint; 471 } 472 getBehindTint()473 public int getBehindTint() { 474 return mBehindTint; 475 } 476 getNotifTint()477 public int getNotifTint() { 478 return mNotifTint; 479 } 480 getAnimationDuration()481 public long getAnimationDuration() { 482 return mAnimationDuration; 483 } 484 getBlanksScreen()485 public boolean getBlanksScreen() { 486 return mBlankScreen; 487 } 488 updateScrimColor(ScrimView scrim, float alpha, int tint)489 public void updateScrimColor(ScrimView scrim, float alpha, int tint) { 490 if (ScrimController.DEBUG_MODE) { 491 tint = scrim == mScrimInFront ? ScrimController.DEBUG_FRONT_TINT 492 : ScrimController.DEBUG_BEHIND_TINT; 493 } 494 TrackTracer.instantForGroup("scrim", 495 scrim == mScrimInFront ? "front_scrim_alpha" : "back_scrim_alpha", 496 (int) (alpha * 255)); 497 498 TrackTracer.instantForGroup("scrim", 499 scrim == mScrimInFront ? "front_scrim_tint" : "back_scrim_tint", 500 Color.alpha(tint)); 501 502 scrim.setTint(tint); 503 scrim.setViewAlpha(alpha); 504 } 505 getAnimateChange()506 public boolean getAnimateChange() { 507 return mAnimateChange; 508 } 509 setAodFrontScrimAlpha(float aodFrontScrimAlpha)510 public void setAodFrontScrimAlpha(float aodFrontScrimAlpha) { 511 mAodFrontScrimAlpha = aodFrontScrimAlpha; 512 } 513 setScrimBehindAlphaKeyguard(float scrimBehindAlphaKeyguard)514 public void setScrimBehindAlphaKeyguard(float scrimBehindAlphaKeyguard) { 515 mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard; 516 } 517 setDefaultScrimAlpha(float defaultScrimAlpha)518 public void setDefaultScrimAlpha(float defaultScrimAlpha) { 519 mDefaultScrimAlpha = defaultScrimAlpha; 520 } 521 setSurfaceColor(int surfaceColor)522 public void setSurfaceColor(int surfaceColor) { 523 mSurfaceColor = surfaceColor; 524 } 525 setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview)526 public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) { 527 mLaunchingAffordanceWithPreview = launchingAffordanceWithPreview; 528 } 529 setOccludeAnimationPlaying(boolean occludeAnimationPlaying)530 public void setOccludeAnimationPlaying(boolean occludeAnimationPlaying) { 531 mOccludeAnimationPlaying = occludeAnimationPlaying; 532 } 533 isLowPowerState()534 public boolean isLowPowerState() { 535 return false; 536 } 537 setWakeLockScreenSensorActive(boolean active)538 public void setWakeLockScreenSensorActive(boolean active) { 539 mWakeLockScreenSensorActive = active; 540 } 541 setKeyguardFadingAway(boolean fadingAway, long duration)542 public void setKeyguardFadingAway(boolean fadingAway, long duration) { 543 mKeyguardFadingAway = fadingAway; 544 mKeyguardFadingAwayDuration = duration; 545 } 546 setClipQsScrim(boolean clipsQsScrim)547 public void setClipQsScrim(boolean clipsQsScrim) { 548 mClipQsScrim = clipsQsScrim; 549 } 550 getNotifBlurRadius()551 public float getNotifBlurRadius() { 552 return mNotifBlurRadius; 553 } 554 setNotifBlurRadius(float value)555 public void setNotifBlurRadius(float value) { 556 mNotifBlurRadius = value; 557 } 558 } 559