Fix NPE with registering content listener

1) Fix the condition to check either subscribed or null.
2) Don't register listeners unless the feature flag is enabled

Test: make RunSettingsRoboTest
Bug: 267357231
Change-Id: I0134812cbac60c394d96c5a5621a7c16d781b05d
diff --git a/src/com/android/settings/biometrics/activeunlock/ActiveUnlockContentListener.java b/src/com/android/settings/biometrics/activeunlock/ActiveUnlockContentListener.java
index c2a8f39..8cc7d6a 100644
--- a/src/com/android/settings/biometrics/activeunlock/ActiveUnlockContentListener.java
+++ b/src/com/android/settings/biometrics/activeunlock/ActiveUnlockContentListener.java
@@ -87,10 +87,10 @@
 
     }
 
-    /** Starts listening for updates from the ContentProvider, and fetches the current value. */
-    public synchronized void subscribe() {
-        if (mSubscribed && mUri != null) {
-            return;
+    /** Returns true if start listening for updates from the ContentProvider, false otherwise. */
+    public synchronized boolean subscribe() {
+        if (mSubscribed || mUri == null) {
+            return false;
         }
         mSubscribed = true;
         mContext.getContentResolver().registerContentObserver(
@@ -99,15 +99,17 @@
                 () -> {
                     getContentFromUri();
                 });
+        return true;
     }
 
-    /** Stops listening for updates from the ContentProvider. */
-    public synchronized void unsubscribe() {
-        if (!mSubscribed && mUri != null) {
-            return;
+    /** Returns true if stops listening for updates from the ContentProvider, false otherewise. */
+    public synchronized boolean unsubscribe() {
+        if (!mSubscribed || mUri == null) {
+            return false;
         }
         mSubscribed = false;
         mContext.getContentResolver().unregisterContentObserver(mContentObserver);
+        return true;
     }
 
     /** Retrieves the most recently fetched value from the ContentProvider. */
diff --git a/src/com/android/settings/biometrics/activeunlock/ActiveUnlockStatusPreferenceController.java b/src/com/android/settings/biometrics/activeunlock/ActiveUnlockStatusPreferenceController.java
index 31c72ae..ff835f8 100644
--- a/src/com/android/settings/biometrics/activeunlock/ActiveUnlockStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/activeunlock/ActiveUnlockStatusPreferenceController.java
@@ -50,6 +50,7 @@
     private final CombinedBiometricStatusUtils mCombinedBiometricStatusUtils;
     private final ActiveUnlockSummaryListener mActiveUnlockSummaryListener;
     private final ActiveUnlockDeviceNameListener mActiveUnlockDeviceNameListener;
+    private final boolean mIsAvailable;
 
     public ActiveUnlockStatusPreferenceController(@NonNull Context context) {
         this(context, KEY_ACTIVE_UNLOCK_SETTINGS);
@@ -59,6 +60,7 @@
             @NonNull Context context, @NonNull String key) {
         super(context, key);
         mActiveUnlockStatusUtils = new ActiveUnlockStatusUtils(context);
+        mIsAvailable = mActiveUnlockStatusUtils.isAvailable();
         mCombinedBiometricStatusUtils = new CombinedBiometricStatusUtils(context, getUserId());
         OnContentChangedListener onSummaryChangedListener = new OnContentChangedListener() {
             @Override
@@ -90,8 +92,10 @@
     /** Subscribes to update preference summary dynamically. */
     @OnLifecycleEvent(Lifecycle.Event.ON_START)
     public void onStart() {
-        mActiveUnlockSummaryListener.subscribe();
-        mActiveUnlockDeviceNameListener.subscribe();
+        if (mIsAvailable) {
+            mActiveUnlockSummaryListener.subscribe();
+            mActiveUnlockDeviceNameListener.subscribe();
+        }
     }
 
     /** Resets the preference reference on resume. */
@@ -105,8 +109,10 @@
     /** Unsubscribes to prevent leaked listener. */
     @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
     public void onStop() {
-        mActiveUnlockSummaryListener.unsubscribe();
-        mActiveUnlockDeviceNameListener.unsubscribe();
+        if (mIsAvailable) {
+            mActiveUnlockSummaryListener.unsubscribe();
+            mActiveUnlockDeviceNameListener.unsubscribe();
+        }
     }
 
     @Override
@@ -127,7 +133,7 @@
         // This should never be called, as getAvailabilityStatus() will return the exact value.
         // However, this is an abstract method in BiometricStatusPreferenceController, and so
         // needs to be overridden.
-        return mActiveUnlockStatusUtils.isAvailable();
+        return mIsAvailable;
     }
 
     @Override
diff --git a/tests/robotests/src/com/android/settings/biometrics/activeunlock/ActiveUnlockContentListenerTest.java b/tests/robotests/src/com/android/settings/biometrics/activeunlock/ActiveUnlockContentListenerTest.java
index cb0c942..4da8151 100644
--- a/tests/robotests/src/com/android/settings/biometrics/activeunlock/ActiveUnlockContentListenerTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/activeunlock/ActiveUnlockContentListenerTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 import static org.robolectric.shadows.ShadowLooper.idleMainLooper;
@@ -43,6 +44,8 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
+import java.util.ArrayList;
+
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {ShadowDeviceConfig.class})
 public class ActiveUnlockContentListenerTest {
@@ -136,6 +139,26 @@
         assertThat(mUpdateCount).isEqualTo(1);
     }
 
+    @Test
+    public void noProvider_subscribeDoesntRegisterObserver() {
+        when(mPackageManager.getInstalledPackages(any()))
+                .thenReturn(new ArrayList<>());
+        OnContentChangedListener listener = new OnContentChangedListener() {
+            @Override
+            public void onContentChanged(String newValue) {}
+        };
+
+        ActiveUnlockContentListener contentListener =
+                new ActiveUnlockContentListener(
+                        mContext,
+                        listener,
+                        "logTag",
+                        FakeContentProvider.METHOD_SUMMARY,
+                        FakeContentProvider.KEY_SUMMARY);
+
+        assertThat(contentListener.subscribe()).isFalse();
+    }
+
     private void updateContent(String content) {
         FakeContentProvider.setTileSummary(content);
         mContext.getContentResolver().notifyChange(