Only ONE view controller controls KeyguardIndication
If a new keyguard indication area is being set,
destroy the old RotateTextViewController so that
there's only one KeyguardIndicationRotateTextViewController
for the keyguard indication view.
The stale RotateTextViewController was causing an old charging
message to surface on LS.
Test: atest KeyguardIndicationControllerTest KeyguardIndicationRotateTextViewController
Fixes: 279115823
Change-Id: Ic9735f0029e2055948542eaee75b6befbedea892
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
index d3fe2c5..8c0cfba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
@@ -23,6 +23,7 @@
import android.text.TextUtils;
import androidx.annotation.IntDef;
+import androidx.annotation.VisibleForTesting;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.Dumpable;
@@ -74,7 +75,9 @@
// Executor that will show the next message after a delay
private final DelayableExecutor mExecutor;
- @Nullable private ShowNextIndication mShowNextIndicationRunnable;
+
+ @VisibleForTesting
+ @Nullable ShowNextIndication mShowNextIndicationRunnable;
// List of indication types to show. The next indication to show is always at index 0
private final List<Integer> mIndicationQueue = new ArrayList<>();
@@ -111,6 +114,12 @@
cancelScheduledIndication();
}
+ /** Destroy ViewController, removing any listeners. */
+ public void destroy() {
+ super.destroy();
+ onViewDetached();
+ }
+
/**
* Update the indication type with the given String.
* @param type of indication
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 142689e..ea5a1c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -335,6 +335,9 @@
R.id.keyguard_indication_text_bottom);
mInitialTextColorState = mTopIndicationView != null
? mTopIndicationView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
+ if (mRotateTextViewController != null) {
+ mRotateTextViewController.destroy();
+ }
mRotateTextViewController = new KeyguardIndicationRotateTextViewController(
mLockScreenIndicationView,
mExecutor,
diff --git a/packages/SystemUI/src/com/android/systemui/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
index 0dd5788..1f118d1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
@@ -109,6 +109,11 @@
}
}
+ /** Destroy ViewController, removing any listeners. */
+ public void destroy() {
+ mView.removeOnAttachStateChangeListener(mOnAttachStateListener);
+ }
+
/**
* Called when the view is attached and a call to {@link #init()} has been made in either order.
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
index c3b0e5226..d934f76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
@@ -23,9 +23,11 @@
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
@@ -88,6 +90,54 @@
}
@Test
+ public void onViewDetached_removesStatusBarStateListener() {
+ mController.onViewDetached();
+ verify(mStatusBarStateController).removeCallback(mStatusBarStateListener);
+ }
+
+ @Test
+ public void onViewDetached_removesAllScheduledIndications() {
+ // GIVEN show next indication runnable is set
+ final KeyguardIndicationRotateTextViewController.ShowNextIndication mockShowNextIndication =
+ mock(KeyguardIndicationRotateTextViewController.ShowNextIndication.class);
+ mController.mShowNextIndicationRunnable = mockShowNextIndication;
+
+ // WHEN the view is detached
+ mController.onViewDetached();
+
+ // THEN delayed execution is cancelled & runnable set to null
+ verify(mockShowNextIndication).cancelDelayedExecution();
+ assertNull(mController.mShowNextIndicationRunnable);
+ }
+
+ @Test
+ public void destroy_removesStatusBarStateListener() {
+ mController.destroy();
+ verify(mStatusBarStateController).removeCallback(mStatusBarStateListener);
+ }
+
+ @Test
+ public void destroy_removesOnAttachStateChangeListener() {
+ mController.destroy();
+ verify(mView).removeOnAttachStateChangeListener(any());
+ }
+
+ @Test
+ public void destroy_removesAllScheduledIndications() {
+ // GIVEN show next indication runnable is set
+ final KeyguardIndicationRotateTextViewController.ShowNextIndication mockShowNextIndication =
+ mock(KeyguardIndicationRotateTextViewController.ShowNextIndication.class);
+ mController.mShowNextIndicationRunnable = mockShowNextIndication;
+
+ // WHEN the controller is destroyed
+ mController.destroy();
+
+ // THEN delayed execution is cancelled & runnable set to null
+ verify(mockShowNextIndication).cancelDelayedExecution();
+ assertNull(mController.mShowNextIndicationRunnable);
+ }
+
+ @Test
public void testInitialState_noIndication() {
assertFalse(mController.hasIndications());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 4438b98..f7fcab1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -325,6 +325,21 @@
}
@Test
+ public void createController_setIndicationAreaAgain_destroysPreviousRotateTextViewController() {
+ // GIVEN a controller with a mocked rotate text view controlller
+ final KeyguardIndicationRotateTextViewController mockedRotateTextViewController =
+ mock(KeyguardIndicationRotateTextViewController.class);
+ createController();
+ mController.mRotateTextViewController = mockedRotateTextViewController;
+
+ // WHEN a new indication area is set
+ mController.setIndicationArea(mIndicationArea);
+
+ // THEN the previous rotateTextViewController is destroyed
+ verify(mockedRotateTextViewController).destroy();
+ }
+
+ @Test
public void createController_addsAlignmentListener() {
createController();