1 /* 2 * Copyright (C) 2014 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 android.animation.Animator; 20 import android.animation.AnimatorListenerAdapter; 21 import android.animation.PropertyValuesHolder; 22 import android.animation.ValueAnimator; 23 import android.content.Context; 24 import android.graphics.Rect; 25 import android.support.v4.graphics.ColorUtils; 26 import android.util.TypedValue; 27 import android.view.View; 28 import android.view.ViewGroup; 29 import android.view.ViewTreeObserver; 30 import android.view.animation.DecelerateInterpolator; 31 import android.view.animation.Interpolator; 32 import android.view.animation.PathInterpolator; 33 import com.android.keyguard.KeyguardUpdateMonitor; 34 import com.android.systemui.R; 35 import com.android.systemui.statusbar.ExpandableNotificationRow; 36 import com.android.systemui.statusbar.NotificationData; 37 import com.android.systemui.statusbar.ScrimView; 38 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; 39 import com.android.systemui.statusbar.stack.ViewState; 40 41 /** 42 * Controls both the scrim behind the notifications and in front of the notifications (when a 43 * security method gets shown). 44 */ 45 public class ScrimController implements ViewTreeObserver.OnPreDrawListener, 46 OnHeadsUpChangedListener { 47 public static final long ANIMATION_DURATION = 220; 48 public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR 49 = new PathInterpolator(0f, 0, 0.7f, 1f); 50 public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED 51 = new PathInterpolator(0.3f, 0f, 0.8f, 1f); 52 protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = 0.45f; 53 protected static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f; 54 private static final float SCRIM_IN_FRONT_ALPHA = 0.75f; 55 private static final float SCRIM_IN_FRONT_ALPHA_LOCKED = 0.85f; 56 private static final int TAG_KEY_ANIM = R.id.scrim; 57 private static final int TAG_KEY_ANIM_TARGET = R.id.scrim_target; 58 private static final int TAG_START_ALPHA = R.id.scrim_alpha_start; 59 private static final int TAG_END_ALPHA = R.id.scrim_alpha_end; 60 private static final float NOT_INITIALIZED = -1; 61 62 private final LightBarController mLightBarController; 63 protected final ScrimView mScrimBehind; 64 private final ScrimView mScrimInFront; 65 private final UnlockMethodCache mUnlockMethodCache; 66 private final View mHeadsUpScrim; 67 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; 68 69 protected float mScrimBehindAlpha; 70 protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD; 71 protected float mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING; 72 73 protected boolean mKeyguardShowing; 74 private float mFraction; 75 76 private boolean mDarkenWhileDragging; 77 protected boolean mBouncerShowing; 78 protected boolean mBouncerIsKeyguard = false; 79 private boolean mWakeAndUnlocking; 80 protected boolean mAnimateChange; 81 private boolean mUpdatePending; 82 private boolean mTracking; 83 private boolean mAnimateKeyguardFadingOut; 84 protected long mDurationOverride = -1; 85 private long mAnimationDelay; 86 private Runnable mOnAnimationFinished; 87 private final Interpolator mInterpolator = new DecelerateInterpolator(); 88 private boolean mDozing; 89 private float mDozeInFrontAlpha; 90 private float mDozeBehindAlpha; 91 private float mCurrentInFrontAlpha = NOT_INITIALIZED; 92 private float mCurrentBehindAlpha = NOT_INITIALIZED; 93 private float mCurrentHeadsUpAlpha = NOT_INITIALIZED; 94 private int mPinnedHeadsUpCount; 95 private float mTopHeadsUpDragAmount; 96 private View mDraggedHeadsUpView; 97 private boolean mForceHideScrims; 98 private boolean mSkipFirstFrame; 99 private boolean mDontAnimateBouncerChanges; 100 private boolean mKeyguardFadingOutInProgress; 101 private ValueAnimator mKeyguardFadeoutAnimation; 102 ScrimController(LightBarController lightBarController, ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim)103 public ScrimController(LightBarController lightBarController, ScrimView scrimBehind, 104 ScrimView scrimInFront, View headsUpScrim) { 105 mScrimBehind = scrimBehind; 106 mScrimInFront = scrimInFront; 107 mHeadsUpScrim = headsUpScrim; 108 final Context context = scrimBehind.getContext(); 109 mUnlockMethodCache = UnlockMethodCache.getInstance(context); 110 mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(context); 111 mLightBarController = lightBarController; 112 mScrimBehindAlpha = context.getResources().getFloat(R.dimen.scrim_behind_alpha); 113 114 updateHeadsUpScrim(false); 115 updateScrims(); 116 } 117 setKeyguardShowing(boolean showing)118 public void setKeyguardShowing(boolean showing) { 119 mKeyguardShowing = showing; 120 scheduleUpdate(); 121 } 122 setScrimBehindValues(float scrimBehindAlphaKeyguard, float scrimBehindAlphaUnlocking)123 protected void setScrimBehindValues(float scrimBehindAlphaKeyguard, 124 float scrimBehindAlphaUnlocking) { 125 mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard; 126 mScrimBehindAlphaUnlocking = scrimBehindAlphaUnlocking; 127 scheduleUpdate(); 128 } 129 onTrackingStarted()130 public void onTrackingStarted() { 131 mTracking = true; 132 mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer(); 133 } 134 onExpandingFinished()135 public void onExpandingFinished() { 136 mTracking = false; 137 } 138 setPanelExpansion(float fraction)139 public void setPanelExpansion(float fraction) { 140 if (mFraction != fraction) { 141 mFraction = fraction; 142 scheduleUpdate(); 143 if (mPinnedHeadsUpCount != 0) { 144 updateHeadsUpScrim(false); 145 } 146 if (mKeyguardFadeoutAnimation != null && mTracking) { 147 mKeyguardFadeoutAnimation.cancel(); 148 } 149 } 150 } 151 setBouncerShowing(boolean showing)152 public void setBouncerShowing(boolean showing) { 153 mBouncerShowing = showing; 154 mAnimateChange = !mTracking && !mDontAnimateBouncerChanges; 155 scheduleUpdate(); 156 } 157 setWakeAndUnlocking()158 public void setWakeAndUnlocking() { 159 mWakeAndUnlocking = true; 160 scheduleUpdate(); 161 } 162 animateKeyguardFadingOut(long delay, long duration, Runnable onAnimationFinished, boolean skipFirstFrame)163 public void animateKeyguardFadingOut(long delay, long duration, Runnable onAnimationFinished, 164 boolean skipFirstFrame) { 165 mWakeAndUnlocking = false; 166 mAnimateKeyguardFadingOut = true; 167 mDurationOverride = duration; 168 mAnimationDelay = delay; 169 mAnimateChange = true; 170 mSkipFirstFrame = skipFirstFrame; 171 mOnAnimationFinished = onAnimationFinished; 172 173 if (!mKeyguardUpdateMonitor.needsSlowUnlockTransition()) { 174 scheduleUpdate(); 175 176 // No need to wait for the next frame to be drawn for this case - onPreDraw will execute 177 // the changes we just scheduled. 178 onPreDraw(); 179 } else { 180 181 // In case the user isn't unlocked, make sure to delay a bit because the system is hosed 182 // with too many things in this case, in order to not skip the initial frames. 183 mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16); 184 } 185 } 186 abortKeyguardFadingOut()187 public void abortKeyguardFadingOut() { 188 if (mAnimateKeyguardFadingOut) { 189 endAnimateKeyguardFadingOut(true /* force */); 190 } 191 } 192 animateKeyguardUnoccluding(long duration)193 public void animateKeyguardUnoccluding(long duration) { 194 mAnimateChange = false; 195 setScrimBehindColor(0f); 196 mAnimateChange = true; 197 scheduleUpdate(); 198 mDurationOverride = duration; 199 } 200 animateGoingToFullShade(long delay, long duration)201 public void animateGoingToFullShade(long delay, long duration) { 202 mDurationOverride = duration; 203 mAnimationDelay = delay; 204 mAnimateChange = true; 205 scheduleUpdate(); 206 } 207 setDozing(boolean dozing)208 public void setDozing(boolean dozing) { 209 if (mDozing != dozing) { 210 mDozing = dozing; 211 scheduleUpdate(); 212 } 213 } 214 setDozeInFrontAlpha(float alpha)215 public void setDozeInFrontAlpha(float alpha) { 216 mDozeInFrontAlpha = alpha; 217 updateScrimColor(mScrimInFront); 218 } 219 setDozeBehindAlpha(float alpha)220 public void setDozeBehindAlpha(float alpha) { 221 mDozeBehindAlpha = alpha; 222 updateScrimColor(mScrimBehind); 223 } 224 getDozeBehindAlpha()225 public float getDozeBehindAlpha() { 226 return mDozeBehindAlpha; 227 } 228 getDozeInFrontAlpha()229 public float getDozeInFrontAlpha() { 230 return mDozeInFrontAlpha; 231 } 232 getScrimInFrontAlpha()233 private float getScrimInFrontAlpha() { 234 return mKeyguardUpdateMonitor.needsSlowUnlockTransition() 235 ? SCRIM_IN_FRONT_ALPHA_LOCKED 236 : SCRIM_IN_FRONT_ALPHA; 237 } 238 scheduleUpdate()239 protected void scheduleUpdate() { 240 if (mUpdatePending) return; 241 242 // Make sure that a frame gets scheduled. 243 mScrimBehind.invalidate(); 244 mScrimBehind.getViewTreeObserver().addOnPreDrawListener(this); 245 mUpdatePending = true; 246 } 247 updateScrims()248 protected void updateScrims() { 249 if (mAnimateKeyguardFadingOut || mForceHideScrims) { 250 setScrimInFrontColor(0f); 251 setScrimBehindColor(0f); 252 } else if (mWakeAndUnlocking) { 253 254 // During wake and unlock, we first hide everything behind a black scrim, which then 255 // gets faded out from animateKeyguardFadingOut. 256 if (mDozing) { 257 setScrimInFrontColor(0f); 258 setScrimBehindColor(1f); 259 } else { 260 setScrimInFrontColor(1f); 261 setScrimBehindColor(0f); 262 } 263 } else if (!mKeyguardShowing && !mBouncerShowing) { 264 updateScrimNormal(); 265 setScrimInFrontColor(0); 266 } else { 267 updateScrimKeyguard(); 268 } 269 mAnimateChange = false; 270 } 271 updateScrimKeyguard()272 private void updateScrimKeyguard() { 273 if (mTracking && mDarkenWhileDragging) { 274 float behindFraction = Math.max(0, Math.min(mFraction, 1)); 275 float fraction = 1 - behindFraction; 276 fraction = (float) Math.pow(fraction, 0.8f); 277 behindFraction = (float) Math.pow(behindFraction, 0.8f); 278 setScrimInFrontColor(fraction * getScrimInFrontAlpha()); 279 setScrimBehindColor(behindFraction * mScrimBehindAlphaKeyguard); 280 } else if (mBouncerShowing && !mBouncerIsKeyguard) { 281 setScrimInFrontColor(getScrimInFrontAlpha()); 282 updateScrimNormal(); 283 } else if (mBouncerShowing) { 284 setScrimInFrontColor(0f); 285 setScrimBehindColor(mScrimBehindAlpha); 286 } else { 287 float fraction = Math.max(0, Math.min(mFraction, 1)); 288 setScrimInFrontColor(0f); 289 setScrimBehindColor(fraction 290 * (mScrimBehindAlphaKeyguard - mScrimBehindAlphaUnlocking) 291 + mScrimBehindAlphaUnlocking); 292 } 293 } 294 updateScrimNormal()295 private void updateScrimNormal() { 296 float frac = mFraction; 297 // let's start this 20% of the way down the screen 298 frac = frac * 1.2f - 0.2f; 299 if (frac <= 0) { 300 setScrimBehindColor(0); 301 } else { 302 // woo, special effects 303 final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f)))); 304 setScrimBehindColor(k * mScrimBehindAlpha); 305 } 306 } 307 setScrimBehindColor(float alpha)308 private void setScrimBehindColor(float alpha) { 309 setScrimColor(mScrimBehind, alpha); 310 } 311 setScrimInFrontColor(float alpha)312 private void setScrimInFrontColor(float alpha) { 313 setScrimColor(mScrimInFront, alpha); 314 if (alpha == 0f) { 315 mScrimInFront.setClickable(false); 316 } else { 317 318 // Eat touch events (unless dozing). 319 mScrimInFront.setClickable(!mDozing); 320 } 321 } 322 setScrimColor(View scrim, float alpha)323 private void setScrimColor(View scrim, float alpha) { 324 updateScrim(mAnimateChange, scrim, alpha, getCurrentScrimAlpha(scrim)); 325 } 326 getDozeAlpha(View scrim)327 protected float getDozeAlpha(View scrim) { 328 return scrim == mScrimBehind ? mDozeBehindAlpha : mDozeInFrontAlpha; 329 } 330 getCurrentScrimAlpha(View scrim)331 protected float getCurrentScrimAlpha(View scrim) { 332 return scrim == mScrimBehind ? mCurrentBehindAlpha 333 : scrim == mScrimInFront ? mCurrentInFrontAlpha 334 : mCurrentHeadsUpAlpha; 335 } 336 setCurrentScrimAlpha(View scrim, float alpha)337 private void setCurrentScrimAlpha(View scrim, float alpha) { 338 if (scrim == mScrimBehind) { 339 mCurrentBehindAlpha = alpha; 340 mLightBarController.setScrimAlpha(mCurrentBehindAlpha); 341 } else if (scrim == mScrimInFront) { 342 mCurrentInFrontAlpha = alpha; 343 } else { 344 alpha = Math.max(0.0f, Math.min(1.0f, alpha)); 345 mCurrentHeadsUpAlpha = alpha; 346 } 347 } 348 updateScrimColor(View scrim)349 protected void updateScrimColor(View scrim) { 350 float alpha1 = getCurrentScrimAlpha(scrim); 351 if (scrim instanceof ScrimView) { 352 float alpha2 = getDozeAlpha(scrim); 353 float alpha = 1 - (1 - alpha1) * (1 - alpha2); 354 alpha = Math.max(0, Math.min(1.0f, alpha)); 355 int baseColor = ((ScrimView) scrim).getScrimColor(); 356 ((ScrimView) scrim).setScrimColor( 357 ColorUtils.setAlphaComponent(baseColor, (int) (alpha * 255))); 358 } else { 359 scrim.setAlpha(alpha1); 360 } 361 } 362 startScrimAnimation(final View scrim, float target)363 private void startScrimAnimation(final View scrim, float target) { 364 float current = getCurrentScrimAlpha(scrim); 365 ValueAnimator anim = ValueAnimator.ofFloat(current, target); 366 anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 367 @Override 368 public void onAnimationUpdate(ValueAnimator animation) { 369 float alpha = (float) animation.getAnimatedValue(); 370 setCurrentScrimAlpha(scrim, alpha); 371 updateScrimColor(scrim); 372 } 373 }); 374 anim.setInterpolator(getInterpolator()); 375 anim.setStartDelay(mAnimationDelay); 376 anim.setDuration(mDurationOverride != -1 ? mDurationOverride : ANIMATION_DURATION); 377 anim.addListener(new AnimatorListenerAdapter() { 378 @Override 379 public void onAnimationEnd(Animator animation) { 380 if (mOnAnimationFinished != null) { 381 mOnAnimationFinished.run(); 382 mOnAnimationFinished = null; 383 } 384 if (mKeyguardFadingOutInProgress) { 385 mKeyguardFadeoutAnimation = null; 386 mKeyguardFadingOutInProgress = false; 387 } 388 scrim.setTag(TAG_KEY_ANIM, null); 389 scrim.setTag(TAG_KEY_ANIM_TARGET, null); 390 } 391 }); 392 anim.start(); 393 if (mAnimateKeyguardFadingOut) { 394 mKeyguardFadingOutInProgress = true; 395 mKeyguardFadeoutAnimation = anim; 396 } 397 if (mSkipFirstFrame) { 398 anim.setCurrentPlayTime(16); 399 } 400 scrim.setTag(TAG_KEY_ANIM, anim); 401 scrim.setTag(TAG_KEY_ANIM_TARGET, target); 402 } 403 getInterpolator()404 protected Interpolator getInterpolator() { 405 if (mAnimateKeyguardFadingOut && mKeyguardUpdateMonitor.needsSlowUnlockTransition()) { 406 return KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED; 407 } else if (mAnimateKeyguardFadingOut) { 408 return KEYGUARD_FADE_OUT_INTERPOLATOR; 409 } else { 410 return mInterpolator; 411 } 412 } 413 414 @Override onPreDraw()415 public boolean onPreDraw() { 416 mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this); 417 mUpdatePending = false; 418 if (mDontAnimateBouncerChanges) { 419 mDontAnimateBouncerChanges = false; 420 } 421 updateScrims(); 422 mDurationOverride = -1; 423 mAnimationDelay = 0; 424 mSkipFirstFrame = false; 425 426 // Make sure that we always call the listener even if we didn't start an animation. 427 endAnimateKeyguardFadingOut(false /* force */); 428 return true; 429 } 430 endAnimateKeyguardFadingOut(boolean force)431 private void endAnimateKeyguardFadingOut(boolean force) { 432 mAnimateKeyguardFadingOut = false; 433 if (force || (!isAnimating(mScrimInFront) && !isAnimating(mScrimBehind))) { 434 if (mOnAnimationFinished != null) { 435 mOnAnimationFinished.run(); 436 mOnAnimationFinished = null; 437 } 438 mKeyguardFadingOutInProgress = false; 439 } 440 } 441 isAnimating(View scrim)442 private boolean isAnimating(View scrim) { 443 return scrim.getTag(TAG_KEY_ANIM) != null; 444 } 445 setDrawBehindAsSrc(boolean asSrc)446 public void setDrawBehindAsSrc(boolean asSrc) { 447 mScrimBehind.setDrawAsSrc(asSrc); 448 } 449 450 @Override onHeadsUpPinnedModeChanged(boolean inPinnedMode)451 public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) { 452 } 453 454 @Override onHeadsUpPinned(ExpandableNotificationRow headsUp)455 public void onHeadsUpPinned(ExpandableNotificationRow headsUp) { 456 mPinnedHeadsUpCount++; 457 updateHeadsUpScrim(true); 458 } 459 460 @Override onHeadsUpUnPinned(ExpandableNotificationRow headsUp)461 public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) { 462 mPinnedHeadsUpCount--; 463 if (headsUp == mDraggedHeadsUpView) { 464 mDraggedHeadsUpView = null; 465 mTopHeadsUpDragAmount = 0.0f; 466 } 467 updateHeadsUpScrim(true); 468 } 469 470 @Override onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp)471 public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) { 472 } 473 updateHeadsUpScrim(boolean animate)474 private void updateHeadsUpScrim(boolean animate) { 475 updateScrim(animate, mHeadsUpScrim, calculateHeadsUpAlpha(), mCurrentHeadsUpAlpha); 476 } 477 updateScrim(boolean animate, View scrim, float alpha, float currentAlpha)478 private void updateScrim(boolean animate, View scrim, float alpha, float currentAlpha) { 479 if (mKeyguardFadingOutInProgress && mKeyguardFadeoutAnimation.getCurrentPlayTime() != 0) { 480 return; 481 } 482 483 ValueAnimator previousAnimator = ViewState.getChildTag(scrim, 484 TAG_KEY_ANIM); 485 float animEndValue = -1; 486 if (previousAnimator != null) { 487 if (animate || alpha == currentAlpha) { 488 previousAnimator.cancel(); 489 } else { 490 animEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA); 491 } 492 } 493 if (alpha != currentAlpha && alpha != animEndValue) { 494 if (animate) { 495 startScrimAnimation(scrim, alpha); 496 scrim.setTag(TAG_START_ALPHA, currentAlpha); 497 scrim.setTag(TAG_END_ALPHA, alpha); 498 } else { 499 if (previousAnimator != null) { 500 float previousStartValue = ViewState.getChildTag(scrim, TAG_START_ALPHA); 501 float previousEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA); 502 // we need to increase all animation keyframes of the previous animator by the 503 // relative change to the end value 504 PropertyValuesHolder[] values = previousAnimator.getValues(); 505 float relativeDiff = alpha - previousEndValue; 506 float newStartValue = previousStartValue + relativeDiff; 507 newStartValue = Math.max(0, Math.min(1.0f, newStartValue)); 508 values[0].setFloatValues(newStartValue, alpha); 509 scrim.setTag(TAG_START_ALPHA, newStartValue); 510 scrim.setTag(TAG_END_ALPHA, alpha); 511 previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); 512 } else { 513 // update the alpha directly 514 setCurrentScrimAlpha(scrim, alpha); 515 updateScrimColor(scrim); 516 } 517 } 518 } 519 } 520 521 /** 522 * Set the amount the current top heads up view is dragged. The range is from 0 to 1 and 0 means 523 * the heads up is in its resting space and 1 means it's fully dragged out. 524 * 525 * @param draggedHeadsUpView the dragged view 526 * @param topHeadsUpDragAmount how far is it dragged 527 */ setTopHeadsUpDragAmount(View draggedHeadsUpView, float topHeadsUpDragAmount)528 public void setTopHeadsUpDragAmount(View draggedHeadsUpView, float topHeadsUpDragAmount) { 529 mTopHeadsUpDragAmount = topHeadsUpDragAmount; 530 mDraggedHeadsUpView = draggedHeadsUpView; 531 updateHeadsUpScrim(false); 532 } 533 calculateHeadsUpAlpha()534 private float calculateHeadsUpAlpha() { 535 float alpha; 536 if (mPinnedHeadsUpCount >= 2) { 537 alpha = 1.0f; 538 } else if (mPinnedHeadsUpCount == 0) { 539 alpha = 0.0f; 540 } else { 541 alpha = 1.0f - mTopHeadsUpDragAmount; 542 } 543 float expandFactor = (1.0f - mFraction); 544 expandFactor = Math.max(expandFactor, 0.0f); 545 return alpha * expandFactor; 546 } 547 forceHideScrims(boolean hide)548 public void forceHideScrims(boolean hide) { 549 mForceHideScrims = hide; 550 mAnimateChange = false; 551 scheduleUpdate(); 552 } 553 dontAnimateBouncerChangesUntilNextFrame()554 public void dontAnimateBouncerChangesUntilNextFrame() { 555 mDontAnimateBouncerChanges = true; 556 } 557 setExcludedBackgroundArea(Rect area)558 public void setExcludedBackgroundArea(Rect area) { 559 mScrimBehind.setExcludedArea(area); 560 } 561 getScrimBehindColor()562 public int getScrimBehindColor() { 563 return mScrimBehind.getScrimColorWithAlpha(); 564 } 565 setScrimBehindChangeRunnable(Runnable changeRunnable)566 public void setScrimBehindChangeRunnable(Runnable changeRunnable) { 567 mScrimBehind.setChangeRunnable(changeRunnable); 568 } 569 onDensityOrFontScaleChanged()570 public void onDensityOrFontScaleChanged() { 571 ViewGroup.LayoutParams layoutParams = mHeadsUpScrim.getLayoutParams(); 572 layoutParams.height = mHeadsUpScrim.getResources().getDimensionPixelSize( 573 R.dimen.heads_up_scrim_height); 574 mHeadsUpScrim.setLayoutParams(layoutParams); 575 } 576 setCurrentUser(int currentUser)577 public void setCurrentUser(int currentUser) { 578 // Don't care in the base class. 579 } 580 } 581