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