Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java +96 −354 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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 { static final int STATE_LOCKED = 0; private static final int STATE_LOCKED = 0; static final int STATE_LOCK_OPEN = 1; private static final int STATE_LOCK_OPEN = 1; static final int STATE_SCANNING_FACE = 2; private static final int STATE_SCANNING_FACE = 2; static final int STATE_BIOMETRICS_ERROR = 3; private static final int STATE_BIOMETRICS_ERROR = 3; private float mDozeAmount; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private int mIconColor; private final AccessibilityController mAccessibilityController; private StateProvider mStateProvider; private final KeyguardStateController mKeyguardStateController; private int mOldState; private final KeyguardBypassController mBypassController; 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 = 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()) { mBouncerPreHideAnimation = false; if (mBlockUpdates) { mBlockUpdates = false; update(true /* force */); } } } @Override public void onUnlockedChanged() { update(); } }; @Inject public LockIcon(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, AccessibilityController accessibilityController, KeyguardBypassController bypassController, NotificationWakeUpCoordinator wakeUpCoordinator, KeyguardStateController keyguardStateController, HeadsUpManagerPhone headsUpManager) { super(context, attrs); mContext = context; mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); mAccessibilityController = accessibilityController; mBypassController = bypassController; mWakeUpCoordinator = wakeUpCoordinator; mKeyguardStateController = keyguardStateController; mHeadsUpManager = headsUpManager; } @Override protected void onAttachedToWindow() { 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 protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); final int density = newConfig.densityDpi; 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); } } private final OnPreDrawListener mOnPreDrawListener = new OnPreDrawListener() { @Override @Override public boolean onPreDraw() { public boolean onPreDraw() { mUpdatePending = false; getViewTreeObserver().removeOnPreDrawListener(this); getViewTreeObserver().removeOnPreDrawListener(this); int state = getState(); int newState = mStateProvider.getState(); int lastState = mLastState; Drawable icon = getIcon(newState); 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); setImageDrawable(icon, false); if (mIsFaceUnlockState) { announceForAccessibility(getContext().getString( if (newState == STATE_SCANNING_FACE) { announceForAccessibility(getResources().getString( R.string.accessibility_scanning_face)); R.string.accessibility_scanning_face)); } } if (animation != null && isAnim) { if (icon instanceof AnimatedVectorDrawable) { final AnimatedVectorDrawable animation = (AnimatedVectorDrawable) icon; animation.forceAnimationOnUI(); animation.forceAnimationOnUI(); animation.clearAnimationCallbacks(); animation.clearAnimationCallbacks(); animation.registerAnimationCallback(new Animatable2.AnimationCallback() { animation.registerAnimationCallback( new Animatable2.AnimationCallback() { @Override @Override public void onAnimationEnd(Drawable drawable) { public void onAnimationEnd(Drawable drawable) { if (getDrawable() == animation && state == getState() if (getDrawable() == animation && doesAnimationLoop(lockAnimIndex)) { && newState == mStateProvider.getState() && newState == STATE_SCANNING_FACE) { animation.start(); animation.start(); } else { } else { Trace.endAsyncSection("LockIcon#Animation", state); Trace.endAsyncSection("LockIcon#Animation", newState); } } } } }); }); Trace.beginAsyncSection("LockIcon#Animation", state); Trace.beginAsyncSection("LockIcon#Animation", newState); animation.start(); animation.start(); } } return true; } } updateDarkTint(); }; updateIconVisibility(); public LockIcon(Context context, AttributeSet attrs) { updateClickability(); super(context, attrs); } return true; void setStateProvider(StateProvider stateProvider) { mStateProvider = stateProvider; } @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mDrawableCache.clear(); } } /** /** * 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() Loading @@ -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(); } } boolean canLock = mKeyguardStateController.isMethodSecure() && mKeyguardStateController.canDismissLockScreen(); void onThemeChange(int iconColor) { boolean clickToUnlock = mAccessibilityController.isAccessibilityEnabled(); mDrawableCache.clear(); setClickable(clickToUnlock); mIconColor = iconColor; setLongClickable(canLock && !clickToUnlock); updateDarkTint(); setFocusable(mAccessibilityController.isAccessibilityEnabled()); } } @Override private void updateDarkTint() { public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { int color = ColorUtils.blendARGB(mIconColor, Color.WHITE, mDozeAmount); super.onInitializeAccessibilityNodeInfo(info); setImageTintList(ColorStateList.valueOf(color)); 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 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)); } } private int getIconForState(int state) { return mDrawableCache.get(iconRes); } static int getIconForState(int state) { int iconRes; int iconRes; switch (state) { switch (state) { case STATE_LOCKED: case STATE_LOCKED: Loading @@ -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 Loading @@ -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, Loading Loading @@ -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(); } } } packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java +271 −41 File changed.Preview size limit exceeded, changes collapsed. Show changes packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java +0 −6 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -147,11 +146,6 @@ public class InjectionInflationController { */ */ KeyguardMessageArea createKeyguardMessageArea(); KeyguardMessageArea createKeyguardMessageArea(); /** * Creates the keyguard LockIcon. */ LockIcon createLockIcon(); /** /** * Creates the QSPanel. * Creates the QSPanel. */ */ Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java +10 −1 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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 Loading @@ -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); } } Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java +96 −354 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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 { static final int STATE_LOCKED = 0; private static final int STATE_LOCKED = 0; static final int STATE_LOCK_OPEN = 1; private static final int STATE_LOCK_OPEN = 1; static final int STATE_SCANNING_FACE = 2; private static final int STATE_SCANNING_FACE = 2; static final int STATE_BIOMETRICS_ERROR = 3; private static final int STATE_BIOMETRICS_ERROR = 3; private float mDozeAmount; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private int mIconColor; private final AccessibilityController mAccessibilityController; private StateProvider mStateProvider; private final KeyguardStateController mKeyguardStateController; private int mOldState; private final KeyguardBypassController mBypassController; 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 = 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()) { mBouncerPreHideAnimation = false; if (mBlockUpdates) { mBlockUpdates = false; update(true /* force */); } } } @Override public void onUnlockedChanged() { update(); } }; @Inject public LockIcon(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, AccessibilityController accessibilityController, KeyguardBypassController bypassController, NotificationWakeUpCoordinator wakeUpCoordinator, KeyguardStateController keyguardStateController, HeadsUpManagerPhone headsUpManager) { super(context, attrs); mContext = context; mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); mAccessibilityController = accessibilityController; mBypassController = bypassController; mWakeUpCoordinator = wakeUpCoordinator; mKeyguardStateController = keyguardStateController; mHeadsUpManager = headsUpManager; } @Override protected void onAttachedToWindow() { 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 protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); final int density = newConfig.densityDpi; 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); } } private final OnPreDrawListener mOnPreDrawListener = new OnPreDrawListener() { @Override @Override public boolean onPreDraw() { public boolean onPreDraw() { mUpdatePending = false; getViewTreeObserver().removeOnPreDrawListener(this); getViewTreeObserver().removeOnPreDrawListener(this); int state = getState(); int newState = mStateProvider.getState(); int lastState = mLastState; Drawable icon = getIcon(newState); 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); setImageDrawable(icon, false); if (mIsFaceUnlockState) { announceForAccessibility(getContext().getString( if (newState == STATE_SCANNING_FACE) { announceForAccessibility(getResources().getString( R.string.accessibility_scanning_face)); R.string.accessibility_scanning_face)); } } if (animation != null && isAnim) { if (icon instanceof AnimatedVectorDrawable) { final AnimatedVectorDrawable animation = (AnimatedVectorDrawable) icon; animation.forceAnimationOnUI(); animation.forceAnimationOnUI(); animation.clearAnimationCallbacks(); animation.clearAnimationCallbacks(); animation.registerAnimationCallback(new Animatable2.AnimationCallback() { animation.registerAnimationCallback( new Animatable2.AnimationCallback() { @Override @Override public void onAnimationEnd(Drawable drawable) { public void onAnimationEnd(Drawable drawable) { if (getDrawable() == animation && state == getState() if (getDrawable() == animation && doesAnimationLoop(lockAnimIndex)) { && newState == mStateProvider.getState() && newState == STATE_SCANNING_FACE) { animation.start(); animation.start(); } else { } else { Trace.endAsyncSection("LockIcon#Animation", state); Trace.endAsyncSection("LockIcon#Animation", newState); } } } } }); }); Trace.beginAsyncSection("LockIcon#Animation", state); Trace.beginAsyncSection("LockIcon#Animation", newState); animation.start(); animation.start(); } } return true; } } updateDarkTint(); }; updateIconVisibility(); public LockIcon(Context context, AttributeSet attrs) { updateClickability(); super(context, attrs); } return true; void setStateProvider(StateProvider stateProvider) { mStateProvider = stateProvider; } @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mDrawableCache.clear(); } } /** /** * 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() Loading @@ -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(); } } boolean canLock = mKeyguardStateController.isMethodSecure() && mKeyguardStateController.canDismissLockScreen(); void onThemeChange(int iconColor) { boolean clickToUnlock = mAccessibilityController.isAccessibilityEnabled(); mDrawableCache.clear(); setClickable(clickToUnlock); mIconColor = iconColor; setLongClickable(canLock && !clickToUnlock); updateDarkTint(); setFocusable(mAccessibilityController.isAccessibilityEnabled()); } } @Override private void updateDarkTint() { public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { int color = ColorUtils.blendARGB(mIconColor, Color.WHITE, mDozeAmount); super.onInitializeAccessibilityNodeInfo(info); setImageTintList(ColorStateList.valueOf(color)); 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 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)); } } private int getIconForState(int state) { return mDrawableCache.get(iconRes); } static int getIconForState(int state) { int iconRes; int iconRes; switch (state) { switch (state) { case STATE_LOCKED: case STATE_LOCKED: Loading @@ -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 Loading @@ -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, Loading Loading @@ -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(); } } }
packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java +271 −41 File changed.Preview size limit exceeded, changes collapsed. Show changes
packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java +0 −6 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -147,11 +146,6 @@ public class InjectionInflationController { */ */ KeyguardMessageArea createKeyguardMessageArea(); KeyguardMessageArea createKeyguardMessageArea(); /** * Creates the keyguard LockIcon. */ LockIcon createLockIcon(); /** /** * Creates the QSPanel. * Creates the QSPanel. */ */ Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java +10 −1 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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 Loading @@ -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); } } Loading