From 1c80dfe0d687460a42500848eb386cb111623a8d Mon Sep 17 00:00:00 2001 From: Beverly Date: Fri, 21 Apr 2023 13:51:00 +0000 Subject: [PATCH] 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 --- ...ardIndicationRotateTextViewController.java | 11 +++- .../KeyguardIndicationController.java | 3 ++ .../android/systemui/util/ViewController.java | 5 ++ ...ndicationRotateTextViewControllerTest.java | 50 +++++++++++++++++++ .../KeyguardIndicationControllerTest.java | 15 ++++++ 5 files changed, 83 insertions(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java index d3fe2c5c48f79..8c0cfba5aea89 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.os.SystemClock; 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 @@ public class KeyguardIndicationRotateTextViewController extends // 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 mIndicationQueue = new ArrayList<>(); @@ -111,6 +114,12 @@ public class KeyguardIndicationRotateTextViewController extends 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 142689e88b51d..ea5a1c0fbe704 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 @@ public class KeyguardIndicationController { 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 0dd5788105b71..1f118d11a44b7 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 @@ public abstract class ViewController { } } + /** 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 c3b0e5226a64d..d934f761f7c52 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.KeyguardIndicationRotateTextViewCont 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; @@ -87,6 +89,54 @@ public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCas mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue(); } + @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 4438b98f6fad8..f7fcab1b769b9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java @@ -324,6 +324,21 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { reset(mRotateTextViewController); } + @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();