Merge changes from topic "b150393918-lock-icon" into rvc-dev
* changes: Cache icon drawables. Remove injection from LockIcon.
This commit is contained in:
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.phone;
|
package com.android.systemui.statusbar.phone;
|
||||||
|
|
||||||
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
|
|
||||||
|
|
||||||
import android.annotation.IntDef;
|
import android.annotation.IntDef;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
@@ -30,241 +28,98 @@ import android.os.Trace;
|
|||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.ViewTreeObserver;
|
import android.util.SparseArray;
|
||||||
import android.view.accessibility.AccessibilityNodeInfo;
|
import android.view.ViewTreeObserver.OnPreDrawListener;
|
||||||
|
|
||||||
import com.android.internal.graphics.ColorUtils;
|
import com.android.internal.graphics.ColorUtils;
|
||||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
|
||||||
import com.android.systemui.Dependency;
|
|
||||||
import com.android.systemui.Interpolators;
|
import com.android.systemui.Interpolators;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.statusbar.KeyguardAffordanceView;
|
import com.android.systemui.statusbar.KeyguardAffordanceView;
|
||||||
import com.android.systemui.statusbar.StatusBarState;
|
|
||||||
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
|
|
||||||
import com.android.systemui.statusbar.phone.ScrimController.ScrimVisibility;
|
|
||||||
import com.android.systemui.statusbar.policy.AccessibilityController;
|
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Named;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the different states and animations of the unlock icon.
|
* Manages the different states and animations of the unlock icon.
|
||||||
*/
|
*/
|
||||||
public class LockIcon extends KeyguardAffordanceView implements
|
public class LockIcon extends KeyguardAffordanceView {
|
||||||
ViewTreeObserver.OnPreDrawListener {
|
|
||||||
|
|
||||||
private static final int STATE_LOCKED = 0;
|
static final int STATE_LOCKED = 0;
|
||||||
private static final int STATE_LOCK_OPEN = 1;
|
static final int STATE_LOCK_OPEN = 1;
|
||||||
private static final int STATE_SCANNING_FACE = 2;
|
static final int STATE_SCANNING_FACE = 2;
|
||||||
private static final int STATE_BIOMETRICS_ERROR = 3;
|
static final int STATE_BIOMETRICS_ERROR = 3;
|
||||||
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
private float mDozeAmount;
|
||||||
private final AccessibilityController mAccessibilityController;
|
private int mIconColor;
|
||||||
private final KeyguardStateController mKeyguardStateController;
|
private StateProvider mStateProvider;
|
||||||
private final KeyguardBypassController mBypassController;
|
private int mOldState;
|
||||||
private final NotificationWakeUpCoordinator mWakeUpCoordinator;
|
|
||||||
private final HeadsUpManagerPhone mHeadsUpManager;
|
|
||||||
|
|
||||||
private int mLastState = 0;
|
|
||||||
private boolean mForceUpdate;
|
|
||||||
private boolean mTransientBiometricsError;
|
|
||||||
private boolean mIsFaceUnlockState;
|
|
||||||
private boolean mSimLocked;
|
|
||||||
private int mDensity;
|
|
||||||
private boolean mPulsing;
|
private boolean mPulsing;
|
||||||
private boolean mDozing;
|
private boolean mDozing;
|
||||||
private boolean mDocked;
|
|
||||||
private boolean mBlockUpdates;
|
|
||||||
private int mIconColor;
|
|
||||||
private float mDozeAmount;
|
|
||||||
private boolean mBouncerShowingScrimmed;
|
|
||||||
private boolean mWakeAndUnlockRunning;
|
|
||||||
private boolean mKeyguardShowing;
|
|
||||||
private boolean mShowingLaunchAffordance;
|
|
||||||
private boolean mKeyguardJustShown;
|
private boolean mKeyguardJustShown;
|
||||||
private boolean mUpdatePending;
|
private final SparseArray<Drawable> mDrawableCache = new SparseArray<>();
|
||||||
private boolean mBouncerPreHideAnimation;
|
|
||||||
private int mStatusBarState = StatusBarState.SHADE;
|
|
||||||
|
|
||||||
private final KeyguardStateController.Callback mKeyguardMonitorCallback =
|
private final OnPreDrawListener mOnPreDrawListener = new OnPreDrawListener() {
|
||||||
new KeyguardStateController.Callback() {
|
@Override
|
||||||
@Override
|
public boolean onPreDraw() {
|
||||||
public void onKeyguardShowingChanged() {
|
getViewTreeObserver().removeOnPreDrawListener(this);
|
||||||
boolean force = false;
|
|
||||||
boolean wasShowing = mKeyguardShowing;
|
|
||||||
mKeyguardShowing = mKeyguardStateController.isShowing();
|
|
||||||
if (!wasShowing && mKeyguardShowing && mBlockUpdates) {
|
|
||||||
mBlockUpdates = false;
|
|
||||||
force = true;
|
|
||||||
}
|
|
||||||
if (!wasShowing && mKeyguardShowing) {
|
|
||||||
mKeyguardJustShown = true;
|
|
||||||
}
|
|
||||||
update(force);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
int newState = mStateProvider.getState();
|
||||||
public void onKeyguardFadingAwayChanged() {
|
Drawable icon = getIcon(newState);
|
||||||
if (!mKeyguardStateController.isKeyguardFadingAway()) {
|
setImageDrawable(icon, false);
|
||||||
mBouncerPreHideAnimation = false;
|
|
||||||
if (mBlockUpdates) {
|
|
||||||
mBlockUpdates = false;
|
|
||||||
update(true /* force */);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (newState == STATE_SCANNING_FACE) {
|
||||||
public void onUnlockedChanged() {
|
announceForAccessibility(getResources().getString(
|
||||||
update();
|
R.string.accessibility_scanning_face));
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
@Inject
|
if (icon instanceof AnimatedVectorDrawable) {
|
||||||
public LockIcon(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
|
final AnimatedVectorDrawable animation = (AnimatedVectorDrawable) icon;
|
||||||
AccessibilityController accessibilityController,
|
animation.forceAnimationOnUI();
|
||||||
KeyguardBypassController bypassController,
|
animation.clearAnimationCallbacks();
|
||||||
NotificationWakeUpCoordinator wakeUpCoordinator,
|
animation.registerAnimationCallback(
|
||||||
KeyguardStateController keyguardStateController,
|
new Animatable2.AnimationCallback() {
|
||||||
HeadsUpManagerPhone headsUpManager) {
|
@Override
|
||||||
|
public void onAnimationEnd(Drawable drawable) {
|
||||||
|
if (getDrawable() == animation
|
||||||
|
&& newState == mStateProvider.getState()
|
||||||
|
&& newState == STATE_SCANNING_FACE) {
|
||||||
|
animation.start();
|
||||||
|
} else {
|
||||||
|
Trace.endAsyncSection("LockIcon#Animation", newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Trace.beginAsyncSection("LockIcon#Animation", newState);
|
||||||
|
animation.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public LockIcon(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
mContext = context;
|
|
||||||
mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
|
|
||||||
mAccessibilityController = accessibilityController;
|
|
||||||
mBypassController = bypassController;
|
|
||||||
mWakeUpCoordinator = wakeUpCoordinator;
|
|
||||||
mKeyguardStateController = keyguardStateController;
|
|
||||||
mHeadsUpManager = headsUpManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void setStateProvider(StateProvider stateProvider) {
|
||||||
protected void onAttachedToWindow() {
|
mStateProvider = stateProvider;
|
||||||
super.onAttachedToWindow();
|
|
||||||
mKeyguardStateController.addCallback(mKeyguardMonitorCallback);
|
|
||||||
mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDetachedFromWindow() {
|
|
||||||
super.onDetachedFromWindow();
|
|
||||||
mKeyguardStateController.removeCallback(mKeyguardMonitorCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If we're currently presenting an authentication error message.
|
|
||||||
*/
|
|
||||||
public void setTransientBiometricsError(boolean transientBiometricsError) {
|
|
||||||
mTransientBiometricsError = transientBiometricsError;
|
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onConfigurationChanged(Configuration newConfig) {
|
protected void onConfigurationChanged(Configuration newConfig) {
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
final int density = newConfig.densityDpi;
|
mDrawableCache.clear();
|
||||||
if (density != mDensity) {
|
|
||||||
mDensity = density;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update() {
|
|
||||||
update(false /* force */);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update(boolean force) {
|
|
||||||
if (force) {
|
|
||||||
mForceUpdate = true;
|
|
||||||
}
|
|
||||||
if (!mUpdatePending) {
|
|
||||||
mUpdatePending = true;
|
|
||||||
getViewTreeObserver().addOnPreDrawListener(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPreDraw() {
|
|
||||||
mUpdatePending = false;
|
|
||||||
getViewTreeObserver().removeOnPreDrawListener(this);
|
|
||||||
|
|
||||||
int state = getState();
|
|
||||||
int lastState = mLastState;
|
|
||||||
boolean keyguardJustShown = mKeyguardJustShown;
|
|
||||||
mIsFaceUnlockState = state == STATE_SCANNING_FACE;
|
|
||||||
mLastState = state;
|
|
||||||
mKeyguardJustShown = false;
|
|
||||||
|
|
||||||
boolean shouldUpdate = lastState != state || mForceUpdate;
|
|
||||||
if (mBlockUpdates && canBlockUpdates()) {
|
|
||||||
shouldUpdate = false;
|
|
||||||
}
|
|
||||||
if (shouldUpdate) {
|
|
||||||
mForceUpdate = false;
|
|
||||||
@LockAnimIndex final int lockAnimIndex = getAnimationIndexForTransition(lastState,
|
|
||||||
state, mPulsing, mDozing, keyguardJustShown);
|
|
||||||
boolean isAnim = lockAnimIndex != -1;
|
|
||||||
int iconRes = isAnim ? getThemedAnimationResId(lockAnimIndex) : getIconForState(state);
|
|
||||||
|
|
||||||
Drawable icon = mContext.getDrawable(iconRes);
|
|
||||||
final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
|
|
||||||
? (AnimatedVectorDrawable) icon
|
|
||||||
: null;
|
|
||||||
setImageDrawable(icon, false);
|
|
||||||
if (mIsFaceUnlockState) {
|
|
||||||
announceForAccessibility(getContext().getString(
|
|
||||||
R.string.accessibility_scanning_face));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (animation != null && isAnim) {
|
|
||||||
animation.forceAnimationOnUI();
|
|
||||||
animation.clearAnimationCallbacks();
|
|
||||||
animation.registerAnimationCallback(new Animatable2.AnimationCallback() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Drawable drawable) {
|
|
||||||
if (getDrawable() == animation && state == getState()
|
|
||||||
&& doesAnimationLoop(lockAnimIndex)) {
|
|
||||||
animation.start();
|
|
||||||
} else {
|
|
||||||
Trace.endAsyncSection("LockIcon#Animation", state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Trace.beginAsyncSection("LockIcon#Animation", state);
|
|
||||||
animation.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateDarkTint();
|
|
||||||
|
|
||||||
updateIconVisibility();
|
|
||||||
updateClickability();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the icon visibility
|
* Update the icon visibility
|
||||||
* @return true if the visibility changed
|
* @return true if the visibility changed
|
||||||
*/
|
*/
|
||||||
boolean updateIconVisibility() {
|
boolean updateIconVisibility(boolean visible) {
|
||||||
boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
|
boolean wasVisible = getVisibility() == VISIBLE;
|
||||||
boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
|
if (visible != wasVisible) {
|
||||||
|| mShowingLaunchAffordance;
|
setVisibility(visible ? VISIBLE : INVISIBLE);
|
||||||
if (mBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
|
|
||||||
if ((mHeadsUpManager.isHeadsUpGoingAway() || mHeadsUpManager.hasPinnedHeadsUp()
|
|
||||||
|| mStatusBarState == StatusBarState.KEYGUARD)
|
|
||||||
&& !mWakeUpCoordinator.getNotificationsFullyHidden()) {
|
|
||||||
invisible = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
boolean wasInvisible = getVisibility() == INVISIBLE;
|
|
||||||
if (invisible != wasInvisible) {
|
|
||||||
setVisibility(invisible ? INVISIBLE : VISIBLE);
|
|
||||||
animate().cancel();
|
animate().cancel();
|
||||||
if (!invisible) {
|
if (visible) {
|
||||||
setScaleX(0);
|
setScaleX(0);
|
||||||
setScaleY(0);
|
setScaleY(0);
|
||||||
animate()
|
animate()
|
||||||
@@ -280,49 +135,47 @@ public class LockIcon extends KeyguardAffordanceView implements
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean canBlockUpdates() {
|
void update(int oldState, boolean pulsing, boolean dozing, boolean keyguardJustShown) {
|
||||||
return mKeyguardShowing || mKeyguardStateController.isKeyguardFadingAway();
|
mOldState = oldState;
|
||||||
|
mPulsing = pulsing;
|
||||||
|
mDozing = dozing;
|
||||||
|
mKeyguardJustShown = keyguardJustShown;
|
||||||
|
|
||||||
|
getViewTreeObserver().addOnPreDrawListener(mOnPreDrawListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateClickability() {
|
void setDozeAmount(float dozeAmount) {
|
||||||
if (mAccessibilityController == null) {
|
mDozeAmount = dozeAmount;
|
||||||
return;
|
updateDarkTint();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onThemeChange(int iconColor) {
|
||||||
|
mDrawableCache.clear();
|
||||||
|
mIconColor = iconColor;
|
||||||
|
updateDarkTint();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDarkTint() {
|
||||||
|
int color = ColorUtils.blendARGB(mIconColor, Color.WHITE, mDozeAmount);
|
||||||
|
setImageTintList(ColorStateList.valueOf(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Drawable getIcon(int newState) {
|
||||||
|
@LockAnimIndex final int lockAnimIndex =
|
||||||
|
getAnimationIndexForTransition(mOldState, newState, mPulsing, mDozing,
|
||||||
|
mKeyguardJustShown);
|
||||||
|
|
||||||
|
boolean isAnim = lockAnimIndex != -1;
|
||||||
|
int iconRes = isAnim ? getThemedAnimationResId(lockAnimIndex) : getIconForState(newState);
|
||||||
|
|
||||||
|
if (!mDrawableCache.contains(iconRes)) {
|
||||||
|
mDrawableCache.put(iconRes, getResources().getDrawable(iconRes));
|
||||||
}
|
}
|
||||||
boolean canLock = mKeyguardStateController.isMethodSecure()
|
|
||||||
&& mKeyguardStateController.canDismissLockScreen();
|
return mDrawableCache.get(iconRes);
|
||||||
boolean clickToUnlock = mAccessibilityController.isAccessibilityEnabled();
|
|
||||||
setClickable(clickToUnlock);
|
|
||||||
setLongClickable(canLock && !clickToUnlock);
|
|
||||||
setFocusable(mAccessibilityController.isAccessibilityEnabled());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
static int getIconForState(int state) {
|
||||||
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
|
||||||
super.onInitializeAccessibilityNodeInfo(info);
|
|
||||||
boolean fingerprintRunning = mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
|
|
||||||
// Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
|
|
||||||
// as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
|
|
||||||
// pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
|
|
||||||
// check of whether non-strong biometric is allowed
|
|
||||||
boolean unlockingAllowed = mKeyguardUpdateMonitor
|
|
||||||
.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */);
|
|
||||||
if (fingerprintRunning && unlockingAllowed) {
|
|
||||||
AccessibilityNodeInfo.AccessibilityAction unlock
|
|
||||||
= new AccessibilityNodeInfo.AccessibilityAction(
|
|
||||||
AccessibilityNodeInfo.ACTION_CLICK,
|
|
||||||
getContext().getString(R.string.accessibility_unlock_without_fingerprint));
|
|
||||||
info.addAction(unlock);
|
|
||||||
info.setHintText(getContext().getString(
|
|
||||||
R.string.accessibility_waiting_for_fingerprint));
|
|
||||||
} else if (mIsFaceUnlockState) {
|
|
||||||
//Avoid 'button' to be spoken for scanning face
|
|
||||||
info.setClassName(LockIcon.class.getName());
|
|
||||||
info.setContentDescription(getContext().getString(
|
|
||||||
R.string.accessibility_scanning_face));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getIconForState(int state) {
|
|
||||||
int iconRes;
|
int iconRes;
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case STATE_LOCKED:
|
case STATE_LOCKED:
|
||||||
@@ -343,11 +196,7 @@ public class LockIcon extends KeyguardAffordanceView implements
|
|||||||
return iconRes;
|
return iconRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean doesAnimationLoop(@LockAnimIndex int lockAnimIndex) {
|
static int getAnimationIndexForTransition(int oldState, int newState, boolean pulsing,
|
||||||
return lockAnimIndex == SCANNING;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getAnimationIndexForTransition(int oldState, int newState, boolean pulsing,
|
|
||||||
boolean dozing, boolean keyguardJustShown) {
|
boolean dozing, boolean keyguardJustShown) {
|
||||||
|
|
||||||
// Never animate when screen is off
|
// Never animate when screen is off
|
||||||
@@ -367,42 +216,10 @@ public class LockIcon extends KeyguardAffordanceView implements
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBouncerShowingScrimmed(boolean bouncerShowing) {
|
|
||||||
mBouncerShowingScrimmed = bouncerShowing;
|
|
||||||
if (mBypassController.getBypassEnabled()) {
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Animate padlock opening when bouncer challenge is solved.
|
|
||||||
*/
|
|
||||||
public void onBouncerPreHideAnimation() {
|
|
||||||
mBouncerPreHideAnimation = true;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setIconColor(int iconColor) {
|
|
||||||
mIconColor = iconColor;
|
|
||||||
updateDarkTint();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSimLocked(boolean simLocked) {
|
|
||||||
mSimLocked = simLocked;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set if the device is docked. */
|
|
||||||
public void setDocked(boolean docked) {
|
|
||||||
if (mDocked != docked) {
|
|
||||||
mDocked = docked;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef({ERROR, UNLOCK, LOCK, SCANNING})
|
@IntDef({ERROR, UNLOCK, LOCK, SCANNING})
|
||||||
@interface LockAnimIndex {}
|
@interface LockAnimIndex {}
|
||||||
private static final int ERROR = 0, UNLOCK = 1, LOCK = 2, SCANNING = 3;
|
static final int ERROR = 0, UNLOCK = 1, LOCK = 2, SCANNING = 3;
|
||||||
private static final int[][] LOCK_ANIM_RES_IDS = new int[][] {
|
private static final int[][] LOCK_ANIM_RES_IDS = new int[][] {
|
||||||
{
|
{
|
||||||
R.anim.lock_to_error,
|
R.anim.lock_to_error,
|
||||||
@@ -433,7 +250,7 @@ public class LockIcon extends KeyguardAffordanceView implements
|
|||||||
private int getThemedAnimationResId(@LockAnimIndex int lockAnimIndex) {
|
private int getThemedAnimationResId(@LockAnimIndex int lockAnimIndex) {
|
||||||
final String setting = TextUtils.emptyIfNull(
|
final String setting = TextUtils.emptyIfNull(
|
||||||
Settings.Secure.getString(getContext().getContentResolver(),
|
Settings.Secure.getString(getContext().getContentResolver(),
|
||||||
Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES));
|
Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES));
|
||||||
if (setting.contains("com.android.theme.icon_pack.circular.android")) {
|
if (setting.contains("com.android.theme.icon_pack.circular.android")) {
|
||||||
return LOCK_ANIM_RES_IDS[1][lockAnimIndex];
|
return LOCK_ANIM_RES_IDS[1][lockAnimIndex];
|
||||||
} else if (setting.contains("com.android.theme.icon_pack.filled.android")) {
|
} else if (setting.contains("com.android.theme.icon_pack.filled.android")) {
|
||||||
@@ -444,83 +261,8 @@ public class LockIcon extends KeyguardAffordanceView implements
|
|||||||
return LOCK_ANIM_RES_IDS[0][lockAnimIndex];
|
return LOCK_ANIM_RES_IDS[0][lockAnimIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getState() {
|
interface StateProvider {
|
||||||
KeyguardUpdateMonitor updateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
|
int getState();
|
||||||
if ((mKeyguardStateController.canDismissLockScreen() || !mKeyguardShowing
|
|
||||||
|| mKeyguardStateController.isKeyguardGoingAway()) && !mSimLocked) {
|
|
||||||
return STATE_LOCK_OPEN;
|
|
||||||
} else if (mTransientBiometricsError) {
|
|
||||||
return STATE_BIOMETRICS_ERROR;
|
|
||||||
} else if (updateMonitor.isFaceDetectionRunning() && !mPulsing) {
|
|
||||||
return STATE_SCANNING_FACE;
|
|
||||||
} else {
|
|
||||||
return STATE_LOCKED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* When keyguard is in pulsing (AOD2) state.
|
|
||||||
* @param pulsing {@code true} when pulsing.
|
|
||||||
*/
|
|
||||||
public void setPulsing(boolean pulsing) {
|
|
||||||
mPulsing = pulsing;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateDarkTint() {
|
|
||||||
int color = ColorUtils.blendARGB(mIconColor, Color.WHITE, mDozeAmount);
|
|
||||||
setImageTintList(ColorStateList.valueOf(color));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We need to hide the lock whenever there's a fingerprint unlock, otherwise you'll see the
|
|
||||||
* icon on top of the black front scrim.
|
|
||||||
* @param wakeAndUnlock are we wake and unlocking
|
|
||||||
* @param isUnlock are we currently unlocking
|
|
||||||
*/
|
|
||||||
public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock) {
|
|
||||||
if (wakeAndUnlock) {
|
|
||||||
mWakeAndUnlockRunning = true;
|
|
||||||
}
|
|
||||||
if (isUnlock && mBypassController.getBypassEnabled() && canBlockUpdates()) {
|
|
||||||
// We don't want the icon to change while we are unlocking
|
|
||||||
mBlockUpdates = true;
|
|
||||||
}
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When we're launching an affordance, like double pressing power to open camera.
|
|
||||||
*/
|
|
||||||
public void onShowingLaunchAffordanceChanged(boolean showing) {
|
|
||||||
mShowingLaunchAffordance = showing;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called whenever the scrims become opaque, transparent or semi-transparent.
|
|
||||||
*/
|
|
||||||
public void onScrimVisibilityChanged(@ScrimVisibility int scrimsVisible) {
|
|
||||||
if (mWakeAndUnlockRunning
|
|
||||||
&& scrimsVisible == ScrimController.TRANSPARENT) {
|
|
||||||
mWakeAndUnlockRunning = false;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDozing(boolean dozing) {
|
|
||||||
mDozing = dozing;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDozeAmount(float dozeAmount) {
|
|
||||||
mDozeAmount = dozeAmount;
|
|
||||||
updateDarkTint();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set the StatusBarState. */
|
|
||||||
public void setStatusBarState(int statusBarState) {
|
|
||||||
mStatusBarState = statusBarState;
|
|
||||||
updateIconVisibility();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,19 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.phone;
|
package com.android.systemui.statusbar.phone;
|
||||||
|
|
||||||
|
import static com.android.systemui.statusbar.phone.LockIcon.STATE_BIOMETRICS_ERROR;
|
||||||
|
import static com.android.systemui.statusbar.phone.LockIcon.STATE_LOCKED;
|
||||||
|
import static com.android.systemui.statusbar.phone.LockIcon.STATE_LOCK_OPEN;
|
||||||
|
import static com.android.systemui.statusbar.phone.LockIcon.STATE_SCANNING_FACE;
|
||||||
|
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.hardware.biometrics.BiometricSourceType;
|
import android.hardware.biometrics.BiometricSourceType;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
@@ -29,15 +37,18 @@ import com.android.internal.widget.LockPatternUtils;
|
|||||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||||
import com.android.keyguard.KeyguardUpdateMonitorCallback;
|
import com.android.keyguard.KeyguardUpdateMonitorCallback;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
import com.android.systemui.dock.DockManager;
|
import com.android.systemui.dock.DockManager;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
import com.android.systemui.statusbar.CommandQueue;
|
import com.android.systemui.statusbar.CommandQueue;
|
||||||
import com.android.systemui.statusbar.KeyguardIndicationController;
|
import com.android.systemui.statusbar.KeyguardIndicationController;
|
||||||
|
import com.android.systemui.statusbar.StatusBarState;
|
||||||
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
|
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
|
||||||
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator.WakeUpListener;
|
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator.WakeUpListener;
|
||||||
import com.android.systemui.statusbar.policy.AccessibilityController;
|
import com.android.systemui.statusbar.policy.AccessibilityController;
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
|
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
|
||||||
|
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@@ -59,6 +70,21 @@ public class LockscreenLockIconController {
|
|||||||
private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
|
private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
|
||||||
private final KeyguardBypassController mKeyguardBypassController;
|
private final KeyguardBypassController mKeyguardBypassController;
|
||||||
private final Optional<DockManager> mDockManager;
|
private final Optional<DockManager> mDockManager;
|
||||||
|
private final KeyguardStateController mKeyguardStateController;
|
||||||
|
private final Resources mResources;
|
||||||
|
private final HeadsUpManagerPhone mHeadsUpManagerPhone;
|
||||||
|
private boolean mKeyguardShowing;
|
||||||
|
private boolean mKeyguardJustShown;
|
||||||
|
private boolean mBlockUpdates;
|
||||||
|
private boolean mPulsing;
|
||||||
|
private boolean mDozing;
|
||||||
|
private boolean mSimLocked;
|
||||||
|
private boolean mTransientBiometricsError;
|
||||||
|
private boolean mDocked;
|
||||||
|
private boolean mWakeAndUnlockRunning;
|
||||||
|
private boolean mShowingLaunchAffordance;
|
||||||
|
private boolean mBouncerShowingScrimmed;
|
||||||
|
private int mStatusBarState = StatusBarState.SHADE;
|
||||||
private LockIcon mLockIcon;
|
private LockIcon mLockIcon;
|
||||||
|
|
||||||
private View.OnAttachStateChangeListener mOnAttachStateChangeListener =
|
private View.OnAttachStateChangeListener mOnAttachStateChangeListener =
|
||||||
@@ -69,10 +95,13 @@ public class LockscreenLockIconController {
|
|||||||
mConfigurationController.addCallback(mConfigurationListener);
|
mConfigurationController.addCallback(mConfigurationListener);
|
||||||
mNotificationWakeUpCoordinator.addListener(mWakeUpListener);
|
mNotificationWakeUpCoordinator.addListener(mWakeUpListener);
|
||||||
mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
|
mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
|
||||||
|
mKeyguardStateController.addCallback(mKeyguardMonitorCallback);
|
||||||
|
|
||||||
mDockManager.ifPresent(dockManager -> dockManager.addListener(mDockEventListener));
|
mDockManager.ifPresent(dockManager -> dockManager.addListener(mDockEventListener));
|
||||||
|
|
||||||
|
mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
|
||||||
mConfigurationListener.onThemeChanged();
|
mConfigurationListener.onThemeChanged();
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -81,7 +110,7 @@ public class LockscreenLockIconController {
|
|||||||
mConfigurationController.removeCallback(mConfigurationListener);
|
mConfigurationController.removeCallback(mConfigurationListener);
|
||||||
mNotificationWakeUpCoordinator.removeListener(mWakeUpListener);
|
mNotificationWakeUpCoordinator.removeListener(mWakeUpListener);
|
||||||
mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
|
mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
|
||||||
|
mKeyguardStateController.removeCallback(mKeyguardMonitorCallback);
|
||||||
|
|
||||||
mDockManager.ifPresent(dockManager -> dockManager.removeListener(mDockEventListener));
|
mDockManager.ifPresent(dockManager -> dockManager.removeListener(mDockEventListener));
|
||||||
}
|
}
|
||||||
@@ -91,32 +120,44 @@ public class LockscreenLockIconController {
|
|||||||
new StatusBarStateController.StateListener() {
|
new StatusBarStateController.StateListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onDozingChanged(boolean isDozing) {
|
public void onDozingChanged(boolean isDozing) {
|
||||||
mLockIcon.setDozing(isDozing);
|
setDozing(isDozing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDozeAmountChanged(float linear, float eased) {
|
public void onDozeAmountChanged(float linear, float eased) {
|
||||||
mLockIcon.setDozeAmount(eased);
|
if (mLockIcon != null) {
|
||||||
|
mLockIcon.setDozeAmount(eased);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStateChanged(int newState) {
|
public void onStateChanged(int newState) {
|
||||||
mLockIcon.setStatusBarState(newState);
|
setStatusBarState(newState);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
|
private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
|
||||||
|
private int mDensity;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onThemeChanged() {
|
public void onThemeChanged() {
|
||||||
|
if (mLockIcon == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TypedArray typedArray = mLockIcon.getContext().getTheme().obtainStyledAttributes(
|
TypedArray typedArray = mLockIcon.getContext().getTheme().obtainStyledAttributes(
|
||||||
null, new int[]{ R.attr.wallpaperTextColor }, 0, 0);
|
null, new int[]{ R.attr.wallpaperTextColor }, 0, 0);
|
||||||
int iconColor = typedArray.getColor(0, Color.WHITE);
|
int iconColor = typedArray.getColor(0, Color.WHITE);
|
||||||
typedArray.recycle();
|
typedArray.recycle();
|
||||||
mLockIcon.setIconColor(iconColor);
|
mLockIcon.onThemeChange(iconColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDensityOrFontScaleChanged() {
|
public void onDensityOrFontScaleChanged() {
|
||||||
|
if (mLockIcon == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ViewGroup.LayoutParams lp = mLockIcon.getLayoutParams();
|
ViewGroup.LayoutParams lp = mLockIcon.getLayoutParams();
|
||||||
if (lp == null) {
|
if (lp == null) {
|
||||||
return;
|
return;
|
||||||
@@ -125,24 +166,41 @@ public class LockscreenLockIconController {
|
|||||||
lp.height = mLockIcon.getResources().getDimensionPixelSize(
|
lp.height = mLockIcon.getResources().getDimensionPixelSize(
|
||||||
R.dimen.keyguard_lock_height);
|
R.dimen.keyguard_lock_height);
|
||||||
mLockIcon.setLayoutParams(lp);
|
mLockIcon.setLayoutParams(lp);
|
||||||
mLockIcon.update(true /* force */);
|
update(true /* force */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLocaleListChanged() {
|
public void onLocaleListChanged() {
|
||||||
|
if (mLockIcon == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mLockIcon.setContentDescription(
|
mLockIcon.setContentDescription(
|
||||||
mLockIcon.getResources().getText(R.string.accessibility_unlock_button));
|
mLockIcon.getResources().getText(R.string.accessibility_unlock_button));
|
||||||
mLockIcon.update(true /* force */);
|
update(true /* force */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConfigChanged(Configuration newConfig) {
|
||||||
|
final int density = newConfig.densityDpi;
|
||||||
|
if (density != mDensity) {
|
||||||
|
mDensity = density;
|
||||||
|
update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final WakeUpListener mWakeUpListener = new WakeUpListener() {
|
private final WakeUpListener mWakeUpListener = new WakeUpListener() {
|
||||||
|
@Override
|
||||||
|
public void onPulseExpansionChanged(boolean expandingChanged) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFullyHiddenChanged(boolean isFullyHidden) {
|
public void onFullyHiddenChanged(boolean isFullyHidden) {
|
||||||
if (mKeyguardBypassController.getBypassEnabled()) {
|
if (mKeyguardBypassController.getBypassEnabled()) {
|
||||||
boolean changed = mLockIcon.updateIconVisibility();
|
boolean changed = updateIconVisibility();
|
||||||
if (changed) {
|
if (changed) {
|
||||||
mLockIcon.update();
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,30 +210,103 @@ public class LockscreenLockIconController {
|
|||||||
new KeyguardUpdateMonitorCallback() {
|
new KeyguardUpdateMonitorCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onSimStateChanged(int subId, int slotId, int simState) {
|
public void onSimStateChanged(int subId, int slotId, int simState) {
|
||||||
mLockIcon.setSimLocked(mKeyguardUpdateMonitor.isSimPinSecure());
|
mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
|
||||||
mLockIcon.update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onKeyguardVisibilityChanged(boolean showing) {
|
public void onKeyguardVisibilityChanged(boolean showing) {
|
||||||
mLockIcon.update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBiometricRunningStateChanged(boolean running,
|
public void onBiometricRunningStateChanged(boolean running,
|
||||||
BiometricSourceType biometricSourceType) {
|
BiometricSourceType biometricSourceType) {
|
||||||
mLockIcon.update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStrongAuthStateChanged(int userId) {
|
public void onStrongAuthStateChanged(int userId) {
|
||||||
mLockIcon.update();
|
update();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final DockManager.DockEventListener mDockEventListener =
|
private final DockManager.DockEventListener mDockEventListener =
|
||||||
event -> mLockIcon.setDocked(event == DockManager.STATE_DOCKED
|
event -> {
|
||||||
|| event == DockManager.STATE_DOCKED_HIDE);
|
boolean docked =
|
||||||
|
event == DockManager.STATE_DOCKED || event == DockManager.STATE_DOCKED_HIDE;
|
||||||
|
if (docked != mDocked) {
|
||||||
|
mDocked = docked;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final KeyguardStateController.Callback mKeyguardMonitorCallback =
|
||||||
|
new KeyguardStateController.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onKeyguardShowingChanged() {
|
||||||
|
boolean force = false;
|
||||||
|
boolean wasShowing = mKeyguardShowing;
|
||||||
|
mKeyguardShowing = mKeyguardStateController.isShowing();
|
||||||
|
if (!wasShowing && mKeyguardShowing && mBlockUpdates) {
|
||||||
|
mBlockUpdates = false;
|
||||||
|
force = true;
|
||||||
|
}
|
||||||
|
if (!wasShowing && mKeyguardShowing) {
|
||||||
|
mKeyguardJustShown = true;
|
||||||
|
}
|
||||||
|
update(force);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onKeyguardFadingAwayChanged() {
|
||||||
|
if (!mKeyguardStateController.isKeyguardFadingAway()) {
|
||||||
|
if (mBlockUpdates) {
|
||||||
|
mBlockUpdates = false;
|
||||||
|
update(true /* force */);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnlockedChanged() {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final View.AccessibilityDelegate mAccessibilityDelegate =
|
||||||
|
new View.AccessibilityDelegate() {
|
||||||
|
@Override
|
||||||
|
public void onInitializeAccessibilityNodeInfo(View host,
|
||||||
|
AccessibilityNodeInfo info) {
|
||||||
|
super.onInitializeAccessibilityNodeInfo(host, info);
|
||||||
|
boolean fingerprintRunning =
|
||||||
|
mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
|
||||||
|
// Only checking if unlocking with Biometric is allowed (no matter strong or
|
||||||
|
// non-strong as long as primary auth, i.e. PIN/pattern/password, is not
|
||||||
|
// required), so it's ok to pass true for isStrongBiometric to
|
||||||
|
// isUnlockingWithBiometricAllowed() to bypass the check of whether non-strong
|
||||||
|
// biometric is allowed
|
||||||
|
boolean unlockingAllowed = mKeyguardUpdateMonitor
|
||||||
|
.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */);
|
||||||
|
if (fingerprintRunning && unlockingAllowed) {
|
||||||
|
AccessibilityNodeInfo.AccessibilityAction unlock =
|
||||||
|
new AccessibilityNodeInfo.AccessibilityAction(
|
||||||
|
AccessibilityNodeInfo.ACTION_CLICK,
|
||||||
|
mResources.getString(
|
||||||
|
R.string.accessibility_unlock_without_fingerprint));
|
||||||
|
info.addAction(unlock);
|
||||||
|
info.setHintText(mResources.getString(
|
||||||
|
R.string.accessibility_waiting_for_fingerprint));
|
||||||
|
} else if (getState() == STATE_SCANNING_FACE) {
|
||||||
|
//Avoid 'button' to be spoken for scanning face
|
||||||
|
info.setClassName(LockIcon.class.getName());
|
||||||
|
info.setContentDescription(mResources.getString(
|
||||||
|
R.string.accessibility_scanning_face));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private int mLastState;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public LockscreenLockIconController(LockscreenGestureLogger lockscreenGestureLogger,
|
public LockscreenLockIconController(LockscreenGestureLogger lockscreenGestureLogger,
|
||||||
@@ -188,7 +319,10 @@ public class LockscreenLockIconController {
|
|||||||
ConfigurationController configurationController,
|
ConfigurationController configurationController,
|
||||||
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
|
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
|
||||||
KeyguardBypassController keyguardBypassController,
|
KeyguardBypassController keyguardBypassController,
|
||||||
@Nullable DockManager dockManager) {
|
@Nullable DockManager dockManager,
|
||||||
|
KeyguardStateController keyguardStateController,
|
||||||
|
@Main Resources resources,
|
||||||
|
HeadsUpManagerPhone headsUpManagerPhone) {
|
||||||
mLockscreenGestureLogger = lockscreenGestureLogger;
|
mLockscreenGestureLogger = lockscreenGestureLogger;
|
||||||
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
||||||
mLockPatternUtils = lockPatternUtils;
|
mLockPatternUtils = lockPatternUtils;
|
||||||
@@ -200,24 +334,31 @@ public class LockscreenLockIconController {
|
|||||||
mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
|
mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
|
||||||
mKeyguardBypassController = keyguardBypassController;
|
mKeyguardBypassController = keyguardBypassController;
|
||||||
mDockManager = dockManager == null ? Optional.empty() : Optional.of(dockManager);
|
mDockManager = dockManager == null ? Optional.empty() : Optional.of(dockManager);
|
||||||
|
mKeyguardStateController = keyguardStateController;
|
||||||
|
mResources = resources;
|
||||||
|
mHeadsUpManagerPhone = headsUpManagerPhone;
|
||||||
|
|
||||||
mKeyguardIndicationController.setLockIconController(this);
|
mKeyguardIndicationController.setLockIconController(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Associate the controller with a {@link LockIcon}
|
* Associate the controller with a {@link LockIcon}
|
||||||
|
*
|
||||||
|
* TODO: change to an init method and inject the view.
|
||||||
*/
|
*/
|
||||||
public void attach(LockIcon lockIcon) {
|
public void attach(LockIcon lockIcon) {
|
||||||
mLockIcon = lockIcon;
|
mLockIcon = lockIcon;
|
||||||
|
|
||||||
mLockIcon.setOnClickListener(this::handleClick);
|
mLockIcon.setOnClickListener(this::handleClick);
|
||||||
mLockIcon.setOnLongClickListener(this::handleLongClick);
|
mLockIcon.setOnLongClickListener(this::handleLongClick);
|
||||||
|
mLockIcon.setAccessibilityDelegate(mAccessibilityDelegate);
|
||||||
|
mLockIcon.setStateProvider(this::getState);
|
||||||
|
|
||||||
if (mLockIcon.isAttachedToWindow()) {
|
if (mLockIcon.isAttachedToWindow()) {
|
||||||
mOnAttachStateChangeListener.onViewAttachedToWindow(mLockIcon);
|
mOnAttachStateChangeListener.onViewAttachedToWindow(mLockIcon);
|
||||||
}
|
}
|
||||||
mLockIcon.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
|
mLockIcon.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
|
||||||
mLockIcon.setStatusBarState(mStatusBarStateController.getState());
|
setStatusBarState(mStatusBarStateController.getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
public LockIcon getView() {
|
public LockIcon getView() {
|
||||||
@@ -228,8 +369,10 @@ public class LockscreenLockIconController {
|
|||||||
* Called whenever the scrims become opaque, transparent or semi-transparent.
|
* Called whenever the scrims become opaque, transparent or semi-transparent.
|
||||||
*/
|
*/
|
||||||
public void onScrimVisibilityChanged(Integer scrimsVisible) {
|
public void onScrimVisibilityChanged(Integer scrimsVisible) {
|
||||||
if (mLockIcon != null) {
|
if (mWakeAndUnlockRunning
|
||||||
mLockIcon.onScrimVisibilityChanged(scrimsVisible);
|
&& scrimsVisible == ScrimController.TRANSPARENT) {
|
||||||
|
mWakeAndUnlockRunning = false;
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,55 +380,56 @@ public class LockscreenLockIconController {
|
|||||||
* Propagate {@link StatusBar} pulsing state.
|
* Propagate {@link StatusBar} pulsing state.
|
||||||
*/
|
*/
|
||||||
public void setPulsing(boolean pulsing) {
|
public void setPulsing(boolean pulsing) {
|
||||||
if (mLockIcon != null) {
|
mPulsing = pulsing;
|
||||||
mLockIcon.setPulsing(pulsing);
|
update();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the biometric authentication mode changes.
|
* We need to hide the lock whenever there's a fingerprint unlock, otherwise you'll see the
|
||||||
*
|
* icon on top of the black front scrim.
|
||||||
* @param wakeAndUnlock If the type is {@link BiometricUnlockController#isWakeAndUnlock()}
|
* @param wakeAndUnlock are we wake and unlocking
|
||||||
* @param isUnlock If the type is {@link BiometricUnlockController#isBiometricUnlock()} ()
|
* @param isUnlock are we currently unlocking
|
||||||
*/
|
*/
|
||||||
public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock) {
|
public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock) {
|
||||||
if (mLockIcon != null) {
|
if (wakeAndUnlock) {
|
||||||
mLockIcon.onBiometricAuthModeChanged(wakeAndUnlock, isUnlock);
|
mWakeAndUnlockRunning = true;
|
||||||
}
|
}
|
||||||
|
if (isUnlock && mKeyguardBypassController.getBypassEnabled() && canBlockUpdates()) {
|
||||||
|
// We don't want the icon to change while we are unlocking
|
||||||
|
mBlockUpdates = true;
|
||||||
|
}
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When we're launching an affordance, like double pressing power to open camera.
|
* When we're launching an affordance, like double pressing power to open camera.
|
||||||
*/
|
*/
|
||||||
public void onShowingLaunchAffordanceChanged(Boolean showing) {
|
public void onShowingLaunchAffordanceChanged(Boolean showing) {
|
||||||
if (mLockIcon != null) {
|
mShowingLaunchAffordance = showing;
|
||||||
mLockIcon.onShowingLaunchAffordanceChanged(showing);
|
update();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets whether the bouncer is showing. */
|
/** Sets whether the bouncer is showing. */
|
||||||
public void setBouncerShowingScrimmed(boolean bouncerShowing) {
|
public void setBouncerShowingScrimmed(boolean bouncerShowing) {
|
||||||
if (mLockIcon != null) {
|
mBouncerShowingScrimmed = bouncerShowing;
|
||||||
mLockIcon.setBouncerShowingScrimmed(bouncerShowing);
|
if (mKeyguardBypassController.getBypassEnabled()) {
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When {@link KeyguardBouncer} starts to be dismissed and starts to play its animation.
|
* Animate padlock opening when bouncer challenge is solved.
|
||||||
*/
|
*/
|
||||||
public void onBouncerPreHideAnimation() {
|
public void onBouncerPreHideAnimation() {
|
||||||
if (mLockIcon != null) {
|
update();
|
||||||
mLockIcon.onBouncerPreHideAnimation();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If we're currently presenting an authentication error message.
|
* If we're currently presenting an authentication error message.
|
||||||
*/
|
*/
|
||||||
public void setTransientBiometricsError(boolean transientBiometricsError) {
|
public void setTransientBiometricsError(boolean transientBiometricsError) {
|
||||||
if (mLockIcon != null) {
|
mTransientBiometricsError = transientBiometricsError;
|
||||||
mLockIcon.setTransientBiometricsError(transientBiometricsError);
|
update();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleLongClick(View view) {
|
private boolean handleLongClick(View view) {
|
||||||
@@ -306,4 +450,90 @@ public class LockscreenLockIconController {
|
|||||||
}
|
}
|
||||||
mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
|
mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void update() {
|
||||||
|
update(false /* force */);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update(boolean force) {
|
||||||
|
int state = getState();
|
||||||
|
boolean shouldUpdate = mLastState != state || force;
|
||||||
|
if (mBlockUpdates && canBlockUpdates()) {
|
||||||
|
shouldUpdate = false;
|
||||||
|
}
|
||||||
|
if (shouldUpdate && mLockIcon != null) {
|
||||||
|
mLockIcon.update(mLastState, mPulsing, mDozing, mKeyguardJustShown);
|
||||||
|
}
|
||||||
|
mLastState = state;
|
||||||
|
mKeyguardJustShown = false;
|
||||||
|
updateIconVisibility();
|
||||||
|
updateClickability();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getState() {
|
||||||
|
if ((mKeyguardStateController.canDismissLockScreen() || !mKeyguardShowing
|
||||||
|
|| mKeyguardStateController.isKeyguardGoingAway()) && !mSimLocked) {
|
||||||
|
return STATE_LOCK_OPEN;
|
||||||
|
} else if (mTransientBiometricsError) {
|
||||||
|
return STATE_BIOMETRICS_ERROR;
|
||||||
|
} else if (mKeyguardUpdateMonitor.isFaceDetectionRunning() && !mPulsing) {
|
||||||
|
return STATE_SCANNING_FACE;
|
||||||
|
} else {
|
||||||
|
return STATE_LOCKED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canBlockUpdates() {
|
||||||
|
return mKeyguardShowing || mKeyguardStateController.isKeyguardFadingAway();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDozing(boolean isDozing) {
|
||||||
|
mDozing = isDozing;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the StatusBarState. */
|
||||||
|
private void setStatusBarState(int statusBarState) {
|
||||||
|
mStatusBarState = statusBarState;
|
||||||
|
updateIconVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the icon visibility
|
||||||
|
* @return true if the visibility changed
|
||||||
|
*/
|
||||||
|
private boolean updateIconVisibility() {
|
||||||
|
boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
|
||||||
|
boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
|
||||||
|
|| mShowingLaunchAffordance;
|
||||||
|
if (mKeyguardBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
|
||||||
|
if ((mHeadsUpManagerPhone.isHeadsUpGoingAway()
|
||||||
|
|| mHeadsUpManagerPhone.hasPinnedHeadsUp()
|
||||||
|
|| mStatusBarState == StatusBarState.KEYGUARD)
|
||||||
|
&& !mNotificationWakeUpCoordinator.getNotificationsFullyHidden()) {
|
||||||
|
invisible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mLockIcon == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mLockIcon.updateIconVisibility(!invisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateClickability() {
|
||||||
|
if (mAccessibilityController == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean canLock = mKeyguardStateController.isMethodSecure()
|
||||||
|
&& mKeyguardStateController.canDismissLockScreen();
|
||||||
|
boolean clickToUnlock = mAccessibilityController.isAccessibilityEnabled();
|
||||||
|
if (mLockIcon != null) {
|
||||||
|
mLockIcon.setClickable(clickToUnlock);
|
||||||
|
mLockIcon.setLongClickable(canLock && !clickToUnlock);
|
||||||
|
mLockIcon.setFocusable(mAccessibilityController.isAccessibilityEnabled());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import com.android.systemui.qs.QuickStatusBarHeader;
|
|||||||
import com.android.systemui.qs.customize.QSCustomizer;
|
import com.android.systemui.qs.customize.QSCustomizer;
|
||||||
import com.android.systemui.statusbar.NotificationShelf;
|
import com.android.systemui.statusbar.NotificationShelf;
|
||||||
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
|
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
|
||||||
import com.android.systemui.statusbar.phone.LockIcon;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@@ -147,11 +146,6 @@ public class InjectionInflationController {
|
|||||||
*/
|
*/
|
||||||
KeyguardMessageArea createKeyguardMessageArea();
|
KeyguardMessageArea createKeyguardMessageArea();
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the keyguard LockIcon.
|
|
||||||
*/
|
|
||||||
LockIcon createLockIcon();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the QSPanel.
|
* Creates the QSPanel.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.eq;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
@@ -35,6 +36,7 @@ import com.android.systemui.statusbar.KeyguardIndicationController;
|
|||||||
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
|
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
|
||||||
import com.android.systemui.statusbar.policy.AccessibilityController;
|
import com.android.systemui.statusbar.policy.AccessibilityController;
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||||
|
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -71,6 +73,12 @@ public class LockscreenIconControllerTest extends SysuiTestCase {
|
|||||||
private KeyguardBypassController mKeyguardBypassController;
|
private KeyguardBypassController mKeyguardBypassController;
|
||||||
@Mock
|
@Mock
|
||||||
private DockManager mDockManager;
|
private DockManager mDockManager;
|
||||||
|
@Mock
|
||||||
|
private KeyguardStateController mKeyguardStateController;
|
||||||
|
@Mock
|
||||||
|
private Resources mResources;
|
||||||
|
@Mock
|
||||||
|
private HeadsUpManagerPhone mHeadsUpManagerPhone;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -81,7 +89,8 @@ public class LockscreenIconControllerTest extends SysuiTestCase {
|
|||||||
mLockscreenGestureLogger, mKeyguardUpdateMonitor, mLockPatternUtils,
|
mLockscreenGestureLogger, mKeyguardUpdateMonitor, mLockPatternUtils,
|
||||||
mShadeController, mAccessibilityController, mKeyguardIndicationController,
|
mShadeController, mAccessibilityController, mKeyguardIndicationController,
|
||||||
mStatusBarStateController, mConfigurationController, mNotificationWakeUpCoordinator,
|
mStatusBarStateController, mConfigurationController, mNotificationWakeUpCoordinator,
|
||||||
mKeyguardBypassController, mDockManager);
|
mKeyguardBypassController, mDockManager, mKeyguardStateController, mResources,
|
||||||
|
mHeadsUpManagerPhone);
|
||||||
|
|
||||||
mLockIconController.attach(mLockIcon);
|
mLockIconController.attach(mLockIcon);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user