Bouncer animation

More obvious animation where bouncer position is influenced
by touches.

Test: Pull up bouncer, press back button
Test: Pull up bouncer, unlock with fp
Test: Unlock with fp with bouncer hidden
Test: Unlock with SmartLock
Test: Ask for auth on top of FLAG_SHOW_WHEN_LOCKED activity, press back
Test: packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
Fixes: 3699775
Change-Id: I016dfa17f17571261691669c82385d2d844c5917
This commit is contained in:
Lucas Dupin
2018-03-04 20:18:15 -08:00
parent 87030d72b0
commit bc9aac10e2
20 changed files with 218 additions and 90 deletions

View File

@@ -1,5 +1,5 @@
<!--
~ Copyright (C) 2014 The Android Open Source Project
~ Copyright (C) 2018 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,5 +15,6 @@
-->
<resources>
<dimen name="keyguard_clock_notifications_margin">32dp</dimen>
<!-- Minimum margin between clock and top of screen or ambient indication -->
<dimen name="keyguard_clock_top_margin">76dp</dimen>
</resources>

View File

@@ -443,8 +443,8 @@
<!-- The margin between the clock and the notifications on Keyguard.-->
<dimen name="keyguard_clock_notifications_margin">30dp</dimen>
<!-- Minimum margin between clock and top of screen or ambient indication -->
<dimen name="keyguard_clock_top_margin">26dp</dimen>
<!-- Minimum margin between clock and status bar -->
<dimen name="keyguard_clock_top_margin">36dp</dimen>
<dimen name="heads_up_scrim_height">250dp</dimen>
<item name="scrim_behind_alpha" format="float" type="dimen">0.62</item>

View File

@@ -149,7 +149,6 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
mSecurityContainer.setLockPatternUtils(mLockPatternUtils);
mSecurityContainer.setSecurityCallback(this);
mSecurityContainer.showPrimarySecurityScreen(false);
// mSecurityContainer.updateSecurityViews(false /* not bouncing */);
}
/**

View File

@@ -79,8 +79,8 @@ public class AnglesClassifier extends StrokeClassifier {
@Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
Data data = mStrokeMap.get(stroke);
return AnglesVarianceEvaluator.evaluate(data.getAnglesVariance())
+ AnglesPercentageEvaluator.evaluate(data.getAnglesPercentage());
return AnglesVarianceEvaluator.evaluate(data.getAnglesVariance(), type)
+ AnglesPercentageEvaluator.evaluate(data.getAnglesPercentage(), type);
}
private static class Data {

View File

@@ -17,10 +17,11 @@
package com.android.systemui.classifier;
public class AnglesPercentageEvaluator {
public static float evaluate(float value) {
public static float evaluate(float value, int type) {
final boolean secureUnlock = type == Classifier.BOUNCER_UNLOCK;
float evaluation = 0.0f;
if (value < 1.00) evaluation++;
if (value < 0.90) evaluation++;
if (value < 1.00 && !secureUnlock) evaluation++;
if (value < 0.90 && !secureUnlock) evaluation++;
if (value < 0.70) evaluation++;
return evaluation;
}

View File

@@ -17,14 +17,15 @@
package com.android.systemui.classifier;
public class AnglesVarianceEvaluator {
public static float evaluate(float value) {
public static float evaluate(float value, int type) {
final boolean secureUnlock = type == Classifier.BOUNCER_UNLOCK;
float evaluation = 0.0f;
if (value > 0.05) evaluation++;
if (value > 0.10) evaluation++;
if (value > 0.20) evaluation++;
if (value > 0.40) evaluation++;
if (value > 0.80) evaluation++;
if (value > 1.50) evaluation++;
if (value > 0.40 && !secureUnlock) evaluation++;
if (value > 0.80 && !secureUnlock) evaluation++;
if (value > 1.50 && !secureUnlock) evaluation++;
return evaluation;
}
}

View File

@@ -31,6 +31,7 @@ public abstract class Classifier {
public static final int LEFT_AFFORDANCE = 5;
public static final int RIGHT_AFFORDANCE = 6;
public static final int GENERIC = 7;
public static final int BOUNCER_UNLOCK = 8;
/**
* Contains all the information about touch events from which the classifier can query

View File

@@ -33,6 +33,7 @@ public class DirectionEvaluator {
}
break;
case Classifier.UNLOCK:
case Classifier.BOUNCER_UNLOCK:
if (!vertical || yDiff >= 0.0) {
return falsingEvaluation;
}

View File

@@ -356,11 +356,12 @@ public class FalsingManager implements SensorEventListener {
mDataCollector.setQsExpanded(expanded);
}
public void onTrackingStarted() {
public void onTrackingStarted(boolean secure) {
if (FalsingLog.ENABLED) {
FalsingLog.i("onTrackingStarted", "");
}
mHumanInteractionClassifier.setType(Classifier.UNLOCK);
mHumanInteractionClassifier.setType(secure ?
Classifier.BOUNCER_UNLOCK : Classifier.UNLOCK);
mDataCollector.onTrackingStarted();
}

View File

@@ -83,6 +83,7 @@ import com.android.systemui.SystemUIFactory;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.phone.FingerprintUnlockController;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -2011,8 +2012,9 @@ public class KeyguardViewMediator extends SystemUI {
}
public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar,
ViewGroup container, FingerprintUnlockController fingerprintUnlockController) {
mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container,
ViewGroup container, NotificationPanelView panelView,
FingerprintUnlockController fingerprintUnlockController) {
mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container, panelView,
fingerprintUnlockController, mDismissCallbackRegistry);
return mStatusBarKeyguardViewManager;
}

View File

@@ -20,6 +20,7 @@ import android.content.Context;
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.MathUtils;
import android.util.Slog;
import android.util.StatsLog;
import android.view.KeyEvent;
@@ -49,7 +50,8 @@ import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
*/
public class KeyguardBouncer {
final static private String TAG = "KeyguardBouncer";
private static final String TAG = "KeyguardBouncer";
static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
protected final Context mContext;
protected final ViewMediatorCallback mCallback;
@@ -86,13 +88,25 @@ public class KeyguardBouncer {
}
public void show(boolean resetSecuritySelection) {
show(resetSecuritySelection, true /* notifyFalsing */);
}
public void show(boolean resetSecuritySelection, boolean notifyFalsing) {
final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
// In split system user mode, we never unlock system user.
return;
}
mFalsingManager.onBouncerShown();
ensureView();
// On the keyguard, we want to show the bouncer when the user drags up, but it's
// not correct to end the falsing session. We still need to verify if those touches
// are valid.
// Later, at the end of the animation, when the bouncer is at the top of the screen,
// onFullyShown() will be called and FalsingManager will stop recording touches.
if (notifyFalsing) {
mFalsingManager.onBouncerShown();
}
if (resetSecuritySelection) {
// showPrimarySecurityScreen() updates the current security method. This is needed in
// case we are already showing and the current security method changed.
@@ -126,6 +140,28 @@ public class KeyguardBouncer {
mCallback.onBouncerVisiblityChanged(true /* shown */);
}
/**
* This method must be called at the end of the bouncer animation when
* the translation is performed manually by the user, otherwise FalsingManager
* will never be notified and its internal state will be out of sync.
*/
public void onFullyShown() {
mFalsingManager.onBouncerShown();
}
/**
* This method must be called at the end of the bouncer animation when
* the translation is performed manually by the user, otherwise FalsingManager
* will never be notified and its internal state will be out of sync.
*/
public void onFullyHidden() {
if (!mShowingSoon) {
cancelShowRunnable();
inflateView();
mFalsingManager.onBouncerHidden();
}
}
private final Runnable mShowRunnable = new Runnable() {
@Override
public void run() {
@@ -247,6 +283,18 @@ public class KeyguardBouncer {
mBouncerPromptReason = mCallback.getBouncerPromptReason();
}
/**
* Current notification panel expansion
* @param fraction 0 when notification panel is collapsed and 1 when expanded.
* @see StatusBarKeyguardViewManager#onPanelExpansionChanged
*/
public void setExpansion(float fraction) {
if (mKeyguardView != null) {
mKeyguardView.setAlpha(MathUtils.map(ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction));
mKeyguardView.setTranslationY(fraction * mKeyguardView.getHeight());
}
}
protected void ensureView() {
// Removal of the view might be deferred to reduce unlock latency,
// in this case we need to force the removal, otherwise we'll

View File

@@ -79,14 +79,9 @@ public class KeyguardClockPositionAlgorithm {
private int mMaxShadeBottom;
/**
* Margin that we should respect within the available space.
* Minimum distance from the status bar.
*/
private int mContainerPadding;
/**
* Position where clock should be when the panel is collapsed.
*/
private int mClockYTarget;
private int mContainerTopPadding;
/**
* @see NotificationPanelView#getMaxPanelHeight()
@@ -108,13 +103,23 @@ public class KeyguardClockPositionAlgorithm {
*/
private float mDarkAmount;
/**
* If keyguard will require a password or just fade away.
*/
private boolean mCurrentlySecure;
/**
* If notification panel view currently has a touch.
*/
private boolean mTracking;
/**
* Refreshes the dimension values.
*/
public void loadDimens(Resources res) {
mClockNotificationsMargin = res.getDimensionPixelSize(
R.dimen.keyguard_clock_notifications_margin);
mContainerPadding = res.getDimensionPixelSize(
mContainerTopPadding = res.getDimensionPixelSize(
R.dimen.keyguard_clock_top_margin);
mBurnInPreventionOffsetX = res.getDimensionPixelSize(
R.dimen.burn_in_prevention_offset_x);
@@ -124,8 +129,8 @@ public class KeyguardClockPositionAlgorithm {
public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight,
float expandedHeight, float maxPanelHeight, int parentHeight, int keyguardStatusHeight,
float dark) {
mMinTopMargin = minTopMargin;
float dark, boolean secure, boolean tracking) {
mMinTopMargin = minTopMargin + mContainerTopPadding;
mMaxShadeBottom = maxShadeBottom;
mNotificationStackHeight = notificationStackHeight;
mExpandedHeight = expandedHeight;
@@ -133,13 +138,8 @@ public class KeyguardClockPositionAlgorithm {
mHeight = parentHeight;
mKeyguardStatusHeight = keyguardStatusHeight;
mDarkAmount = dark;
// Where the clock should stop when swiping up.
// This should be outside of the display when unlocked or
// under then status bar when the bouncer will be shown
mClockYTarget = -mKeyguardStatusHeight;
// TODO: on bouncer animation follow-up CL
// mClockYTarget = mMinTopMargin + mContainerPadding;
mCurrentlySecure = secure;
mTracking = tracking;
}
public void run(Result result) {
@@ -173,8 +173,8 @@ public class KeyguardClockPositionAlgorithm {
float y = containerCenter - mKeyguardStatusHeight * CLOCK_HEIGHT_WEIGHT
- mClockNotificationsMargin - mNotificationStackHeight / 2;
if (y < mMinTopMargin + mContainerPadding) {
y = mMinTopMargin + mContainerPadding;
if (y < mMinTopMargin) {
y = mMinTopMargin;
}
// Don't allow the clock base to be under half of the screen
@@ -190,18 +190,32 @@ public class KeyguardClockPositionAlgorithm {
// Dark: Align the bottom edge of the clock at about half of the screen:
final float clockYDark = getMaxClockY() + burnInPreventionOffsetY();
float clockYRegular = getExpandedClockPosition();
float clockYTarget = mCurrentlySecure ? mMinTopMargin : -mKeyguardStatusHeight;
// Move clock up while collapsing the shade
final float shadeExpansion = mExpandedHeight / mMaxPanelHeight;
final float clockY = MathUtils.lerp(mClockYTarget, clockYRegular, shadeExpansion);
final float clockY = MathUtils.lerp(clockYTarget, clockYRegular, shadeExpansion);
return (int) MathUtils.lerp(clockY, clockYDark, mDarkAmount);
}
/**
* We might want to fade out the clock when the user is swiping up.
* One exception is when the bouncer will become visible, in this cause the clock
* should always persist.
*
* @param y Current clock Y.
* @return Alpha from 0 to 1.
*/
private float getClockAlpha(int y) {
float alphaKeyguard = Math.max(0, Math.min(1, (y - mMinTopMargin)
/ Math.max(1f, getExpandedClockPosition() - mMinTopMargin)));
alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
float alphaKeyguard;
if (mCurrentlySecure) {
alphaKeyguard = 1;
} else {
alphaKeyguard = Math.max(0, Math.min(1, (y - mMinTopMargin)
/ Math.max(1f, getExpandedClockPosition() - mMinTopMargin)));
alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
}
return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
}

View File

@@ -238,7 +238,6 @@ public class NotificationPanelView extends PanelView implements
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private boolean mNoVisibleNotifications = true;
private ValueAnimator mDarkAnimator;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private boolean mUserSetupComplete;
private int mQsNotificationTopPadding;
private float mExpandOffset;
@@ -265,10 +264,8 @@ public class NotificationPanelView extends PanelView implements
mKeyguardStatusBar = findViewById(R.id.keyguard_header);
mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
mNotificationContainerParent = (NotificationsQuickSettingsContainer)
findViewById(R.id.notification_container_parent);
mNotificationStackScroller = (NotificationStackScrollLayout)
findViewById(R.id.notification_stack_scroller);
mNotificationContainerParent = findViewById(R.id.notification_container_parent);
mNotificationStackScroller = findViewById(R.id.notification_stack_scroller);
mNotificationStackScroller.setOnHeightChangedListener(this);
mNotificationStackScroller.setOverscrollTopChangedListener(this);
mNotificationStackScroller.setOnEmptySpaceClickListener(this);
@@ -470,7 +467,9 @@ public class NotificationPanelView extends PanelView implements
getMaxPanelHeight(),
totalHeight,
mKeyguardStatusView.getHeight(),
mDarkAmount);
mDarkAmount,
mStatusBar.isKeyguardCurrentlySecure(),
mTracking);
mClockPositionAlgorithm.run(mClockPositionResult);
if (animate || mClockAnimator != null) {
startClockAnimation(mClockPositionResult.clockX, mClockPositionResult.clockY);
@@ -1710,7 +1709,16 @@ public class NotificationPanelView extends PanelView implements
}
private void updateKeyguardBottomAreaAlpha() {
float alpha = Math.min(getKeyguardContentsAlpha(), 1 - getQsExpansionFraction());
// There are two possible panel expansion behaviors:
// • User dragging up to unlock: we want to fade out as quick as possible
// (ALPHA_EXPANSION_THRESHOLD) to avoid seeing the bouncer over the bottom area.
// • User tapping on lock screen: bouncer won't be visible but panel expansion will
// change due to "unlock hint animation." In this case, fading out the bottom area
// would also hide the message that says "swipe to unlock," we don't want to do that.
float expansionAlpha = MathUtils.map(isUnlockHintRunning()
? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f,
0f, 1f, getExpandedFraction());
float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
mKeyguardBottomArea.setAlpha(alpha);
mKeyguardBottomArea.setImportantForAccessibility(alpha == 0f
? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
@@ -1809,7 +1817,7 @@ public class NotificationPanelView extends PanelView implements
@Override
protected void onTrackingStarted() {
mFalsingManager.onTrackingStarted();
mFalsingManager.onTrackingStarted(mStatusBar.isKeyguardCurrentlySecure());
super.onTrackingStarted();
if (mQsFullyExpanded) {
mQsExpandImmediate = true;

View File

@@ -27,6 +27,7 @@ public abstract class PanelBar extends FrameLayout {
public static final boolean DEBUG = false;
public static final String TAG = PanelBar.class.getSimpleName();
private static final boolean SPEW = false;
private boolean mBouncerShowing;
public static final void LOG(String fmt, Object... args) {
if (!DEBUG) return;
@@ -65,6 +66,7 @@ public abstract class PanelBar extends FrameLayout {
}
public void setBouncerShowing(boolean showing) {
mBouncerShowing = showing;
int important = showing ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: IMPORTANT_FOR_ACCESSIBILITY_AUTO;
@@ -122,7 +124,7 @@ public abstract class PanelBar extends FrameLayout {
boolean fullyOpened = false;
if (SPEW) LOG("panelExpansionChanged: start state=%d", mState);
PanelView pv = mPanel;
pv.setVisibility(expanded ? VISIBLE : INVISIBLE);
pv.setVisibility(expanded || mBouncerShowing ? VISIBLE : INVISIBLE);
// adjust any other panels that may be partially visible
if (expanded) {
if (mState == STATE_CLOSED) {

View File

@@ -23,14 +23,8 @@ import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.view.InputDevice;
@@ -51,10 +45,10 @@ import com.android.systemui.doze.DozeLog;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.function.BiConsumer;
public abstract class PanelView extends FrameLayout {
public static final boolean DEBUG = PanelBar.DEBUG;
@@ -69,6 +63,7 @@ public abstract class PanelView extends FrameLayout {
private boolean mVibrateOnOpening;
protected boolean mLaunchingNotification;
private int mFixedDuration = NO_FIXED_DURATION;
private BiConsumer<Float, Boolean> mExpansionListener;
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -326,7 +321,8 @@ public abstract class PanelView extends FrameLayout {
cancelPeek();
onTrackingStarted();
}
if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()) {
if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()
&& !mStatusBar.isBouncerShowing()) {
startOpening(event);
}
break;
@@ -490,7 +486,8 @@ public abstract class PanelView extends FrameLayout {
if (mUpdateFlingOnLayout) {
mUpdateFlingVelocity = vel;
}
} else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking) {
} else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking
&& !mStatusBar.isBouncerShowing()) {
long timePassed = SystemClock.uptimeMillis() - mDownTime;
if (timePassed < ViewConfiguration.getLongPressTimeout()) {
// Lets show the user that he can actually expand the panel
@@ -499,7 +496,7 @@ public abstract class PanelView extends FrameLayout {
// We need to collapse the panel since we peeked to the small height.
postOnAnimation(mPostCollapseRunnable);
}
} else {
} else if (!mStatusBar.isBouncerShowing()) {
boolean expands = onEmptySpaceClick(mInitialTouchX);
onTrackingStopped(expands);
}
@@ -1099,6 +1096,10 @@ public abstract class PanelView extends FrameLayout {
mStatusBar.onUnlockHintStarted();
}
public boolean isUnlockHintRunning() {
return mHintAnimationRunning;
}
/**
* Phase 1: Move everything upwards.
*/
@@ -1190,6 +1191,13 @@ public abstract class PanelView extends FrameLayout {
mBar.panelExpansionChanged(mExpandedFraction, mExpandedFraction > 0f
|| mPeekAnimator != null || mInstantExpanding || isPanelVisibleBecauseOfHeadsUp()
|| mTracking || mHeightAnimator != null);
if (mExpansionListener != null) {
mExpansionListener.accept(mExpandedFraction, mTracking);
}
}
public void setExpansionListener(BiConsumer<Float, Boolean> consumer) {
mExpansionListener = consumer;
}
protected abstract boolean isPanelVisibleBecauseOfHeadsUp();

View File

@@ -35,7 +35,6 @@ import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
@@ -97,14 +96,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
* The most common scrim, the one under the keyguard.
*/
protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = GRADIENT_SCRIM_ALPHA;
/**
* We fade out the bottom scrim when the bouncer is visible.
*/
protected static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f;
/**
* Opacity of the scrim behind the bouncer (the one doing actual background protection.)
*/
protected static final float SCRIM_IN_FRONT_ALPHA_LOCKED = GRADIENT_SCRIM_ALPHA_BUSY;
static final int TAG_KEY_ANIM = R.id.scrim;
private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
@@ -130,7 +121,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
protected float mScrimBehindAlpha;
protected float mScrimBehindAlphaResValue;
protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
protected float mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING;
// Assuming the shade is expanded during initialization
private float mExpansionFraction = 1f;
@@ -177,6 +167,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
mScrimVisibleListener = scrimVisibleListener;
mContext = scrimBehind.getContext();
mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
mLightBarController = lightBarController;
mScrimBehindAlphaResValue = mContext.getResources().getFloat(R.dimen.scrim_behind_alpha);
@@ -300,10 +291,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
return mState;
}
protected void setScrimBehindValues(float scrimBehindAlphaKeyguard,
float scrimBehindAlphaUnlocking) {
protected void setScrimBehindValues(float scrimBehindAlphaKeyguard) {
mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
mScrimBehindAlphaUnlocking = scrimBehindAlphaUnlocking;
ScrimState[] states = ScrimState.values();
for (int i = 0; i < states.length; i++) {
states[i].setScrimBehindAlphaKeyguard(scrimBehindAlphaKeyguard);
@@ -404,9 +393,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
float interpolatedFract = getInterpolatedFraction();
float alphaBehind = mState.getBehindAlpha(mNotificationDensity);
if (mDarkenWhileDragging) {
mCurrentBehindAlpha = MathUtils.lerp(mScrimBehindAlphaUnlocking, alphaBehind,
mCurrentBehindAlpha = MathUtils.lerp(GRADIENT_SCRIM_ALPHA_BUSY, alphaBehind,
interpolatedFract);
mCurrentInFrontAlpha = (1f - interpolatedFract) * SCRIM_IN_FRONT_ALPHA_LOCKED;
mCurrentInFrontAlpha = 0;
} else {
mCurrentBehindAlpha = MathUtils.lerp(0 /* start */, alphaBehind,
interpolatedFract);
@@ -455,7 +444,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
if (mNeedsDrawableColorUpdate) {
mNeedsDrawableColorUpdate = false;
final GradientColors currentScrimColors;
if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER) {
if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER_OCCLUDED
|| mState == ScrimState.BOUNCER) {
// Always animate color changes if we're seeing the keyguard
mScrimInFront.setColors(mLockColors, true /* animated */);
mScrimBehind.setColors(mLockColors, true /* animated */);

View File

@@ -66,20 +66,31 @@ public enum ScrimState {
},
/**
* Showing password challenge.
* Showing password challenge on the keyguard.
*/
BOUNCER(1) {
@Override
public void prepare(ScrimState previousState) {
mCurrentBehindAlpha = ScrimController.SCRIM_BEHIND_ALPHA_UNLOCKING;
mCurrentInFrontAlpha = ScrimController.SCRIM_IN_FRONT_ALPHA_LOCKED;
mCurrentBehindAlpha = ScrimController.GRADIENT_SCRIM_ALPHA_BUSY;
mCurrentInFrontAlpha = 0f;
}
},
/**
* Showing password challenge on top of a FLAG_SHOW_WHEN_LOCKED activity.
*/
BOUNCER_OCCLUDED(2) {
@Override
public void prepare(ScrimState previousState) {
mCurrentBehindAlpha = 0;
mCurrentInFrontAlpha = ScrimController.GRADIENT_SCRIM_ALPHA_BUSY;
}
},
/**
* Changing screen brightness from quick settings.
*/
BRIGHTNESS_MIRROR(2) {
BRIGHTNESS_MIRROR(3) {
@Override
public void prepare(ScrimState previousState) {
mCurrentBehindAlpha = 0;
@@ -90,7 +101,7 @@ public enum ScrimState {
/**
* Always on display or screen off.
*/
AOD(3) {
AOD(4) {
@Override
public void prepare(ScrimState previousState) {
final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
@@ -110,7 +121,7 @@ public enum ScrimState {
/**
* When phone wakes up because you received a notification.
*/
PULSING(4) {
PULSING(5) {
@Override
public void prepare(ScrimState previousState) {
mCurrentInFrontAlpha = 0;
@@ -125,7 +136,7 @@ public enum ScrimState {
/**
* Unlocked on top of an app (launcher or any other activity.)
*/
UNLOCKED(5) {
UNLOCKED(6) {
@Override
public void prepare(ScrimState previousState) {
mCurrentBehindAlpha = 0;

View File

@@ -1296,7 +1296,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mDozeScrimController, keyguardViewMediator,
mScrimController, this, UnlockMethodCache.getInstance(mContext));
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
getBouncerContainer(), mFingerprintUnlockController);
getBouncerContainer(), mNotificationPanel, mFingerprintUnlockController);
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
@@ -4619,7 +4619,8 @@ public class StatusBar extends SystemUI implements DemoMode,
== FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
if (mBouncerShowing) {
mScrimController.transitionTo(ScrimState.BOUNCER);
mScrimController.transitionTo(
mIsOccluded ? ScrimState.BOUNCER_OCCLUDED : ScrimState.BOUNCER);
} else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
} else if (mBrightnessMirrorVisible) {

View File

@@ -31,10 +31,10 @@ import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dependency;
@@ -75,6 +75,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
protected LockPatternUtils mLockPatternUtils;
protected ViewMediatorCallback mViewMediatorCallback;
protected StatusBar mStatusBar;
private NotificationPanelView mNotificationPanelView;
private FingerprintUnlockController mFingerprintUnlockController;
private ViewGroup mContainer;
@@ -88,6 +89,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
protected boolean mFirstUpdate = true;
protected boolean mLastShowing;
protected boolean mLastOccluded;
private boolean mLastTracking;
private boolean mLastBouncerShowing;
private boolean mLastBouncerDismissible;
protected boolean mLastRemoteInputActive;
@@ -124,6 +126,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
public void registerStatusBar(StatusBar statusBar,
ViewGroup container,
NotificationPanelView notificationPanelView,
FingerprintUnlockController fingerprintUnlockController,
DismissCallbackRegistry dismissCallbackRegistry) {
mStatusBar = statusBar;
@@ -131,6 +134,32 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mFingerprintUnlockController = fingerprintUnlockController;
mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry);
mNotificationPanelView = notificationPanelView;
notificationPanelView.setExpansionListener(this::onPanelExpansionChanged);
}
private void onPanelExpansionChanged(float expansion, boolean tracking) {
// We don't want to translate the bounce when the keyguard is occluded, because we're in
// a FLAG_SHOW_WHEN_LOCKED activity and need to conserve the original animation.
// We also don't want to show the bouncer when the user quickly taps on the display.
final boolean noLongerTracking = mLastTracking != tracking && !tracking;
if (mOccluded || mNotificationPanelView.isUnlockHintRunning()) {
mBouncer.setExpansion(0);
} else if (mShowing && mStatusBar.isKeyguardCurrentlySecure() && !mDozing) {
mBouncer.setExpansion(expansion);
if (expansion == 1) {
mBouncer.onFullyHidden();
updateStates();
} else if (!mBouncer.isShowing()) {
mBouncer.show(true /* resetSecuritySelection */, false /* notifyFalsing */);
} else if (noLongerTracking) {
// Notify that falsing manager should stop its session when user stops touching,
// even before the animation ends, to guarantee that we're not recording sensitive
// data.
mBouncer.onFullyShown();
}
}
mLastTracking = tracking;
}
/**

View File

@@ -170,12 +170,22 @@ public class ScrimControllerTest extends SysuiTestCase {
}
@Test
public void transitionToBouncer() {
public void transitionToKeyguardBouncer() {
mScrimController.transitionTo(ScrimState.BOUNCER);
mScrimController.finishAnimationsImmediately();
// Front scrim should be transparent
// Back scrim should be visible without tint
assertScrimVisibility(VISIBILITY_SEMI_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
assertScrimTint(mScrimBehind, false /* tinted */);
}
@Test
public void transitionToBouncer() {
mScrimController.transitionTo(ScrimState.BOUNCER_OCCLUDED);
mScrimController.finishAnimationsImmediately();
// Front scrim should be transparent
// Back scrim should be visible without tint
assertScrimVisibility(VISIBILITY_SEMI_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT);
assertScrimTint(mScrimBehind, false /* tinted */);
}