Merge "[Settings] Code refactor for availability session"
diff --git a/src/com/android/settings/network/telephony/AbstractMobileNetworkSettings.java b/src/com/android/settings/network/telephony/AbstractMobileNetworkSettings.java
new file mode 100644
index 0000000..889fbae
--- /dev/null
+++ b/src/com/android/settings/network/telephony/AbstractMobileNetworkSettings.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.telephony;
+
+import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+abstract class AbstractMobileNetworkSettings extends RestrictedDashboardFragment {
+
+    private static final String LOG_TAG = "AbsNetworkSettings";
+
+    /**
+     * @param restrictionKey The restriction key to check before pin protecting
+     *            this settings page. Pass in {@link RESTRICT_IF_OVERRIDABLE} if it should
+     *            be protected whenever a restrictions provider is set. Pass in
+     *            null if it should never be protected.
+     */
+    AbstractMobileNetworkSettings(String restrictionKey) {
+        super(restrictionKey);
+    }
+
+    List<AbstractPreferenceController> getPreferenceControllersAsList() {
+        final List<AbstractPreferenceController> result =
+                new ArrayList<AbstractPreferenceController>();
+        getPreferenceControllers().forEach(controllers -> result.addAll(controllers));
+        return result;
+    }
+
+    TelephonyStatusControlSession setTelephonyAvailabilityStatus(
+            Collection<AbstractPreferenceController> listOfPrefControllers) {
+        return (new TelephonyStatusControlSession.Builder(listOfPrefControllers))
+                .build();
+    }
+
+}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index d5e6f5e..a9148dd 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -40,7 +40,6 @@
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.FeatureFlags;
-import com.android.settings.dashboard.RestrictedDashboardFragment;
 import com.android.settings.datausage.BillingCyclePreferenceController;
 import com.android.settings.datausage.DataUsageSummaryPreferenceController;
 import com.android.settings.development.featureflags.FeatureFlagPersistent;
@@ -66,7 +65,7 @@
 import androidx.preference.Preference;
 
 @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
-public class MobileNetworkSettings extends RestrictedDashboardFragment {
+public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
 
     private static final String LOG_TAG = "NetworkSettings";
     public static final int REQUEST_CODE_EXIT_ECM = 17;
@@ -197,11 +196,8 @@
     public void onCreate(Bundle icicle) {
         Log.i(LOG_TAG, "onCreate:+");
 
-        final Collection<List<AbstractPreferenceController>> controllerLists =
-                getPreferenceControllers();
-        final Future<Boolean> result = ThreadUtils.postOnBackgroundThread(() ->
-                setupAvailabilityStatus(controllerLists)
-        );
+        final TelephonyStatusControlSession session =
+                setTelephonyAvailabilityStatus(getPreferenceControllersAsList());
 
         super.onCreate(icicle);
         final Context context = getContext();
@@ -209,46 +205,11 @@
         mTelephonyManager = context.getSystemService(TelephonyManager.class)
                 .createForSubscriptionId(mSubId);
 
-        // Check the background thread is finished then unset the status of availability.
-        try {
-            result.get();
-        } catch (ExecutionException | InterruptedException exception) {
-            Log.e(LOG_TAG, "onCreate, setup availability status failed!", exception);
-        }
-        unsetAvailabilityStatus(controllerLists);
+        session.close();
 
         onRestoreInstance(icicle);
     }
 
-    private Boolean setupAvailabilityStatus(
-            Collection<List<AbstractPreferenceController>> controllerLists) {
-        try {
-            controllerLists.stream().flatMap(Collection::stream)
-                    .filter(controller -> controller instanceof TelephonyAvailabilityHandler)
-                    .map(TelephonyAvailabilityHandler.class::cast)
-                    .forEach(controller -> {
-                        int status = ((BasePreferenceController) controller)
-                                .getAvailabilityStatus();
-                        controller.unsetAvailabilityStatus(true);
-                        controller.setAvailabilityStatus(status);
-                    });
-            return true;
-        } catch (Exception exception) {
-            Log.e(LOG_TAG, "Setup availability status failed!", exception);
-            return false;
-        }
-    }
-
-    private void unsetAvailabilityStatus(
-            Collection<List<AbstractPreferenceController>> controllerLists) {
-        controllerLists.stream().flatMap(Collection::stream)
-                .filter(controller -> controller instanceof TelephonyAvailabilityHandler)
-                .map(TelephonyAvailabilityHandler.class::cast)
-                .forEach(controller -> {
-                    controller.unsetAvailabilityStatus(false);
-                });
-    }
-
     @Override
     public void onExpandButtonClick() {
         final PreferenceScreen screen = getPreferenceScreen();
diff --git a/src/com/android/settings/network/telephony/TelephonyAvailabilityHandler.java b/src/com/android/settings/network/telephony/TelephonyAvailabilityHandler.java
index 50dd26b..c1acd91 100644
--- a/src/com/android/settings/network/telephony/TelephonyAvailabilityHandler.java
+++ b/src/com/android/settings/network/telephony/TelephonyAvailabilityHandler.java
@@ -25,14 +25,16 @@
 public interface TelephonyAvailabilityHandler {
 
     /**
-     * Set availability to preference controller.
+     * Set availability status of preference controller to a fixed value.
+     * @param status is the given status. Which will be reported from
+     * {@link BasePreferenceController#getAvailabilityStatus()}
      */
-    public void setAvailabilityStatus(int status);
+    void setAvailabilityStatus(int status);
 
     /**
      * Do not set availability, use
      * {@link MobileNetworkUtils#getAvailability(Context, int, TelephonyAvailabilityCallback)}
      * to get the availability.
      */
-    public void unsetAvailabilityStatus(boolean enable);
+    void unsetAvailabilityStatus();
 }
diff --git a/src/com/android/settings/network/telephony/TelephonyBasePreferenceController.java b/src/com/android/settings/network/telephony/TelephonyBasePreferenceController.java
index 678209d..2bd7de9 100644
--- a/src/com/android/settings/network/telephony/TelephonyBasePreferenceController.java
+++ b/src/com/android/settings/network/telephony/TelephonyBasePreferenceController.java
@@ -23,7 +23,6 @@
 
 import com.android.settings.core.BasePreferenceController;
 
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -33,7 +32,7 @@
         implements TelephonyAvailabilityCallback, TelephonyAvailabilityHandler {
     protected int mSubId;
     private AtomicInteger mAvailabilityStatus = new AtomicInteger(0);
-    private AtomicBoolean mUnsetAvailabilityStatus = new AtomicBoolean(false);
+    private AtomicInteger mSetSessionCount = new AtomicInteger(0);
 
     public TelephonyBasePreferenceController(Context context, String preferenceKey) {
         super(context, preferenceKey);
@@ -42,7 +41,7 @@
 
     @Override
     public int getAvailabilityStatus() {
-        if (!mUnsetAvailabilityStatus.get()) {
+        if (mSetSessionCount.get() <= 0) {
             mAvailabilityStatus.set(MobileNetworkUtils
                     .getAvailability(mContext, mSubId, this::getAvailabilityStatus));
         }
@@ -52,11 +51,12 @@
     @Override
     public void setAvailabilityStatus(int status) {
         mAvailabilityStatus.set(status);
+        mSetSessionCount.getAndIncrement();
     }
 
     @Override
-    public void unsetAvailabilityStatus(boolean enable) {
-        mUnsetAvailabilityStatus.set(enable);
+    public void unsetAvailabilityStatus() {
+        mSetSessionCount.getAndDecrement();
     }
 
     /**
diff --git a/src/com/android/settings/network/telephony/TelephonyStatusControlSession.java b/src/com/android/settings/network/telephony/TelephonyStatusControlSession.java
new file mode 100644
index 0000000..12c9bee
--- /dev/null
+++ b/src/com/android/settings/network/telephony/TelephonyStatusControlSession.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.telephony;
+
+import android.util.Log;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.utils.ThreadUtils;
+
+import java.util.Collection;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+/**
+ * Session for controlling the status of TelephonyPreferenceController(s).
+ *
+ * Within this session, result of {@link BasePreferenceController#availabilityStatus()}
+ * would be under control.
+ */
+public class TelephonyStatusControlSession implements AutoCloseable {
+
+    private static final String LOG_TAG = "TelephonyStatusControlSS";
+
+    private Collection<AbstractPreferenceController> mControllers;
+    private Future<Boolean> mResult;
+
+    /**
+     * Buider of session
+     */
+    public static class Builder {
+        private Collection<AbstractPreferenceController> mControllers;
+
+        /**
+         * Constructor
+         *
+         * @param controllers is a collection of {@link AbstractPreferenceController}
+         *        which would have {@link BasePreferenceController#availabilityStatus()}
+         *        under control within this session.
+         */
+        public Builder(Collection<AbstractPreferenceController> controllers) {
+            mControllers = controllers;
+        }
+
+        /**
+         * Method to build this session.
+         * @return {@link TelephonyStatusControlSession} session been setup.
+         */
+        public TelephonyStatusControlSession build() {
+            return new TelephonyStatusControlSession(mControllers);
+        }
+    }
+
+    private TelephonyStatusControlSession(Collection<AbstractPreferenceController> controllers) {
+        mControllers = controllers;
+        mResult = ThreadUtils.postOnBackgroundThread(() ->
+            setupAvailabilityStatus(controllers)
+        );
+    }
+
+    /**
+     * Close the session.
+     *
+     * No longer control the status.
+     */
+    public void close() {
+        //check the background thread is finished then unset the status of availability.
+        try {
+            mResult.get();
+        } catch (ExecutionException | InterruptedException exception) {
+            Log.e(LOG_TAG, "setup availability status failed!", exception);
+        }
+        unsetAvailabilityStatus(mControllers);
+    }
+
+    private Boolean setupAvailabilityStatus(
+            Collection<AbstractPreferenceController> controllerLists) {
+        try {
+            controllerLists.stream()
+                    .filter(controller -> controller instanceof TelephonyAvailabilityHandler)
+                    .map(TelephonyAvailabilityHandler.class::cast)
+                    .forEach(controller -> {
+                        int status = ((BasePreferenceController) controller)
+                                .getAvailabilityStatus();
+                        controller.setAvailabilityStatus(status);
+                    });
+            return true;
+        } catch (Exception exception) {
+            Log.e(LOG_TAG, "Setup availability status failed!", exception);
+            return false;
+        }
+    }
+
+    private void unsetAvailabilityStatus(
+            Collection<AbstractPreferenceController> controllerLists) {
+        controllerLists.stream()
+                .filter(controller -> controller instanceof TelephonyAvailabilityHandler)
+                .map(TelephonyAvailabilityHandler.class::cast)
+                .forEach(controller -> {
+                    controller.unsetAvailabilityStatus();
+                });
+    }
+}
diff --git a/src/com/android/settings/network/telephony/TelephonyTogglePreferenceController.java b/src/com/android/settings/network/telephony/TelephonyTogglePreferenceController.java
index 56d51eb..ecad755 100644
--- a/src/com/android/settings/network/telephony/TelephonyTogglePreferenceController.java
+++ b/src/com/android/settings/network/telephony/TelephonyTogglePreferenceController.java
@@ -23,7 +23,6 @@
 
 import com.android.settings.core.TogglePreferenceController;
 
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -33,8 +32,7 @@
         implements TelephonyAvailabilityCallback, TelephonyAvailabilityHandler {
     protected int mSubId;
     private AtomicInteger mAvailabilityStatus = new AtomicInteger(0);
-    private AtomicBoolean mUnsetAvailabilityStatus = new AtomicBoolean(false);
-
+    private AtomicInteger mSetSessionCount = new AtomicInteger(0);
 
     public TelephonyTogglePreferenceController(Context context, String preferenceKey) {
         super(context, preferenceKey);
@@ -43,7 +41,7 @@
 
     @Override
     public int getAvailabilityStatus() {
-        if (!mUnsetAvailabilityStatus.get()) {
+        if (mSetSessionCount.get() <= 0) {
             mAvailabilityStatus.set(MobileNetworkUtils
                     .getAvailability(mContext, mSubId, this::getAvailabilityStatus));
         }
@@ -53,13 +51,15 @@
     @Override
     public void setAvailabilityStatus(int status) {
         mAvailabilityStatus.set(status);
+        mSetSessionCount.getAndIncrement();
     }
 
     @Override
-    public void unsetAvailabilityStatus(boolean enable) {
-        mUnsetAvailabilityStatus.set(enable);
+    public void unsetAvailabilityStatus() {
+        mSetSessionCount.getAndDecrement();
     }
 
+
     /**
      * Get carrier config based on specific subscription id.
      *