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:
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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 */);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -33,6 +33,7 @@ public class DirectionEvaluator {
|
||||
}
|
||||
break;
|
||||
case Classifier.UNLOCK:
|
||||
case Classifier.BOUNCER_UNLOCK:
|
||||
if (!vertical || yDiff >= 0.0) {
|
||||
return falsingEvaluation;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 */);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 */);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user