Cleanup listener reference in Screen Attention

This will fix a memory leak being caused by dangling listeners.

Test: locally with oriole, make RunSettingsRoboTests -j$(nproc) ROBOTEST_FILTER=AdaptiveSleepCameraStatePreferenceControllerTest,AdaptiveSleepPreferenceControllerTest

Bug: 245990072
Change-Id: I35eeedc3ece719f1f3baff6235cc5ac2d42fbba3
diff --git a/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java b/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java
index 4963e2f..a7bbdff 100644
--- a/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java
+++ b/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java
@@ -19,9 +19,15 @@
 import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
 import static android.hardware.SensorPrivacyManager.Sources.DIALOG;
 
+import static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
 import android.content.Context;
 import android.hardware.SensorPrivacyManager;
 
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
 import androidx.preference.PreferenceScreen;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -32,17 +38,34 @@
  * The controller of Screen attention's camera disabled warning preference.
  * The preference appears when the camera access is disabled for Screen Attention feature.
  */
-public class AdaptiveSleepCameraStatePreferenceController {
+public class AdaptiveSleepCameraStatePreferenceController implements LifecycleObserver {
     @VisibleForTesting
     BannerMessagePreference mPreference;
     private final SensorPrivacyManager mPrivacyManager;
     private final Context mContext;
 
-    public AdaptiveSleepCameraStatePreferenceController(Context context) {
+    private final SensorPrivacyManager.OnSensorPrivacyChangedListener mPrivacyChangedListener =
+            new SensorPrivacyManager.OnSensorPrivacyChangedListener() {
+                @Override
+                public void onSensorPrivacyChanged(int sensor, boolean enabled) {
+                    updateVisibility();
+                }
+            };
+
+    public AdaptiveSleepCameraStatePreferenceController(Context context, Lifecycle lifecycle) {
         mPrivacyManager = SensorPrivacyManager.getInstance(context);
-        mPrivacyManager.addSensorPrivacyListener(CAMERA,
-                (sensor, enabled) -> updateVisibility());
         mContext = context;
+        lifecycle.addObserver(this);
+    }
+
+    @OnLifecycleEvent(ON_START)
+    public void onStart() {
+        mPrivacyManager.addSensorPrivacyListener(CAMERA, mPrivacyChangedListener);
+    }
+
+    @OnLifecycleEvent(ON_STOP)
+    public void onStop() {
+        mPrivacyManager.removeSensorPrivacyListener(CAMERA, mPrivacyChangedListener);
     }
 
     /**
@@ -55,7 +78,7 @@
     }
 
     /**
-     * Need this because all controller tests use RoboElectric. No easy way to mock this service,
+     * Need this because all controller tests use Robolectric. No easy way to mock this service,
      * so we mock the call we need
      */
     @VisibleForTesting
diff --git a/src/com/android/settings/display/ScreenTimeoutSettings.java b/src/com/android/settings/display/ScreenTimeoutSettings.java
index 2fc0164..8ca8e0e 100644
--- a/src/com/android/settings/display/ScreenTimeoutSettings.java
+++ b/src/com/android/settings/display/ScreenTimeoutSettings.java
@@ -81,6 +81,7 @@
     };
 
     private DevicePolicyManager mDevicePolicyManager;
+    private SensorPrivacyManager.OnSensorPrivacyChangedListener mPrivacyChangedListener;
 
     @VisibleForTesting
     Context mContext;
@@ -120,7 +121,7 @@
         mAdaptiveSleepPermissionController = new AdaptiveSleepPermissionPreferenceController(
                 context);
         mAdaptiveSleepCameraStatePreferenceController =
-                new AdaptiveSleepCameraStatePreferenceController(context);
+                new AdaptiveSleepCameraStatePreferenceController(context, getLifecycle());
         mAdaptiveSleepBatterySaverPreferenceController =
                 new AdaptiveSleepBatterySaverPreferenceController(context);
         mPrivacyPreference = new FooterPreference(context);
@@ -129,8 +130,7 @@
         mPrivacyPreference.setSelectable(false);
         mPrivacyPreference.setLayoutResource(R.layout.preference_footer);
         mPrivacyManager = SensorPrivacyManager.getInstance(context);
-        mPrivacyManager.addSensorPrivacyListener(CAMERA,
-                (sensor, enabled) -> mAdaptiveSleepController.updatePreference());
+        mPrivacyChangedListener = (sensor, enabled) -> mAdaptiveSleepController.updatePreference();
     }
 
     @Override
@@ -159,12 +159,14 @@
         mAdaptiveSleepController.updatePreference();
         mContext.registerReceiver(mReceiver,
                 new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
+        mPrivacyManager.addSensorPrivacyListener(CAMERA, mPrivacyChangedListener);
     }
 
     @Override
     public void onStop() {
         super.onStop();
         mContext.unregisterReceiver(mReceiver);
+        mPrivacyManager.removeSensorPrivacyListener(CAMERA, mPrivacyChangedListener);
     }
 
     @Override
diff --git a/tests/robotests/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceControllerTest.java
index 282335b..f328312 100644
--- a/tests/robotests/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceControllerTest.java
@@ -28,6 +28,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 
+import androidx.lifecycle.Lifecycle;
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager;
@@ -50,6 +51,8 @@
     private PackageManager mPackageManager;
     @Mock
     private PreferenceScreen mScreen;
+    @Mock
+    private Lifecycle mLifecycle;
 
     @Before
     public void setUp() {
@@ -61,7 +64,7 @@
         when(mPackageManager.checkPermission(any(), any())).thenReturn(
                 PackageManager.PERMISSION_GRANTED);
 
-        mController = new AdaptiveSleepCameraStatePreferenceController(mContext);
+        mController = new AdaptiveSleepCameraStatePreferenceController(mContext, mLifecycle);
         when(mController.isCameraLocked()).thenReturn(false);
     }