Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3c5850ee authored by Doris Ling's avatar Doris Ling
Browse files

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
parent 4b2a053b
Loading
Loading
Loading
Loading
+37 −58
Original line number Diff line number Diff line
/*
 * 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.Intent;
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.AppItem;
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 @@ public class AppDataUsageV2 extends DataUsageBaseFragment implements OnPreferenc
    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 @@ public class AppDataUsageV2 extends DataUsageBaseFragment implements OnPreferenc
    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 @@ public class AppDataUsageV2 extends DataUsageBaseFragment implements OnPreferenc
        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;
@@ -208,21 +195,13 @@ public class AppDataUsageV2 extends DataUsageBaseFragment implements OnPreferenc
        }
    }

    @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 @@ public class AppDataUsageV2 extends DataUsageBaseFragment implements OnPreferenc
        }
    }

    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 @@ public class AppDataUsageV2 extends DataUsageBaseFragment implements OnPreferenc
            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,22 +362,28 @@ public class AppDataUsageV2 extends DataUsageBaseFragment implements OnPreferenc
        }
    };

    private final LoaderManager.LoaderCallbacks<ChartData> mChartDataCallbacks =
            new LoaderManager.LoaderCallbacks<ChartData>() {
    private final LoaderManager.LoaderCallbacks<List<NetworkCycleDataForUid>> mUidDataCallbacks =
        new LoaderManager.LoaderCallbacks<List<NetworkCycleDataForUid>>() {
            @Override
        public Loader<ChartData> onCreateLoader(int id, Bundle args) {
            return new ChartDataLoaderCompat(getActivity(), mStatsSession, args);
            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();
            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) {
            public void onLoaderReset(Loader<List<NetworkCycleDataForUid>> loader) {
            }
        };

+52 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.settings.datausage;
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.spy;
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.settings.widget.EntityHeaderController;
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.RuntimeEnvironment;
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 @@ public class AppDataUsageV2Test {
        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));
    }
}