Merge "Unregister listeners and reset wake lock" into qt-dev
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index d4c7366..2047797 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -104,15 +104,19 @@
     private final AlarmManager.OnAlarmListener mUpdateNextAlarm = this::updateNextAlarm;
     private final HashSet<Integer> mMediaInvisibleStates;
     private final Object mMediaToken = new Object();
-    private SettableWakeLock mMediaWakeLock;
-    private ZenModeController mZenModeController;
+    @VisibleForTesting
+    protected SettableWakeLock mMediaWakeLock;
+    @VisibleForTesting
+    protected ZenModeController mZenModeController;
     private String mDatePattern;
     private DateFormat mDateFormat;
     private String mLastText;
     private boolean mRegistered;
     private String mNextAlarm;
     private NextAlarmController mNextAlarmController;
+    @VisibleForTesting
     protected AlarmManager mAlarmManager;
+    @VisibleForTesting
     protected ContentResolver mContentResolver;
     private AlarmManager.AlarmClockInfo mNextAlarmInfo;
     private PendingIntent mPendingIntent;
@@ -297,22 +301,44 @@
 
     @Override
     public boolean onCreateSliceProvider() {
-        mAlarmManager = getContext().getSystemService(AlarmManager.class);
-        mContentResolver = getContext().getContentResolver();
-        mNextAlarmController = new NextAlarmControllerImpl(getContext());
-        mNextAlarmController.addCallback(this);
-        mZenModeController = new ZenModeControllerImpl(getContext(), mHandler);
-        mZenModeController.addCallback(this);
-        mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
-        mPendingIntent = PendingIntent.getActivity(getContext(), 0, new Intent(), 0);
-        mMediaWakeLock = new SettableWakeLock(WakeLock.createPartial(getContext(), "media"),
-                "media");
-        KeyguardSliceProvider.sInstance = this;
-        registerClockUpdate();
-        updateClockLocked();
+        synchronized (this) {
+            KeyguardSliceProvider oldInstance = KeyguardSliceProvider.sInstance;
+            if (oldInstance != null) {
+                oldInstance.onDestroy();
+            }
+
+            mAlarmManager = getContext().getSystemService(AlarmManager.class);
+            mContentResolver = getContext().getContentResolver();
+            mNextAlarmController = new NextAlarmControllerImpl(getContext());
+            mNextAlarmController.addCallback(this);
+            mZenModeController = new ZenModeControllerImpl(getContext(), mHandler);
+            mZenModeController.addCallback(this);
+            mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
+            mPendingIntent = PendingIntent.getActivity(getContext(), 0, new Intent(), 0);
+            mMediaWakeLock = new SettableWakeLock(WakeLock.createPartial(getContext(), "media"),
+                    "media");
+            KeyguardSliceProvider.sInstance = this;
+            registerClockUpdate();
+            updateClockLocked();
+        }
         return true;
     }
 
+    @VisibleForTesting
+    protected void onDestroy() {
+        synchronized (this) {
+            mNextAlarmController.removeCallback(this);
+            mZenModeController.removeCallback(this);
+            mMediaWakeLock.setAcquired(false);
+            mAlarmManager.cancel(mUpdateNextAlarm);
+            if (mRegistered) {
+                mRegistered = false;
+                getKeyguardUpdateMonitor().removeCallback(mKeyguardUpdateMonitorCallback);
+                getContext().unregisterReceiver(mIntentReceiver);
+            }
+        }
+    }
+
     @Override
     public void onZenChanged(int zen) {
         notifyChange();
@@ -350,7 +376,8 @@
      * Registers a broadcast receiver for clock updates, include date, time zone and manually
      * changing the date/time via the settings app.
      */
-    private void registerClockUpdate() {
+    @VisibleForTesting
+    protected void registerClockUpdate() {
         synchronized (this) {
             if (mRegistered) {
                 return;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index 355e260..857f50c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -48,6 +48,9 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.util.wakelock.SettableWakeLock;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -73,6 +76,14 @@
     private NotificationMediaManager mNotificationMediaManager;
     @Mock
     private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private KeyguardBypassController mKeyguardBypassController;
+    @Mock
+    private ZenModeController mZenModeController;
+    @Mock
+    private SettableWakeLock mMediaWakeLock;
+    @Mock
+    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private TestableKeyguardSliceProvider mProvider;
     private boolean mIsZenMode;
 
@@ -194,6 +205,20 @@
         verify(mContentResolver, never()).notifyChange(eq(mProvider.getUri()), eq(null));
     }
 
+    @Test
+    public void onDestroy_noCrash() {
+        mProvider.onDestroy();
+    }
+
+    @Test
+    public void onDestroy_unregisterListeners() {
+        mProvider.registerClockUpdate();
+        mProvider.onDestroy();
+        verify(mMediaWakeLock).setAcquired(eq(false));
+        verify(mAlarmManager).cancel(any(AlarmManager.OnAlarmListener.class));
+        verify(mKeyguardUpdateMonitor).removeCallback(any());
+    }
+
     private class TestableKeyguardSliceProvider extends KeyguardSliceProvider {
         int mCleanDateFormatInvokations;
         private int mCounter;
@@ -207,6 +232,8 @@
             super.onCreateSliceProvider();
             mAlarmManager = KeyguardSliceProviderTest.this.mAlarmManager;
             mContentResolver = KeyguardSliceProviderTest.this.mContentResolver;
+            mZenModeController = KeyguardSliceProviderTest.this.mZenModeController;
+            mMediaWakeLock = KeyguardSliceProviderTest.this.mMediaWakeLock;
             return true;
         }
 
@@ -223,7 +250,7 @@
 
         @Override
         public KeyguardUpdateMonitor getKeyguardUpdateMonitor() {
-            return mock(KeyguardUpdateMonitor.class);
+            return mKeyguardUpdateMonitor;
         }
 
         @Override