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;
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);
@@ -622,10 +618,6 @@ public class KeyguardIndicationController {
}
protected final void updateIndication(boolean animate) {
if (TextUtils.isEmpty(mTransientIndication)) {
mWakeLock.setAcquired(false);
}
if (!mVisible) {
return;
}
@@ -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;
}

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 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);
final boolean hasIcon = indication != null && indication.getIcon() != null;
final AnimatorSet animSet = new AnimatorSet();
final AnimatorSet.Builder animSetBuilder = animSet.play(getOutAnimator());
if (animate) {
final boolean hasIcon = indication != null && indication.getIcon() != null;
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
// 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.setStartDelay(delay);
animator.start();
} else {
setAlpha(1f);
setTranslationY(0f);
setNextIndication();
if (onAnimationEndCallback != null) {
onAnimationEndCallback.run();
}
}
animSet.setStartDelay(delay);
animSet.start();
}
private AnimatorSet getOutAnimator() {
@@ -143,29 +184,8 @@ public class KeyguardIndicationTextView extends TextView {
fadeOut.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
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());
super.onAnimationEnd(animator);
setNextIndication();
}
});
@@ -177,6 +197,32 @@ public class KeyguardIndicationTextView extends TextView {
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() {
AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(this, View.ALPHA, 1f);
@@ -190,6 +236,7 @@ public class KeyguardIndicationTextView extends TextView {
yTranslate.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
setTranslationY(0);
}
});

View File

@@ -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;
@@ -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());
// THEN wake lock is held while the animation is running
assertTrue("WakeLock expected: HELD, was: RELEASED", mWakeLock.isHeld());
}
@Test
public void transientIndication_releasesWakeLock_afterHiding() {
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.hideTransientIndication();
assertFalse(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]);
// THEN wake lock is RELEASED, not held
assertFalse("WakeLock expected: RELEASED, was: HELD", mWakeLock.isHeld());
}
@Test