Loading packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +12 −13 Original line number Diff line number Diff line Loading @@ -599,10 +599,6 @@ public class KeyguardIndicationController { mHideTransientMessageOnScreenOff = hideOnScreenOff && transientIndication != null; mHandler.removeMessages(MSG_HIDE_TRANSIENT); mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK); if (mDozing && !TextUtils.isEmpty(mTransientIndication)) { // Make sure this doesn't get stuck and burns in. Acquire wakelock until its cleared. mWakeLock.setAcquired(true); } hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS); updateIndication(false); Loading @@ -622,10 +618,6 @@ public class KeyguardIndicationController { } protected final void updateIndication(boolean animate) { if (TextUtils.isEmpty(mTransientIndication)) { mWakeLock.setAcquired(false); } if (!mVisible) { return; } Loading @@ -643,24 +635,31 @@ public class KeyguardIndicationController { // colors can be hard to read in low brightness. mTopIndicationView.setTextColor(Color.WHITE); if (!TextUtils.isEmpty(mTransientIndication)) { mTopIndicationView.switchIndication(mTransientIndication, null); mWakeLock.setAcquired(true); mTopIndicationView.switchIndication(mTransientIndication, null, true, () -> mWakeLock.setAcquired(false)); } else if (!mBatteryPresent) { // If there is no battery detected, hide the indication and bail mIndicationArea.setVisibility(GONE); } else if (!TextUtils.isEmpty(mAlignmentIndication)) { mTopIndicationView.switchIndication(mAlignmentIndication, null); mTopIndicationView.switchIndication(mAlignmentIndication, null, false /* animate */, null /* onAnimationEndCallback */); mTopIndicationView.setTextColor(mContext.getColor(R.color.misalignment_text_color)); } else if (mPowerPluggedIn || mEnableBatteryDefender) { String indication = computePowerIndication(); if (animate) { animateText(mTopIndicationView, indication); mWakeLock.setAcquired(true); mTopIndicationView.switchIndication(indication, null, true /* animate */, () -> mWakeLock.setAcquired(false)); } else { mTopIndicationView.switchIndication(indication, null); mTopIndicationView.switchIndication(indication, null, false /* animate */, null /* onAnimationEndCallback */); } } else { String percentage = NumberFormat.getPercentInstance() .format(mBatteryLevel / 100f); mTopIndicationView.switchIndication(percentage, null); mTopIndicationView.switchIndication(percentage, null /* indication */, false /* animate */, null /* onAnimationEnd*/); } return; } Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java +92 −45 Original line number Diff line number Diff line Loading @@ -95,44 +95,85 @@ public class KeyguardIndicationTextView extends TextView { } /** * Changes the text with an animation and makes sure a single indication is shown long enough. * Changes the text with an animation. Makes sure a single indication is shown long enough. */ public void switchIndication(CharSequence text, KeyguardIndication indication) { switchIndication(text, indication, true, null); } /** * Changes the text with an optional animation. For animating text, makes sure a single * indication is shown long enough. * * @param text The text to show. * @param indication optional display information for the text * @param animate whether to animate this indication in - we may not want this on AOD * @param onAnimationEndCallback runnable called after this indication is animated in */ public void switchIndication(CharSequence text, KeyguardIndication indication) { public void switchIndication(CharSequence text, KeyguardIndication indication, boolean animate, Runnable onAnimationEndCallback) { if (text == null) text = ""; CharSequence lastPendingMessage = mMessages.peekLast(); if (TextUtils.equals(lastPendingMessage, text) || (lastPendingMessage == null && TextUtils.equals(text, getText()))) { if (onAnimationEndCallback != null) { onAnimationEndCallback.run(); } return; } mMessages.add(text); mKeyguardIndicationInfo.add(indication); if (animate) { final boolean hasIcon = indication != null && indication.getIcon() != null; final AnimatorSet animSet = new AnimatorSet(); final AnimatorSet.Builder animSetBuilder = animSet.play(getOutAnimator()); final AnimatorSet animator = new AnimatorSet(); // Make sure each animation is visible for a minimum amount of time, while not worrying // about fading in blank text long timeInMillis = System.currentTimeMillis(); long delay = Math.max(0, mNextAnimationTime - timeInMillis); setNextAnimationTime(timeInMillis + delay + getFadeOutDuration()); final long minDurationMillis = (indication != null && indication.getMinVisibilityMillis() != null) ? indication.getMinVisibilityMillis() : MSG_MIN_DURATION_MILLIS_DEFAULT; if (!text.equals("") || hasIcon) { setNextAnimationTime(mNextAnimationTime + minDurationMillis); animSetBuilder.before(getInAnimator()); Animator inAnimator = getInAnimator(); inAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); if (onAnimationEndCallback != null) { onAnimationEndCallback.run(); } } }); animator.playSequentially(getOutAnimator(), inAnimator); } else { Animator outAnimator = getOutAnimator(); outAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); if (onAnimationEndCallback != null) { onAnimationEndCallback.run(); } } }); animator.play(outAnimator); } animSet.setStartDelay(delay); animSet.start(); animator.setStartDelay(delay); animator.start(); } else { setAlpha(1f); setTranslationY(0f); setNextIndication(); if (onAnimationEndCallback != null) { onAnimationEndCallback.run(); } } } private AnimatorSet getOutAnimator() { Loading @@ -143,6 +184,20 @@ public class KeyguardIndicationTextView extends TextView { fadeOut.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animator) { super.onAnimationEnd(animator); setNextIndication(); } }); Animator yTranslate = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, 0, -getYTranslationPixels()); yTranslate.setDuration(getFadeOutDuration()); animatorSet.playTogether(fadeOut, yTranslate); return animatorSet; } private void setNextIndication() { KeyguardIndication info = mKeyguardIndicationInfo.poll(); if (info != null) { // First, update the style. Loading @@ -167,15 +222,6 @@ public class KeyguardIndicationTextView extends TextView { } setText(mMessages.poll()); } }); Animator yTranslate = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, 0, -getYTranslationPixels()); yTranslate.setDuration(getFadeOutDuration()); animatorSet.playTogether(fadeOut, yTranslate); return animatorSet; } private AnimatorSet getInAnimator() { AnimatorSet animatorSet = new AnimatorSet(); Loading @@ -190,6 +236,7 @@ public class KeyguardIndicationTextView extends TextView { yTranslate.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationCancel(Animator animation) { super.onAnimationCancel(animation); setTranslationY(0); } }); Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +14 −23 Original line number Diff line number Diff line Loading @@ -166,7 +166,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { private BroadcastReceiver mBroadcastReceiver; private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); private KeyguardIndicationTextView mTextView; private KeyguardIndicationTextView mTextView; // AOD text private KeyguardIndicationController mController; private WakeLockFake.Builder mWakeLockBuilder; Loading Loading @@ -412,41 +412,32 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { @Test public void transientIndication_holdsWakeLock_whenDozing() { // GIVEN animations are enabled and text is visible mTextView.setAnimationsEnabled(true); createController(); mController.setVisible(true); // WHEN transient text is shown mStatusBarStateListener.onDozingChanged(true); mController.showTransientIndication("Test"); assertTrue(mWakeLock.isHeld()); } @Test public void transientIndication_releasesWakeLock_afterHiding() { createController(); mStatusBarStateListener.onDozingChanged(true); mController.showTransientIndication("Test"); mController.hideTransientIndication(); assertFalse(mWakeLock.isHeld()); // THEN wake lock is held while the animation is running assertTrue("WakeLock expected: HELD, was: RELEASED", mWakeLock.isHeld()); } @Test public void transientIndication_releasesWakeLock_afterHidingDelayed() throws Throwable { mInstrumentation.runOnMainSync(() -> { public void transientIndication_releasesWakeLock_whenDozing() { // GIVEN animations aren't enabled mTextView.setAnimationsEnabled(false); createController(); mController.setVisible(true); // WHEN we show the transient indication mStatusBarStateListener.onDozingChanged(true); mController.showTransientIndication("Test"); mController.hideTransientIndicationDelayed(0); }); mInstrumentation.waitForIdleSync(); Boolean[] held = new Boolean[1]; mInstrumentation.runOnMainSync(() -> { held[0] = mWakeLock.isHeld(); }); assertFalse("WakeLock expected: RELEASED, was: HELD", held[0]); // THEN wake lock is RELEASED, not held assertFalse("WakeLock expected: RELEASED, was: HELD", mWakeLock.isHeld()); } @Test Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +12 −13 Original line number Diff line number Diff line Loading @@ -599,10 +599,6 @@ public class KeyguardIndicationController { mHideTransientMessageOnScreenOff = hideOnScreenOff && transientIndication != null; mHandler.removeMessages(MSG_HIDE_TRANSIENT); mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK); if (mDozing && !TextUtils.isEmpty(mTransientIndication)) { // Make sure this doesn't get stuck and burns in. Acquire wakelock until its cleared. mWakeLock.setAcquired(true); } hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS); updateIndication(false); Loading @@ -622,10 +618,6 @@ public class KeyguardIndicationController { } protected final void updateIndication(boolean animate) { if (TextUtils.isEmpty(mTransientIndication)) { mWakeLock.setAcquired(false); } if (!mVisible) { return; } Loading @@ -643,24 +635,31 @@ public class KeyguardIndicationController { // colors can be hard to read in low brightness. mTopIndicationView.setTextColor(Color.WHITE); if (!TextUtils.isEmpty(mTransientIndication)) { mTopIndicationView.switchIndication(mTransientIndication, null); mWakeLock.setAcquired(true); mTopIndicationView.switchIndication(mTransientIndication, null, true, () -> mWakeLock.setAcquired(false)); } else if (!mBatteryPresent) { // If there is no battery detected, hide the indication and bail mIndicationArea.setVisibility(GONE); } else if (!TextUtils.isEmpty(mAlignmentIndication)) { mTopIndicationView.switchIndication(mAlignmentIndication, null); mTopIndicationView.switchIndication(mAlignmentIndication, null, false /* animate */, null /* onAnimationEndCallback */); mTopIndicationView.setTextColor(mContext.getColor(R.color.misalignment_text_color)); } else if (mPowerPluggedIn || mEnableBatteryDefender) { String indication = computePowerIndication(); if (animate) { animateText(mTopIndicationView, indication); mWakeLock.setAcquired(true); mTopIndicationView.switchIndication(indication, null, true /* animate */, () -> mWakeLock.setAcquired(false)); } else { mTopIndicationView.switchIndication(indication, null); mTopIndicationView.switchIndication(indication, null, false /* animate */, null /* onAnimationEndCallback */); } } else { String percentage = NumberFormat.getPercentInstance() .format(mBatteryLevel / 100f); mTopIndicationView.switchIndication(percentage, null); mTopIndicationView.switchIndication(percentage, null /* indication */, false /* animate */, null /* onAnimationEnd*/); } return; } Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java +92 −45 Original line number Diff line number Diff line Loading @@ -95,44 +95,85 @@ public class KeyguardIndicationTextView extends TextView { } /** * Changes the text with an animation and makes sure a single indication is shown long enough. * Changes the text with an animation. Makes sure a single indication is shown long enough. */ public void switchIndication(CharSequence text, KeyguardIndication indication) { switchIndication(text, indication, true, null); } /** * Changes the text with an optional animation. For animating text, makes sure a single * indication is shown long enough. * * @param text The text to show. * @param indication optional display information for the text * @param animate whether to animate this indication in - we may not want this on AOD * @param onAnimationEndCallback runnable called after this indication is animated in */ public void switchIndication(CharSequence text, KeyguardIndication indication) { public void switchIndication(CharSequence text, KeyguardIndication indication, boolean animate, Runnable onAnimationEndCallback) { if (text == null) text = ""; CharSequence lastPendingMessage = mMessages.peekLast(); if (TextUtils.equals(lastPendingMessage, text) || (lastPendingMessage == null && TextUtils.equals(text, getText()))) { if (onAnimationEndCallback != null) { onAnimationEndCallback.run(); } return; } mMessages.add(text); mKeyguardIndicationInfo.add(indication); if (animate) { final boolean hasIcon = indication != null && indication.getIcon() != null; final AnimatorSet animSet = new AnimatorSet(); final AnimatorSet.Builder animSetBuilder = animSet.play(getOutAnimator()); final AnimatorSet animator = new AnimatorSet(); // Make sure each animation is visible for a minimum amount of time, while not worrying // about fading in blank text long timeInMillis = System.currentTimeMillis(); long delay = Math.max(0, mNextAnimationTime - timeInMillis); setNextAnimationTime(timeInMillis + delay + getFadeOutDuration()); final long minDurationMillis = (indication != null && indication.getMinVisibilityMillis() != null) ? indication.getMinVisibilityMillis() : MSG_MIN_DURATION_MILLIS_DEFAULT; if (!text.equals("") || hasIcon) { setNextAnimationTime(mNextAnimationTime + minDurationMillis); animSetBuilder.before(getInAnimator()); Animator inAnimator = getInAnimator(); inAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); if (onAnimationEndCallback != null) { onAnimationEndCallback.run(); } } }); animator.playSequentially(getOutAnimator(), inAnimator); } else { Animator outAnimator = getOutAnimator(); outAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); if (onAnimationEndCallback != null) { onAnimationEndCallback.run(); } } }); animator.play(outAnimator); } animSet.setStartDelay(delay); animSet.start(); animator.setStartDelay(delay); animator.start(); } else { setAlpha(1f); setTranslationY(0f); setNextIndication(); if (onAnimationEndCallback != null) { onAnimationEndCallback.run(); } } } private AnimatorSet getOutAnimator() { Loading @@ -143,6 +184,20 @@ public class KeyguardIndicationTextView extends TextView { fadeOut.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animator) { super.onAnimationEnd(animator); setNextIndication(); } }); Animator yTranslate = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, 0, -getYTranslationPixels()); yTranslate.setDuration(getFadeOutDuration()); animatorSet.playTogether(fadeOut, yTranslate); return animatorSet; } private void setNextIndication() { KeyguardIndication info = mKeyguardIndicationInfo.poll(); if (info != null) { // First, update the style. Loading @@ -167,15 +222,6 @@ public class KeyguardIndicationTextView extends TextView { } setText(mMessages.poll()); } }); Animator yTranslate = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, 0, -getYTranslationPixels()); yTranslate.setDuration(getFadeOutDuration()); animatorSet.playTogether(fadeOut, yTranslate); return animatorSet; } private AnimatorSet getInAnimator() { AnimatorSet animatorSet = new AnimatorSet(); Loading @@ -190,6 +236,7 @@ public class KeyguardIndicationTextView extends TextView { yTranslate.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationCancel(Animator animation) { super.onAnimationCancel(animation); setTranslationY(0); } }); Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +14 −23 Original line number Diff line number Diff line Loading @@ -166,7 +166,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { private BroadcastReceiver mBroadcastReceiver; private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); private KeyguardIndicationTextView mTextView; private KeyguardIndicationTextView mTextView; // AOD text private KeyguardIndicationController mController; private WakeLockFake.Builder mWakeLockBuilder; Loading Loading @@ -412,41 +412,32 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { @Test public void transientIndication_holdsWakeLock_whenDozing() { // GIVEN animations are enabled and text is visible mTextView.setAnimationsEnabled(true); createController(); mController.setVisible(true); // WHEN transient text is shown mStatusBarStateListener.onDozingChanged(true); mController.showTransientIndication("Test"); assertTrue(mWakeLock.isHeld()); } @Test public void transientIndication_releasesWakeLock_afterHiding() { createController(); mStatusBarStateListener.onDozingChanged(true); mController.showTransientIndication("Test"); mController.hideTransientIndication(); assertFalse(mWakeLock.isHeld()); // THEN wake lock is held while the animation is running assertTrue("WakeLock expected: HELD, was: RELEASED", mWakeLock.isHeld()); } @Test public void transientIndication_releasesWakeLock_afterHidingDelayed() throws Throwable { mInstrumentation.runOnMainSync(() -> { public void transientIndication_releasesWakeLock_whenDozing() { // GIVEN animations aren't enabled mTextView.setAnimationsEnabled(false); createController(); mController.setVisible(true); // WHEN we show the transient indication mStatusBarStateListener.onDozingChanged(true); mController.showTransientIndication("Test"); mController.hideTransientIndicationDelayed(0); }); mInstrumentation.waitForIdleSync(); Boolean[] held = new Boolean[1]; mInstrumentation.runOnMainSync(() -> { held[0] = mWakeLock.isHeld(); }); assertFalse("WakeLock expected: RELEASED, was: HELD", held[0]); // THEN wake lock is RELEASED, not held assertFalse("WakeLock expected: RELEASED, was: HELD", mWakeLock.isHeld()); } @Test Loading