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
This commit is contained in:
Beverly
2023-04-21 13:51:00 +00:00
committed by Beverly Tai
parent e691f5963e
commit 1c80dfe0d6
5 changed files with 83 additions and 1 deletions

View File

@@ -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<Integer> 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

View File

@@ -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,

View File

@@ -109,6 +109,11 @@ public abstract class ViewController<T extends View> {
}
}
/** 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.
*/

View File

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

View File

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