Merge "[Settings] Code refactor for performance"
diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
index e48d745..691cbd6 100644
--- a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
+++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
@@ -51,6 +51,8 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 @SearchIndexable
 public class MyDeviceInfoFragment extends DashboardFragment
@@ -105,14 +107,9 @@
             Context context, MyDeviceInfoFragment fragment, Lifecycle lifecycle) {
         final List<AbstractPreferenceController> controllers = new ArrayList<>();
 
-        final SlotSimStatus slotSimStatus = new SlotSimStatus(context);
-        for (int slotIndex = 0; slotIndex < slotSimStatus.size(); slotIndex ++) {
-            SimStatusPreferenceController slotRecord =
-                    new SimStatusPreferenceController(context,
-                    slotSimStatus.getPreferenceKey(slotIndex));
-            slotRecord.init(fragment, slotSimStatus);
-            controllers.add(slotRecord);
-        }
+        final ExecutorService executor = (fragment == null) ? null :
+                Executors.newSingleThreadExecutor();
+        final SlotSimStatus slotSimStatus = new SlotSimStatus(context, executor);
 
         controllers.add(new IpAddressPreferenceController(context, lifecycle));
         controllers.add(new WifiMacAddressPreferenceController(context, lifecycle));
@@ -123,6 +120,17 @@
         controllers.add(new FeedbackPreferenceController(fragment, context));
         controllers.add(new FccEquipmentIdPreferenceController(context));
         controllers.add(new UptimePreferenceController(context, lifecycle));
+
+        for (int slotIndex = 0; slotIndex < slotSimStatus.size(); slotIndex ++) {
+            SimStatusPreferenceController slotRecord =
+                    new SimStatusPreferenceController(context,
+                    slotSimStatus.getPreferenceKey(slotIndex));
+            slotRecord.init(fragment, slotSimStatus);
+            controllers.add(slotRecord);
+        }
+        if (executor != null) {
+            executor.shutdown();
+        }
         return controllers;
     }
 
diff --git a/src/com/android/settings/deviceinfo/simstatus/SlotSimStatus.java b/src/com/android/settings/deviceinfo/simstatus/SlotSimStatus.java
index 7056181..033222a 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SlotSimStatus.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SlotSimStatus.java
@@ -21,6 +21,10 @@
 import android.telephony.SubscriptionManager;
 import android.util.Log;
 
+import java.util.concurrent.Executor;
+import java.util.concurrent.Phaser;
+import java.util.concurrent.atomic.AtomicInteger;
+
 /**
  * A class for showing a summary of status of sim slots.
  */
@@ -28,7 +32,8 @@
 
     private static final String TAG = "SlotSimStatus";
 
-    private int mNumberOfSlots;
+    private final AtomicInteger mNumberOfSlots = new AtomicInteger(0);
+    private final Phaser mBlocker = new Phaser(1);
     private int mBasePreferenceOrdering;
 
     private static final String KEY_SIM_STATUS = "sim_status";
@@ -38,11 +43,32 @@
      * @param context Context
      */
     public SlotSimStatus(Context context) {
-        TelephonyManager telMgr = context.getSystemService(TelephonyManager.class);
-        if (telMgr == null) {
-            return;
+        this(context, null);
+    }
+
+    /**
+     * Construct of class.
+     * @param context Context
+     * @param executor executor for offload to thread
+     */
+    public SlotSimStatus(Context context, Executor executor) {
+        if (executor == null) {
+            queryRecords(context);
+        } else {
+            executor.execute(() -> queryRecords(context));
         }
-        mNumberOfSlots = telMgr.getPhoneCount();
+    }
+
+    protected void queryRecords(Context context) {
+        TelephonyManager telMgr = context.getSystemService(TelephonyManager.class);
+        if (telMgr != null) {
+            mNumberOfSlots.set(telMgr.getPhoneCount());
+        }
+        mBlocker.arrive();
+    }
+
+    protected void waitForResult() {
+        mBlocker.awaitAdvance(0);
     }
 
     /**
@@ -58,7 +84,8 @@
      * @return number of slots
      */
     public int size() {
-        return mNumberOfSlots;
+        waitForResult();
+        return mNumberOfSlots.get();
     }
 
     /**
diff --git a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SlotSimStatusTest.java b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SlotSimStatusTest.java
index 1a4e740..71f0faf 100644
--- a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SlotSimStatusTest.java
+++ b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SlotSimStatusTest.java
@@ -33,6 +33,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
 @RunWith(AndroidJUnit4.class)
 public class SlotSimStatusTest {
 
@@ -59,6 +62,16 @@
     }
 
     @Test
+    public void size_returnNumberOfPhone_whenQueryInBackgroundThread() {
+        doReturn(2).when(mTelephonyManager).getPhoneCount();
+
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        SlotSimStatus target = new SlotSimStatus(mContext, executor);
+
+        assertEquals(new Integer(target.size()), new Integer(2));
+    }
+
+    @Test
     public void getPreferenceOrdering_returnOrdering_whenQuery() {
         doReturn(2).when(mTelephonyManager).getPhoneCount();