Merge "Hold a wake-lock for battery % changes in AOD" into sc-v2-dev

This commit is contained in:
TreeHugger Robot
2021-10-14 19:25:43 +00:00
committed by Android (Google) Code Review
3 changed files with 118 additions and 81 deletions

View File

@@ -599,10 +599,6 @@ public class KeyguardIndicationController {
mHideTransientMessageOnScreenOff = hideOnScreenOff && transientIndication != null; mHideTransientMessageOnScreenOff = hideOnScreenOff && transientIndication != null;
mHandler.removeMessages(MSG_HIDE_TRANSIENT); mHandler.removeMessages(MSG_HIDE_TRANSIENT);
mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK); 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); hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
updateIndication(false); updateIndication(false);
@@ -622,10 +618,6 @@ public class KeyguardIndicationController {
} }
protected final void updateIndication(boolean animate) { protected final void updateIndication(boolean animate) {
if (TextUtils.isEmpty(mTransientIndication)) {
mWakeLock.setAcquired(false);
}
if (!mVisible) { if (!mVisible) {
return; return;
} }
@@ -643,24 +635,31 @@ public class KeyguardIndicationController {
// colors can be hard to read in low brightness. // colors can be hard to read in low brightness.
mTopIndicationView.setTextColor(Color.WHITE); mTopIndicationView.setTextColor(Color.WHITE);
if (!TextUtils.isEmpty(mTransientIndication)) { if (!TextUtils.isEmpty(mTransientIndication)) {
mTopIndicationView.switchIndication(mTransientIndication, null); mWakeLock.setAcquired(true);
mTopIndicationView.switchIndication(mTransientIndication, null,
true, () -> mWakeLock.setAcquired(false));
} else if (!mBatteryPresent) { } else if (!mBatteryPresent) {
// If there is no battery detected, hide the indication and bail // If there is no battery detected, hide the indication and bail
mIndicationArea.setVisibility(GONE); mIndicationArea.setVisibility(GONE);
} else if (!TextUtils.isEmpty(mAlignmentIndication)) { } 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)); mTopIndicationView.setTextColor(mContext.getColor(R.color.misalignment_text_color));
} else if (mPowerPluggedIn || mEnableBatteryDefender) { } else if (mPowerPluggedIn || mEnableBatteryDefender) {
String indication = computePowerIndication(); String indication = computePowerIndication();
if (animate) { if (animate) {
animateText(mTopIndicationView, indication); mWakeLock.setAcquired(true);
mTopIndicationView.switchIndication(indication, null, true /* animate */,
() -> mWakeLock.setAcquired(false));
} else { } else {
mTopIndicationView.switchIndication(indication, null); mTopIndicationView.switchIndication(indication, null, false /* animate */,
null /* onAnimationEndCallback */);
} }
} else { } else {
String percentage = NumberFormat.getPercentInstance() String percentage = NumberFormat.getPercentInstance()
.format(mBatteryLevel / 100f); .format(mBatteryLevel / 100f);
mTopIndicationView.switchIndication(percentage, null); mTopIndicationView.switchIndication(percentage, null /* indication */,
false /* animate */, null /* onAnimationEnd*/);
} }
return; return;
} }

View File

@@ -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 text The text to show.
* @param indication optional display information for the text * @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 = ""; if (text == null) text = "";
CharSequence lastPendingMessage = mMessages.peekLast(); CharSequence lastPendingMessage = mMessages.peekLast();
if (TextUtils.equals(lastPendingMessage, text) if (TextUtils.equals(lastPendingMessage, text)
|| (lastPendingMessage == null && TextUtils.equals(text, getText()))) { || (lastPendingMessage == null && TextUtils.equals(text, getText()))) {
if (onAnimationEndCallback != null) {
onAnimationEndCallback.run();
}
return; return;
} }
mMessages.add(text); mMessages.add(text);
mKeyguardIndicationInfo.add(indication); mKeyguardIndicationInfo.add(indication);
final boolean hasIcon = indication != null && indication.getIcon() != null; if (animate) {
final AnimatorSet animSet = new AnimatorSet(); final boolean hasIcon = indication != null && indication.getIcon() != null;
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);
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);
}
// Make sure each animation is visible for a minimum amount of time, while not worrying animator.setStartDelay(delay);
// about fading in blank text animator.start();
long timeInMillis = System.currentTimeMillis(); } else {
long delay = Math.max(0, mNextAnimationTime - timeInMillis); setAlpha(1f);
setNextAnimationTime(timeInMillis + delay + getFadeOutDuration()); setTranslationY(0f);
setNextIndication();
final long minDurationMillis = if (onAnimationEndCallback != null) {
(indication != null && indication.getMinVisibilityMillis() != null) onAnimationEndCallback.run();
? indication.getMinVisibilityMillis() }
: MSG_MIN_DURATION_MILLIS_DEFAULT;
if (!text.equals("") || hasIcon) {
setNextAnimationTime(mNextAnimationTime + minDurationMillis);
animSetBuilder.before(getInAnimator());
} }
animSet.setStartDelay(delay);
animSet.start();
} }
private AnimatorSet getOutAnimator() { private AnimatorSet getOutAnimator() {
@@ -143,29 +184,8 @@ public class KeyguardIndicationTextView extends TextView {
fadeOut.addListener(new AnimatorListenerAdapter() { fadeOut.addListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animator) { public void onAnimationEnd(Animator animator) {
KeyguardIndication info = mKeyguardIndicationInfo.poll(); super.onAnimationEnd(animator);
if (info != null) { setNextIndication();
// First, update the style.
// If a background is set on the text, we don't want shadow on the text
if (info.getBackground() != null) {
setTextAppearance(sButtonStyleId);
} else {
setTextAppearance(sStyleId);
}
setBackground(info.getBackground());
setTextColor(info.getTextColor());
setOnClickListener(info.getClickListener());
setClickable(info.getClickListener() != null);
final Drawable icon = info.getIcon();
if (icon != null) {
icon.setTint(getCurrentTextColor());
if (icon instanceof AnimatedVectorDrawable) {
((AnimatedVectorDrawable) icon).start();
}
}
setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null);
}
setText(mMessages.poll());
} }
}); });
@@ -177,6 +197,32 @@ public class KeyguardIndicationTextView extends TextView {
return animatorSet; return animatorSet;
} }
private void setNextIndication() {
KeyguardIndication info = mKeyguardIndicationInfo.poll();
if (info != null) {
// First, update the style.
// If a background is set on the text, we don't want shadow on the text
if (info.getBackground() != null) {
setTextAppearance(sButtonStyleId);
} else {
setTextAppearance(sStyleId);
}
setBackground(info.getBackground());
setTextColor(info.getTextColor());
setOnClickListener(info.getClickListener());
setClickable(info.getClickListener() != null);
final Drawable icon = info.getIcon();
if (icon != null) {
icon.setTint(getCurrentTextColor());
if (icon instanceof AnimatedVectorDrawable) {
((AnimatedVectorDrawable) icon).start();
}
}
setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null);
}
setText(mMessages.poll());
}
private AnimatorSet getInAnimator() { private AnimatorSet getInAnimator() {
AnimatorSet animatorSet = new AnimatorSet(); AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(this, View.ALPHA, 1f); ObjectAnimator fadeIn = ObjectAnimator.ofFloat(this, View.ALPHA, 1f);
@@ -190,6 +236,7 @@ public class KeyguardIndicationTextView extends TextView {
yTranslate.addListener(new AnimatorListenerAdapter() { yTranslate.addListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationCancel(Animator animation) { public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
setTranslationY(0); setTranslationY(0);
} }
}); });

View File

@@ -166,7 +166,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
private BroadcastReceiver mBroadcastReceiver; private BroadcastReceiver mBroadcastReceiver;
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
private KeyguardIndicationTextView mTextView; private KeyguardIndicationTextView mTextView; // AOD text
private KeyguardIndicationController mController; private KeyguardIndicationController mController;
private WakeLockFake.Builder mWakeLockBuilder; private WakeLockFake.Builder mWakeLockBuilder;
@@ -412,41 +412,32 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
@Test @Test
public void transientIndication_holdsWakeLock_whenDozing() { public void transientIndication_holdsWakeLock_whenDozing() {
// GIVEN animations are enabled and text is visible
mTextView.setAnimationsEnabled(true);
createController(); createController();
mController.setVisible(true);
// WHEN transient text is shown
mStatusBarStateListener.onDozingChanged(true); mStatusBarStateListener.onDozingChanged(true);
mController.showTransientIndication("Test"); mController.showTransientIndication("Test");
assertTrue(mWakeLock.isHeld()); // THEN wake lock is held while the animation is running
assertTrue("WakeLock expected: HELD, was: RELEASED", mWakeLock.isHeld());
} }
@Test @Test
public void transientIndication_releasesWakeLock_afterHiding() { public void transientIndication_releasesWakeLock_whenDozing() {
// GIVEN animations aren't enabled
mTextView.setAnimationsEnabled(false);
createController(); createController();
mController.setVisible(true);
// WHEN we show the transient indication
mStatusBarStateListener.onDozingChanged(true); mStatusBarStateListener.onDozingChanged(true);
mController.showTransientIndication("Test"); mController.showTransientIndication("Test");
mController.hideTransientIndication();
assertFalse(mWakeLock.isHeld()); // THEN wake lock is RELEASED, not held
} assertFalse("WakeLock expected: RELEASED, was: HELD", mWakeLock.isHeld());
@Test
public void transientIndication_releasesWakeLock_afterHidingDelayed() throws Throwable {
mInstrumentation.runOnMainSync(() -> {
createController();
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]);
} }
@Test @Test