Create DataUsageListAppsController

Move apps group logic from DataUsageList.

Also add key to AppDataUsagePreference, which reduce flaky and keep
scroll position when back from app detail page.

Bug: 290856342
Test: manual - on DataUsageList
Test: unit test
Change-Id: I61e2b6bd9b192b7230e3553dbc6038f5d59bd303
This commit is contained in:
Chaohui Wang
2023-09-17 07:25:06 +08:00
parent 089318d92f
commit 0cb8d91e4e
8 changed files with 252 additions and 177 deletions

View File

@@ -14,7 +14,8 @@
limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="usage_amount"
@@ -32,6 +33,7 @@
<PreferenceCategory
android:key="apps_group"
android:layout="@layout/preference_category_no_label" />
android:layout="@layout/preference_category_no_label"
settings:controller="com.android.settings.datausage.DataUsageListAppsController" />
</PreferenceScreen>

View File

@@ -38,6 +38,7 @@ public class AppDataUsagePreference extends AppPreference {
public AppDataUsagePreference(Context context, AppItem item, int percent,
UidDetailProvider provider) {
super(context);
setKey("app_data_usage_" + item.key);
mItem = item;
mPercent = percent;

View File

@@ -15,9 +15,7 @@
package com.android.settings.datausage;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.settings.SettingsEnums;
import android.app.usage.NetworkStats;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
@@ -46,25 +44,19 @@ import androidx.lifecycle.Lifecycle;
import androidx.loader.app.LoaderManager.LoaderCallbacks;
import androidx.loader.content.Loader;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.datausage.CycleAdapter.SpinnerInterface;
import com.android.settings.datausage.lib.AppDataUsageRepository;
import com.android.settings.network.MobileDataEnabledListener;
import com.android.settings.network.MobileNetworkRepository;
import com.android.settings.network.ProxySubscriptionManager;
import com.android.settings.widget.LoadingViewController;
import com.android.settingslib.AppItem;
import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
import com.android.settingslib.net.NetworkCycleChartData;
import com.android.settingslib.net.NetworkCycleChartDataLoader;
import com.android.settingslib.net.NetworkStatsSummaryLoader;
import com.android.settingslib.net.UidDetailProvider;
import com.android.settingslib.utils.ThreadUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -85,14 +77,11 @@ public class DataUsageList extends DataUsageBaseFragment
private static final String KEY_USAGE_AMOUNT = "usage_amount";
private static final String KEY_CHART_DATA = "chart_data";
private static final String KEY_APPS_GROUP = "apps_group";
private static final String KEY_TEMPLATE = "template";
private static final String KEY_APP = "app";
@VisibleForTesting
static final int LOADER_CHART_DATA = 2;
@VisibleForTesting
static final int LOADER_SUMMARY = 3;
@VisibleForTesting
MobileDataEnabledListener mDataStateListener;
@@ -113,18 +102,15 @@ public class DataUsageList extends DataUsageBaseFragment
@Nullable
private List<NetworkCycleChartData> mCycleData;
// Caches the cycles for startAppDataUsage usage, which need be cleared when resumed.
private ArrayList<Long> mCycles;
// Spinner will keep the selected cycle even after paused, this only keeps the displayed cycle,
// which need be cleared when resumed.
private CycleAdapter.CycleItem mLastDisplayedCycle;
private UidDetailProvider mUidDetailProvider;
private CycleAdapter mCycleAdapter;
private Preference mUsageAmount;
private PreferenceGroup mApps;
private View mHeader;
private MobileNetworkRepository mMobileNetworkRepository;
private SubscriptionInfoEntity mSubscriptionInfoEntity;
private DataUsageListAppsController mDataUsageListAppsController;
@Override
public int getMetricsCategory() {
@@ -148,14 +134,19 @@ public class DataUsageList extends DataUsageBaseFragment
return;
}
mUidDetailProvider = new UidDetailProvider(activity);
mUsageAmount = findPreference(KEY_USAGE_AMOUNT);
mChart = findPreference(KEY_CHART_DATA);
mApps = findPreference(KEY_APPS_GROUP);
processArgument();
if (mTemplate == null) {
Log.e(TAG, "No template; leaving");
finish();
return;
}
updateSubscriptionInfoEntity();
mDataStateListener = new MobileDataEnabledListener(activity, this);
mDataUsageListAppsController = use(DataUsageListAppsController.class);
mDataUsageListAppsController.init(mTemplate);
}
@Override
@@ -216,7 +207,6 @@ public class DataUsageList extends DataUsageBaseFragment
super.onResume();
mLoadingViewController.showLoadingViewDelayed();
mDataStateListener.start(mSubId);
mCycles = null;
mLastDisplayedCycle = null;
// kick off loader for network history
@@ -234,16 +224,6 @@ public class DataUsageList extends DataUsageBaseFragment
mDataStateListener.stop();
getLoaderManager().destroyLoader(LOADER_CHART_DATA);
getLoaderManager().destroyLoader(LOADER_SUMMARY);
}
@Override
public void onDestroy() {
if (mUidDetailProvider != null) {
mUidDetailProvider.clearCache();
mUidDetailProvider = null;
}
super.onDestroy();
}
@Override
@@ -352,6 +332,7 @@ public class DataUsageList extends DataUsageBaseFragment
if (mCycleData != null) {
mCycleAdapter.updateCycleList(mCycleData);
}
mDataUsageListAppsController.setCycleData(mCycleData);
updateSelectedCycle();
}
@@ -402,8 +383,11 @@ public class DataUsageList extends DataUsageBaseFragment
if (LOGD) Log.d(TAG, "updateDetailData()");
// kick off loader for detailed stats
getLoaderManager().restartLoader(LOADER_SUMMARY, null /* args */,
mNetworkStatsDetailCallbacks);
mDataUsageListAppsController.update(
mSubscriptionInfoEntity == null ? null : mSubscriptionInfoEntity.carrierId,
mChart.getInspectStart(),
mChart.getInspectEnd()
);
final long totalBytes = mCycleData != null && !mCycleData.isEmpty()
? mCycleData.get(mCycleSpinner.getSelectedItemPosition()).getTotalUsage() : 0;
@@ -411,58 +395,6 @@ public class DataUsageList extends DataUsageBaseFragment
mUsageAmount.setTitle(getString(R.string.data_used_template, totalPhrase));
}
/**
* Bind the given buckets.
*/
private void bindStats(List<AppDataUsageRepository.Bucket> buckets) {
mApps.removeAll();
AppDataUsageRepository repository = new AppDataUsageRepository(
requireContext(),
ActivityManager.getCurrentUser(),
mSubscriptionInfoEntity == null ? null : mSubscriptionInfoEntity.carrierId,
appItem -> mUidDetailProvider.getUidDetail(appItem.key, true).packageName
);
for (var itemPercentPair : repository.getAppPercent(buckets)) {
final AppDataUsagePreference preference = new AppDataUsagePreference(getContext(),
itemPercentPair.getFirst(), itemPercentPair.getSecond(), mUidDetailProvider);
preference.setOnPreferenceClickListener(p -> {
AppDataUsagePreference pref = (AppDataUsagePreference) p;
startAppDataUsage(pref.getItem());
return true;
});
mApps.addPreference(preference);
}
}
@VisibleForTesting
void startAppDataUsage(AppItem item) {
if (mCycleData == null) {
return;
}
final Bundle args = new Bundle();
args.putParcelable(AppDataUsage.ARG_APP_ITEM, item);
args.putParcelable(AppDataUsage.ARG_NETWORK_TEMPLATE, mTemplate);
if (mCycles == null) {
mCycles = new ArrayList<>();
for (NetworkCycleChartData data : mCycleData) {
if (mCycles.isEmpty()) {
mCycles.add(data.getEndTime());
}
mCycles.add(data.getStartTime());
}
}
args.putSerializable(AppDataUsage.ARG_NETWORK_CYCLES, mCycles);
args.putLong(AppDataUsage.ARG_SELECTED_CYCLE,
mCycleData.get(mCycleSpinner.getSelectedItemPosition()).getEndTime());
new SubSettingLauncher(getContext())
.setDestination(AppDataUsage.class.getName())
.setTitleRes(R.string.data_usage_app_summary_title)
.setArguments(args)
.setSourceMetricsCategory(getMetricsCategory())
.launch();
}
private final OnItemSelectedListener mCycleListener = new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
@@ -502,44 +434,6 @@ public class DataUsageList extends DataUsageBaseFragment
}
};
private final LoaderCallbacks<NetworkStats> mNetworkStatsDetailCallbacks =
new LoaderCallbacks<>() {
@Override
@NonNull
public Loader<NetworkStats> onCreateLoader(int id, Bundle args) {
return new NetworkStatsSummaryLoader.Builder(getContext())
.setStartTime(mChart.getInspectStart())
.setEndTime(mChart.getInspectEnd())
.setNetworkTemplate(mTemplate)
.build();
}
@Override
public void onLoadFinished(
@NonNull Loader<NetworkStats> loader, NetworkStats data) {
bindStats(AppDataUsageRepository.Companion.convertToBuckets(data));
updateEmptyVisible();
}
@Override
public void onLoaderReset(@NonNull Loader<NetworkStats> loader) {
mApps.removeAll();
updateEmptyVisible();
}
private void updateEmptyVisible() {
if ((mApps.getPreferenceCount() != 0)
!= (getPreferenceScreen().getPreferenceCount() != 0)) {
if (mApps.getPreferenceCount() != 0) {
getPreferenceScreen().addPreference(mUsageAmount);
getPreferenceScreen().addPreference(mApps);
} else {
getPreferenceScreen().removeAll();
}
}
}
};
private static boolean isGuestUser(Context context) {
if (context == null) return false;
final UserManager userManager = context.getSystemService(UserManager.class);

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2023 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.datausage
import android.app.ActivityManager
import android.content.Context
import android.net.NetworkTemplate
import android.os.Bundle
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceGroup
import androidx.preference.PreferenceScreen
import com.android.settings.R
import com.android.settings.core.BasePreferenceController
import com.android.settings.core.SubSettingLauncher
import com.android.settings.datausage.lib.AppDataUsageRepository
import com.android.settingslib.AppItem
import com.android.settingslib.net.NetworkCycleChartData
import com.android.settingslib.net.UidDetailProvider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class DataUsageListAppsController(context: Context, preferenceKey: String) :
BasePreferenceController(context, preferenceKey) {
private val uidDetailProvider = UidDetailProvider(context)
private lateinit var template: NetworkTemplate
private lateinit var repository: AppDataUsageRepository
private lateinit var preference: PreferenceGroup
private lateinit var lifecycleScope: LifecycleCoroutineScope
private var cycleData: List<NetworkCycleChartData>? = null
fun init(template: NetworkTemplate) {
this.template = template
repository = AppDataUsageRepository(
context = mContext,
currentUserId = ActivityManager.getCurrentUser(),
template = template,
) { appItem: AppItem -> uidDetailProvider.getUidDetail(appItem.key, true).packageName }
}
override fun getAvailabilityStatus() = AVAILABLE
override fun displayPreference(screen: PreferenceScreen) {
super.displayPreference(screen)
preference = screen.findPreference(preferenceKey)!!
}
override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
lifecycleScope = viewLifecycleOwner.lifecycleScope
}
fun setCycleData(cycleData: List<NetworkCycleChartData>?) {
this.cycleData = cycleData
}
fun update(carrierId: Int?, startTime: Long, endTime: Long) = lifecycleScope.launch {
val apps = withContext(Dispatchers.Default) {
repository.getAppPercent(carrierId, startTime, endTime).map { (appItem, percent) ->
AppDataUsagePreference(mContext, appItem, percent, uidDetailProvider).apply {
setOnPreferenceClickListener {
startAppDataUsage(appItem, endTime)
true
}
}
}
}
preference.removeAll()
for (app in apps) {
preference.addPreference(app)
}
}
@VisibleForTesting
fun startAppDataUsage(item: AppItem, endTime: Long) {
val cycleData = cycleData ?: return
val args = Bundle().apply {
putParcelable(AppDataUsage.ARG_APP_ITEM, item)
putParcelable(AppDataUsage.ARG_NETWORK_TEMPLATE, template)
val cycles = ArrayList<Long>().apply {
for (data in cycleData) {
if (isEmpty()) add(data.endTime)
add(data.startTime)
}
}
putSerializable(AppDataUsage.ARG_NETWORK_CYCLES, cycles)
putLong(AppDataUsage.ARG_SELECTED_CYCLE, endTime)
}
SubSettingLauncher(mContext).apply {
setDestination(AppDataUsage::class.java.name)
setTitleRes(R.string.data_usage_app_summary_title)
setArguments(args)
setSourceMetricsCategory(metricsCategory)
}.launch()
}
}

View File

@@ -17,11 +17,15 @@
package com.android.settings.datausage.lib
import android.app.usage.NetworkStats
import android.app.usage.NetworkStatsManager
import android.content.Context
import android.net.NetworkPolicyManager
import android.net.NetworkTemplate
import android.os.Process
import android.os.UserHandle
import android.util.Log
import android.util.SparseArray
import androidx.annotation.VisibleForTesting
import com.android.settings.R
import com.android.settingslib.AppItem
import com.android.settingslib.net.UidDetailProvider
@@ -30,15 +34,18 @@ import com.android.settingslib.spaprivileged.framework.common.userManager
class AppDataUsageRepository(
private val context: Context,
private val currentUserId: Int,
private val carrierId: Int?,
private val getPackageName: (AppItem) -> String,
private val template: NetworkTemplate,
private val getPackageName: (AppItem) -> String?,
) {
data class Bucket(
val uid: Int,
val bytes: Long,
)
private val networkStatsManager = context.getSystemService(NetworkStatsManager::class.java)!!
fun getAppPercent(buckets: List<Bucket>): List<Pair<AppItem, Int>> {
fun getAppPercent(carrierId: Int?, startTime: Long, endTime: Long): List<Pair<AppItem, Int>> {
val networkStats = querySummary(startTime, endTime) ?: return emptyList()
return getAppPercent(carrierId, convertToBuckets(networkStats))
}
@VisibleForTesting
fun getAppPercent(carrierId: Int?, buckets: List<Bucket>): List<Pair<AppItem, Int>> {
val items = ArrayList<AppItem>()
val knownItems = SparseArray<AppItem>()
val profiles = context.userManager.userProfiles
@@ -61,7 +68,7 @@ class AppDataUsageRepository(
item.restricted = true
}
val filteredItems = filterItems(items).sorted()
val filteredItems = filterItems(carrierId, items).sorted()
val largest: Long = filteredItems.maxOfOrNull { it.total } ?: 0
return filteredItems.map { item ->
val percentTotal = if (largest > 0) (item.total * 100 / largest).toInt() else 0
@@ -69,7 +76,14 @@ class AppDataUsageRepository(
}
}
private fun filterItems(items: List<AppItem>): List<AppItem> {
private fun querySummary(startTime: Long, endTime: Long): NetworkStats? = try {
networkStatsManager.querySummary(template, startTime, endTime)
} catch (e: RuntimeException) {
Log.e(TAG, "Exception querying network detail.", e)
null
}
private fun filterItems(carrierId: Int?, items: List<AppItem>): List<AppItem> {
// When there is no specified SubscriptionInfo, Wi-Fi data usage will be displayed.
// In this case, the carrier service package also needs to be hidden.
if (carrierId != null && carrierId !in context.resources.getIntArray(
@@ -178,7 +192,15 @@ class AppDataUsageRepository(
}
companion object {
fun convertToBuckets(stats: NetworkStats): List<Bucket> {
private const val TAG = "AppDataUsageRepository"
@VisibleForTesting
data class Bucket(
val uid: Int,
val bytes: Long,
)
private fun convertToBuckets(stats: NetworkStats): List<Bucket> {
val buckets = mutableListOf<Bucket>()
stats.use {
val bucket = NetworkStats.Bucket()

View File

@@ -17,7 +17,6 @@
package com.android.settings.datausage;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -44,19 +43,15 @@ import androidx.loader.app.LoaderManager;
import androidx.preference.PreferenceManager;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.network.MobileDataEnabledListener;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.widget.LoadingViewController;
import com.android.settingslib.AppItem;
import com.android.settingslib.NetworkPolicyEditor;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.net.NetworkCycleChartData;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
@@ -67,9 +62,6 @@ import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class DataUsageListTest {
@@ -195,34 +187,6 @@ public class DataUsageListTest {
assertThat(mDataUsageList.mSubId).isEqualTo(3);
}
@Test
public void startAppDataUsage_shouldAddCyclesInfoToLaunchArguments() {
final long startTime = 1521583200000L;
final long endTime = 1521676800000L;
final List<NetworkCycleChartData> data = new ArrayList<>();
final NetworkCycleChartData.Builder builder = new NetworkCycleChartData.Builder();
builder.setStartTime(startTime)
.setEndTime(endTime);
data.add(builder.build());
ReflectionHelpers.setField(mDataUsageList, "mCycleData", data);
final Spinner spinner = mock(Spinner.class);
when(spinner.getSelectedItemPosition()).thenReturn(0);
ReflectionHelpers.setField(mDataUsageList, "mCycleSpinner", spinner);
final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
mDataUsageList.startAppDataUsage(new AppItem());
verify(mActivity).startActivity(intent.capture());
final Bundle arguments =
intent.getValue().getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
assertThat(arguments.getLong(AppDataUsage.ARG_SELECTED_CYCLE)).isEqualTo(endTime);
final ArrayList<Long> cycles =
(ArrayList) arguments.getSerializable(AppDataUsage.ARG_NETWORK_CYCLES);
assertThat(cycles).hasSize(2);
assertThat(cycles.get(0)).isEqualTo(endTime);
assertThat(cycles.get(1)).isEqualTo(startTime);
}
@Test
public void onViewCreated_shouldHideCycleSpinner() {
final View view = new View(mActivity);
@@ -255,7 +219,6 @@ public class DataUsageListTest {
mDataUsageList.onPause();
verify(mLoaderManager).destroyLoader(DataUsageList.LOADER_CHART_DATA);
verify(mLoaderManager).destroyLoader(DataUsageList.LOADER_SUMMARY);
}
private View getHeader() {

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2023 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.datausage
import android.content.Context
import android.content.Intent
import android.net.NetworkTemplate
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.SettingsActivity
import com.android.settingslib.AppItem
import com.android.settingslib.net.NetworkCycleChartData
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.doNothing
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
class DataUsageListAppsControllerTest {
private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
doNothing().whenever(mock).startActivity(any())
}
private val controller = DataUsageListAppsController(context, "test_key")
@Before
fun setUp() {
controller.init(mock<NetworkTemplate>())
val data = NetworkCycleChartData.Builder().apply {
setStartTime(START_TIME)
setEndTime(END_TIME)
}.build()
controller.setCycleData(listOf(data))
}
@Test
fun startAppDataUsage_shouldAddCyclesInfoToLaunchArguments() {
controller.startAppDataUsage(AppItem(), END_TIME)
val intent = argumentCaptor<Intent> {
verify(context).startActivity(capture())
}.firstValue
val arguments = intent.getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)!!
assertThat(arguments.getLong(AppDataUsage.ARG_SELECTED_CYCLE)).isEqualTo(END_TIME)
assertThat(
arguments.getSerializable(AppDataUsage.ARG_NETWORK_CYCLES, ArrayList::class.java)
).containsExactly(END_TIME, START_TIME).inOrder()
}
private companion object {
const val START_TIME = 1521583200000L
const val END_TIME = 1521676800000L
}
}

View File

@@ -20,12 +20,13 @@ import android.content.Context
import android.content.pm.UserInfo
import android.content.res.Resources
import android.net.NetworkPolicyManager
import android.net.NetworkTemplate
import android.os.UserHandle
import android.os.UserManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
import com.android.settings.datausage.lib.AppDataUsageRepository.Bucket
import com.android.settings.datausage.lib.AppDataUsageRepository.Companion.Bucket
import com.android.settingslib.AppItem
import com.android.settingslib.spaprivileged.framework.common.userManager
import com.google.common.truth.Truth.assertThat
@@ -72,15 +73,15 @@ class AppDataUsageRepositoryTest {
val repository = AppDataUsageRepository(
context = context,
currentUserId = USER_ID,
carrierId = null,
getPackageName = { "" },
template = Template,
getPackageName = { null },
)
val buckets = listOf(
Bucket(uid = APP_ID_1, bytes = 1),
Bucket(uid = APP_ID_2, bytes = 2),
)
val appPercentList = repository.getAppPercent(buckets)
val appPercentList = repository.getAppPercent(null, buckets)
assertThat(appPercentList).hasSize(2)
appPercentList[0].first.apply {
@@ -102,15 +103,15 @@ class AppDataUsageRepositoryTest {
val repository = AppDataUsageRepository(
context = context,
currentUserId = USER_ID,
carrierId = HIDING_CARRIER_ID,
getPackageName = { if (it.key == APP_ID_1) HIDING_PACKAGE_NAME else "" },
template = Template,
getPackageName = { if (it.key == APP_ID_1) HIDING_PACKAGE_NAME else null },
)
val buckets = listOf(
Bucket(uid = APP_ID_1, bytes = 1),
Bucket(uid = APP_ID_2, bytes = 2),
)
val appPercentList = repository.getAppPercent(buckets)
val appPercentList = repository.getAppPercent(HIDING_CARRIER_ID, buckets)
assertThat(appPercentList).hasSize(1)
appPercentList[0].first.apply {
@@ -127,5 +128,7 @@ class AppDataUsageRepositoryTest {
const val APP_ID_2 = 110002
const val HIDING_CARRIER_ID = 4
const val HIDING_PACKAGE_NAME = "hiding.package.name"
val Template: NetworkTemplate = mock<NetworkTemplate>()
}
}