Use the new loader to show app data usage details.

- this is for showing the detail usage (total, background, and
foreground) for a specific app for each billing cycle.

Bug: 111751694
Test: make RunSettingsRoboTests
Change-Id: I8e02872a4204b682089ea117811b50966e785c55
diff --git a/src/com/android/settings/datausage/AppDataUsageV2.java b/src/com/android/settings/datausage/AppDataUsageV2.java
index 6d6089e..4e8325b 100644
--- a/src/com/android/settings/datausage/AppDataUsageV2.java
+++ b/src/com/android/settings/datausage/AppDataUsageV2.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2018 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
@@ -22,13 +22,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
-import android.net.INetworkStatsSession;
-import android.net.NetworkPolicy;
-import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
-import android.net.TrafficStats;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.ArraySet;
 import android.util.IconDrawableFactory;
@@ -51,11 +46,13 @@
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.RestrictedSwitchPreference;
-import com.android.settingslib.net.ChartData;
-import com.android.settingslib.net.ChartDataLoaderCompat;
+import com.android.settingslib.net.NetworkCycleDataForUid;
+import com.android.settingslib.net.NetworkCycleDataForUidLoader;
 import com.android.settingslib.net.UidDetail;
 import com.android.settingslib.net.UidDetailProvider;
 
+import java.util.List;
+
 public class AppDataUsageV2 extends DataUsageBaseFragment implements OnPreferenceChangeListener,
         DataSaverBackend.Listener {
 
@@ -73,7 +70,7 @@
     private static final String KEY_CYCLE = "cycle";
     private static final String KEY_UNRESTRICTED_DATA = "unrestricted_data_saver";
 
-    private static final int LOADER_CHART_DATA = 2;
+    private static final int LOADER_APP_USAGE_DATA = 2;
     private static final int LOADER_APP_PREF = 3;
 
     private PackageManager mPackageManager;
@@ -88,14 +85,10 @@
     private Drawable mIcon;
     private CharSequence mLabel;
     private String mPackageName;
-    private INetworkStatsSession mStatsSession;
     private CycleAdapter mCycleAdapter;
 
-    private long mStart;
-    private long mEnd;
-    private ChartData mChartData;
+    private List<NetworkCycleDataForUid> mUsageData;
     private NetworkTemplate mTemplate;
-    private NetworkPolicy mPolicy;
     private AppItem mAppItem;
     private Intent mAppSettingsIntent;
     private SpinnerPreference mCycle;
@@ -108,12 +101,6 @@
         mPackageManager = getPackageManager();
         final Bundle args = getArguments();
 
-        try {
-            mStatsSession = services.mStatsService.openSession();
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-
         mAppItem = (args != null) ? (AppItem) args.getParcelable(ARG_APP_ITEM) : null;
         mTemplate = (args != null) ? (NetworkTemplate) args.getParcelable(ARG_NETWORK_TEMPLATE)
                 : null;
@@ -209,20 +196,12 @@
     }
 
     @Override
-    public void onDestroy() {
-        TrafficStats.closeQuietly(mStatsSession);
-        super.onDestroy();
-    }
-
-    @Override
     public void onResume() {
         super.onResume();
         if (mDataSaverBackend != null) {
             mDataSaverBackend.addListener(this);
         }
-        mPolicy = services.mPolicyEditor.getPolicy(mTemplate);
-        getLoaderManager().restartLoader(LOADER_CHART_DATA,
-                ChartDataLoaderCompat.buildArgs(mTemplate, mAppItem), mChartDataCallbacks);
+        getLoaderManager().restartLoader(LOADER_APP_USAGE_DATA, null /* args */, mUidDataCallbacks);
         updatePrefs();
     }
 
@@ -300,19 +279,17 @@
         }
     }
 
-    private void bindData() {
+    @VisibleForTesting
+    void bindData(int position) {
         final long backgroundBytes, foregroundBytes;
-        if (mChartData == null || mStart == 0) {
+        if (mUsageData == null || position >= mUsageData.size()) {
             backgroundBytes = foregroundBytes = 0;
             mCycle.setVisible(false);
         } else {
             mCycle.setVisible(true);
-            final long now = System.currentTimeMillis();
-            NetworkStatsHistory.Entry entry = null;
-            entry = mChartData.detailDefault.getValues(mStart, mEnd, now, entry);
-            backgroundBytes = entry.rxBytes + entry.txBytes;
-            entry = mChartData.detailForeground.getValues(mStart, mEnd, now, entry);
-            foregroundBytes = entry.rxBytes + entry.txBytes;
+            final NetworkCycleDataForUid data = mUsageData.get(position);
+            backgroundBytes = data.getBackgroudUsage();
+            foregroundBytes = data.getForegroudUsage();
         }
         final long totalBytes = backgroundBytes + foregroundBytes;
         final Context context = getContext();
@@ -376,11 +353,7 @@
             new AdapterView.OnItemSelectedListener() {
         @Override
         public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-            final CycleAdapter.CycleItem cycle = (CycleAdapter.CycleItem) mCycle.getSelectedItem();
-
-            mStart = cycle.start;
-            mEnd = cycle.end;
-            bindData();
+            bindData(position);
         }
 
         @Override
@@ -389,24 +362,30 @@
         }
     };
 
-    private final LoaderManager.LoaderCallbacks<ChartData> mChartDataCallbacks =
-            new LoaderManager.LoaderCallbacks<ChartData>() {
-        @Override
-        public Loader<ChartData> onCreateLoader(int id, Bundle args) {
-            return new ChartDataLoaderCompat(getActivity(), mStatsSession, args);
-        }
+    private final LoaderManager.LoaderCallbacks<List<NetworkCycleDataForUid>> mUidDataCallbacks =
+        new LoaderManager.LoaderCallbacks<List<NetworkCycleDataForUid>>() {
+            @Override
+            public Loader<List<NetworkCycleDataForUid>> onCreateLoader(int id, Bundle args) {
+                return NetworkCycleDataForUidLoader.builder(getContext())
+                    .setUid(mAppItem.key)
+                    .setRetrieveDetail(true)
+                    .setNetworkTemplate(mTemplate)
+                    .setSubscriberId(mTemplate.getSubscriberId())
+                    .build();
+            }
 
-        @Override
-        public void onLoadFinished(Loader<ChartData> loader, ChartData data) {
-            mChartData = data;
-            mCycleAdapter.updateCycleList(mPolicy, mChartData);
-            bindData();
-        }
+            @Override
+            public void onLoadFinished(Loader<List<NetworkCycleDataForUid>> loader,
+                    List<NetworkCycleDataForUid> data) {
+                mUsageData = data;
+                mCycleAdapter.updateCycleList(data);
+                bindData(0 /* position */);
+            }
 
-        @Override
-        public void onLoaderReset(Loader<ChartData> loader) {
-        }
-    };
+            @Override
+            public void onLoaderReset(Loader<List<NetworkCycleDataForUid>> loader) {
+            }
+        };
 
     private final LoaderManager.LoaderCallbacks<ArraySet<Preference>> mAppPrefCallbacks =
         new LoaderManager.LoaderCallbacks<ArraySet<Preference>>() {
diff --git a/tests/robotests/src/com/android/settings/datausage/AppDataUsageV2Test.java b/tests/robotests/src/com/android/settings/datausage/AppDataUsageV2Test.java
index d979b68..8796a39 100644
--- a/tests/robotests/src/com/android/settings/datausage/AppDataUsageV2Test.java
+++ b/tests/robotests/src/com/android/settings/datausage/AppDataUsageV2Test.java
@@ -19,6 +19,7 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.doNothing;
@@ -28,12 +29,14 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.Context;
 import android.content.pm.PackageManager;
 import android.net.NetworkPolicyManager;
 import android.os.Bundle;
 import android.util.ArraySet;
 import android.view.View;
 
+import androidx.preference.Preference;
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceScreen;
 
@@ -45,6 +48,7 @@
 import com.android.settingslib.AppItem;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import com.android.settingslib.RestrictedSwitchPreference;
+import com.android.settingslib.net.NetworkCycleDataForUid;
 
 import org.junit.After;
 import org.junit.Before;
@@ -57,6 +61,9 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(shadows = {ShadowEntityHeaderController.class, ShadowRestrictedLockUtilsInternal.class})
 public class AppDataUsageV2Test {
@@ -172,4 +179,49 @@
         verify(restrictBackgroundPref).setDisabledByAdmin(any(EnforcedAdmin.class));
         verify(unrestrictedDataPref).setDisabledByAdmin(any(EnforcedAdmin.class));
     }
+
+    @Test
+    public void bindData_noAppUsageData_shouldHideCycleSpinner() {
+        mFragment = spy(new AppDataUsageV2());
+        final SpinnerPreference cycle = mock(SpinnerPreference.class);
+        ReflectionHelpers.setField(mFragment, "mCycle", cycle);
+        final Preference preference = mock(Preference.class);
+        ReflectionHelpers.setField(mFragment, "mBackgroundUsage", preference);
+        ReflectionHelpers.setField(mFragment, "mForegroundUsage", preference);
+        ReflectionHelpers.setField(mFragment, "mTotalUsage", preference);
+        doReturn(RuntimeEnvironment.application).when(mFragment).getContext();
+
+        mFragment.bindData(0 /* position */);
+
+        verify(cycle).setVisible(false);
+    }
+
+    @Test
+    public void bindData_hasAppUsageData_shouldShowCycleSpinnerAndUpdateUsageSummary() {
+        mFragment = spy(new AppDataUsageV2());
+        final Context context = RuntimeEnvironment.application;
+        doReturn(context).when(mFragment).getContext();
+        final long backgroundBytes = 1234L;
+        final long foregroundBytes = 5678L;
+        final List<NetworkCycleDataForUid> appUsage = new ArrayList<>();
+        appUsage.add(new NetworkCycleDataForUid.Builder()
+            .setBackgroundUsage(backgroundBytes).setForegroundUsage(foregroundBytes).build());
+        ReflectionHelpers.setField(mFragment, "mUsageData", appUsage);
+        final Preference backgroundPref = mock(Preference.class);
+        ReflectionHelpers.setField(mFragment, "mBackgroundUsage", backgroundPref);
+        final Preference foregroundPref = mock(Preference.class);
+        ReflectionHelpers.setField(mFragment, "mForegroundUsage", foregroundPref);
+        final Preference totalPref = mock(Preference.class);
+        ReflectionHelpers.setField(mFragment, "mTotalUsage", totalPref);
+        final SpinnerPreference cycle = mock(SpinnerPreference.class);
+        ReflectionHelpers.setField(mFragment, "mCycle", cycle);
+
+        mFragment.bindData(0 /* position */);
+
+        verify(cycle).setVisible(true);
+        verify(totalPref).setSummary(
+            DataUsageUtils.formatDataUsage(context, backgroundBytes + foregroundBytes));
+        verify(backgroundPref).setSummary(DataUsageUtils.formatDataUsage(context, backgroundBytes));
+        verify(foregroundPref).setSummary(DataUsageUtils.formatDataUsage(context, foregroundBytes));
+    }
 }