[Settings] Move some work into background thread

1. Move some work into backgroud thread when query data usage status.
2. Fix test case

Bug: 141833767
Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=DataUsagePreferenceControllerTest
Change-Id: Ic1496323cd2bbaf794881394565d8d9bb0a89111
diff --git a/src/com/android/settings/network/telephony/DataUsagePreferenceController.java b/src/com/android/settings/network/telephony/DataUsagePreferenceController.java
index 4499881..035a8c1 100644
--- a/src/com/android/settings/network/telephony/DataUsagePreferenceController.java
+++ b/src/com/android/settings/network/telephony/DataUsagePreferenceController.java
@@ -22,22 +22,33 @@
 import android.provider.Settings;
 import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.preference.Preference;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
 import com.android.settings.datausage.DataUsageUtils;
 import com.android.settingslib.net.DataUsageController;
+import com.android.settingslib.utils.ThreadUtils;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Preference controller for "Data usage"
  */
 public class DataUsagePreferenceController extends TelephonyBasePreferenceController {
 
-    private NetworkTemplate mTemplate;
+    private static final String LOG_TAG = "DataUsagePreferCtrl";
+
+    private Future<NetworkTemplate> mTemplateFuture;
+    private AtomicReference<NetworkTemplate> mTemplate;
 
     public DataUsagePreferenceController(Context context, String key) {
         super(context, key);
+        mTemplate = new AtomicReference<NetworkTemplate>();
     }
 
     @Override
@@ -53,7 +64,7 @@
             return false;
         }
         final Intent intent = new Intent(Settings.ACTION_MOBILE_DATA_USAGE);
-        intent.putExtra(Settings.EXTRA_NETWORK_TEMPLATE, mTemplate);
+        intent.putExtra(Settings.EXTRA_NETWORK_TEMPLATE, getNetworkTemplate());
         intent.putExtra(Settings.EXTRA_SUB_ID, mSubId);
 
         mContext.startActivity(intent);
@@ -78,22 +89,49 @@
 
     public void init(int subId) {
         mSubId = subId;
+        mTemplate.set(null);
+        mTemplateFuture = ThreadUtils.postOnBackgroundThread(()
+                -> fetchMobileTemplate(mContext, mSubId));
+    }
 
+    private NetworkTemplate fetchMobileTemplate(Context context, int subId) {
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
-            return;
+            return null;
         }
-        mTemplate = DataUsageUtils.getDefaultTemplate(mContext, mSubId);
+        return DataUsageUtils.getMobileTemplate(context, subId);
+    }
+
+    private NetworkTemplate getNetworkTemplate() {
+        if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
+            return null;
+        }
+        NetworkTemplate template = mTemplate.get();
+        if (template != null) {
+            return template;
+        }
+        try {
+            template = mTemplateFuture.get();
+            mTemplate.set(template);
+        } catch (ExecutionException | InterruptedException | NullPointerException exception) {
+            Log.e(LOG_TAG, "Fail to get data usage template", exception);
+        }
+        return template;
+    }
+
+    @VisibleForTesting
+    DataUsageController.DataUsageInfo getDataUsageInfo(DataUsageController controller) {
+        return controller.getDataUsageInfo(getNetworkTemplate());
     }
 
     private CharSequence getDataUsageSummary(Context context, int subId) {
         final DataUsageController controller = new DataUsageController(context);
         controller.setSubscriptionId(subId);
 
-        final DataUsageController.DataUsageInfo usageInfo = controller.getDataUsageInfo(mTemplate);
+        final DataUsageController.DataUsageInfo usageInfo = getDataUsageInfo(controller);
 
         long usageLevel = usageInfo.usageLevel;
         if (usageLevel <= 0L) {
-            usageLevel = controller.getHistoricalUsageLevel(mTemplate);
+            usageLevel = controller.getHistoricalUsageLevel(getNetworkTemplate());
         }
         if (usageLevel <= 0L) {
             return null;
diff --git a/tests/robotests/src/com/android/settings/network/telephony/DataUsagePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/DataUsagePreferenceControllerTest.java
index 3b61342..43bda4e3 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/DataUsagePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/DataUsagePreferenceControllerTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
@@ -36,7 +37,6 @@
 import com.android.settingslib.net.DataUsageController;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -46,7 +46,6 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.Shadows;
 import org.robolectric.shadows.ShadowTelephonyManager;
-import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
 public class DataUsagePreferenceControllerTest {
@@ -73,7 +72,7 @@
         doReturn(mNetworkStatsManager).when(mContext).getSystemService(NetworkStatsManager.class);
 
         mPreference = new SwitchPreference(mContext);
-        mController = new DataUsagePreferenceController(mContext, "data_usage");
+        mController = spy(new DataUsagePreferenceController(mContext, "data_usage"));
         mController.init(SUB_ID);
         mPreference.setKey(mController.getPreferenceKey());
     }
@@ -115,10 +114,10 @@
     }
 
     @Test
-    @Ignore
     public void updateState_noUsageData_shouldDisablePreference() {
-        ReflectionHelpers.setField(
-                mController, "mDataUsageInfo", new DataUsageController.DataUsageInfo());
+        final DataUsageController.DataUsageInfo usageInfo =
+                new DataUsageController.DataUsageInfo();
+        doReturn(usageInfo).when(mController).getDataUsageInfo(any());
 
         mController.updateState(mPreference);
 
@@ -126,11 +125,11 @@
     }
 
     @Test
-    @Ignore
     public void updateState_shouldUseIECUnit() {
-        final DataUsageController.DataUsageInfo usageInfo = new DataUsageController.DataUsageInfo();
+        final DataUsageController.DataUsageInfo usageInfo =
+                new DataUsageController.DataUsageInfo();
         usageInfo.usageLevel = TrafficStats.MB_IN_BYTES;
-        ReflectionHelpers.setField(mController, "mDataUsageInfo", usageInfo);
+        doReturn(usageInfo).when(mController).getDataUsageInfo(any());
 
         mController.updateState(mPreference);