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();