Merge "Fixed the robo test failed in FoldLockBehaviorSettingsTest" into main
diff --git a/res/xml/data_usage_list.xml b/res/xml/data_usage_list.xml
index 28f09c6..791fc86 100644
--- a/res/xml/data_usage_list.xml
+++ b/res/xml/data_usage_list.xml
@@ -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>
diff --git a/src/com/android/settings/datausage/AppDataUsagePreference.java b/src/com/android/settings/datausage/AppDataUsagePreference.java
index 2805819..d8c7392 100644
--- a/src/com/android/settings/datausage/AppDataUsagePreference.java
+++ b/src/com/android/settings/datausage/AppDataUsagePreference.java
@@ -38,6 +38,7 @@
public AppDataUsagePreference(Context context, AppItem item, int percent,
UidDetailProvider provider) {
super(context);
+ setKey("app_data_usage_" + item.key);
mItem = item;
mPercent = percent;
diff --git a/src/com/android/settings/datausage/DataUsageList.java b/src/com/android/settings/datausage/DataUsageList.java
index b030219..e4bad12 100644
--- a/src/com/android/settings/datausage/DataUsageList.java
+++ b/src/com/android/settings/datausage/DataUsageList.java
@@ -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.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 @@
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 @@
@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 @@
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 @@
super.onResume();
mLoadingViewController.showLoadingViewDelayed();
mDataStateListener.start(mSubId);
- mCycles = null;
mLastDisplayedCycle = null;
// kick off loader for network history
@@ -234,16 +224,6 @@
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 @@
if (mCycleData != null) {
mCycleAdapter.updateCycleList(mCycleData);
}
+ mDataUsageListAppsController.setCycleData(mCycleData);
updateSelectedCycle();
}
@@ -402,67 +383,18 @@
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;
+ ? mCycleData.get(mCycleSpinner.getSelectedItemPosition()).getTotalUsage() : 0;
final CharSequence totalPhrase = DataUsageUtils.formatDataUsage(getActivity(), totalBytes);
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 @@
}
};
- 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);
diff --git a/src/com/android/settings/datausage/DataUsageListAppsController.kt b/src/com/android/settings/datausage/DataUsageListAppsController.kt
new file mode 100644
index 0000000..cc55e1a
--- /dev/null
+++ b/src/com/android/settings/datausage/DataUsageListAppsController.kt
@@ -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()
+ }
+}
diff --git a/src/com/android/settings/datausage/lib/AppDataUsageRepository.kt b/src/com/android/settings/datausage/lib/AppDataUsageRepository.kt
index 3813af5..074a555 100644
--- a/src/com/android/settings/datausage/lib/AppDataUsageRepository.kt
+++ b/src/com/android/settings/datausage/lib/AppDataUsageRepository.kt
@@ -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 @@
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 @@
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 @@
}
}
- 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 @@
}
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()
diff --git a/src/com/android/settings/network/apn/ApnEditPageProvider.kt b/src/com/android/settings/network/apn/ApnEditPageProvider.kt
new file mode 100644
index 0000000..c62cc78
--- /dev/null
+++ b/src/com/android/settings/network/apn/ApnEditPageProvider.kt
@@ -0,0 +1,75 @@
+/*
+ * 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.network.apn
+
+import android.content.Context
+import android.net.Uri
+import android.os.Bundle
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.navigation.NavType
+import androidx.navigation.navArgument
+import com.android.settings.R
+import com.android.settingslib.spa.framework.common.SettingsPageProvider
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
+import java.util.Base64
+
+const val URI_TYPE = "uriType"
+const val URI = "uri"
+const val SUB_ID = "subId"
+const val MVNO_TYPE = "mvnoType"
+const val MVNO_MATCH_DATA = "mvnoMatchData"
+const val EDIT_URL = "editUrl"
+
+object ApnEditPageProvider : SettingsPageProvider {
+
+ override val name = "Apn"
+ const val TAG = "ApnPageProvider"
+
+ override val parameter = listOf(
+ navArgument(URI_TYPE) { type = NavType.StringType },
+ navArgument(URI) { type = NavType.StringType },
+ navArgument(SUB_ID) { type = NavType.IntType },
+ navArgument(MVNO_TYPE) { type = NavType.StringType },
+ navArgument(MVNO_MATCH_DATA) { type = NavType.StringType },
+ )
+
+ @Composable
+ override fun Page(arguments: Bundle?) {
+ val context = LocalContext.current
+ ApnPage(context)
+ }
+
+ fun getRoute(
+ uriType: String,
+ uri: Uri,
+ subId: Int,
+ mMvnoType: String,
+ mMvnoMatchData: String
+ ): String = "${name}/$uriType/${
+ Base64.getUrlEncoder().encodeToString(uri.toString().toByteArray())
+ }/$subId/$mMvnoType/$mMvnoMatchData"
+}
+
+@Composable
+fun ApnPage(context: Context) {
+ RegularScaffold(
+ title = stringResource(id = R.string.apn_edit),
+ ) {
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/network/apn/ApnPreference.java b/src/com/android/settings/network/apn/ApnPreference.java
index f277db0..07d371a 100755
--- a/src/com/android/settings/network/apn/ApnPreference.java
+++ b/src/com/android/settings/network/apn/ApnPreference.java
@@ -16,6 +16,8 @@
package com.android.settings.network.apn;
+import static com.android.settings.network.apn.ApnEditPageProviderKt.EDIT_URL;
+
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
@@ -34,15 +36,21 @@
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
+import com.android.settings.flags.Flags;
+import com.android.settings.spa.SpaActivity;
/**
* Preference of APN UI entry
*/
-public class ApnPreference extends Preference implements CompoundButton.OnCheckedChangeListener,
- View.OnClickListener {
- private static final String TAG = "ApnPreference";
-
+public class ApnPreference extends Preference
+ implements CompoundButton.OnCheckedChangeListener, View.OnClickListener {
+ private static final String TAG = "ApnPreference";
+ private static String sSelectedKey = null;
+ private static CompoundButton sCurrentChecked = null;
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private boolean mProtectFromCheckedChange = false;
+ private boolean mSelectable = true;
+ private boolean mHideDetails = false;
/**
* Constructor of Preference
@@ -65,12 +73,6 @@
this(context, null);
}
- private static String sSelectedKey = null;
- private static CompoundButton sCurrentChecked = null;
- private boolean mProtectFromCheckedChange = false;
- private boolean mSelectable = true;
- private boolean mHideDetails = false;
-
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
@@ -147,25 +149,32 @@
}
if (mHideDetails) {
- Toast.makeText(context, context.getString(
- R.string.cannot_change_apn_toast), Toast.LENGTH_LONG).show();
+ Toast.makeText(context, context.getString(R.string.cannot_change_apn_toast),
+ Toast.LENGTH_LONG).show();
return;
}
- final Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
- final Intent editIntent = new Intent(Intent.ACTION_EDIT, url);
- editIntent.putExtra(ApnSettings.SUB_ID, mSubId);
- editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- context.startActivity(editIntent);
- }
- public void setSelectable(boolean selectable) {
- mSelectable = selectable;
+ final Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
+
+ if (Flags.newApnPageEnabled()) {
+ String route = ApnEditPageProvider.INSTANCE.getRoute(EDIT_URL, url, mSubId, "_", "_");
+ SpaActivity.startSpaActivity(context, route);
+ } else {
+ final Intent editIntent = new Intent(Intent.ACTION_EDIT, url);
+ editIntent.putExtra(ApnSettings.SUB_ID, mSubId);
+ editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ context.startActivity(editIntent);
+ }
}
public boolean getSelectable() {
return mSelectable;
}
+ public void setSelectable(boolean selectable) {
+ mSelectable = selectable;
+ }
+
public void setSubId(int subId) {
mSubId = subId;
}
diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
index f08a2de..40cc9a2 100644
--- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt
+++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.util.FeatureFlagUtils
+import com.android.settings.network.apn.ApnEditPageProvider
import com.android.settings.spa.about.AboutPhonePageProvider
import com.android.settings.spa.app.AllAppListPageProvider
import com.android.settings.spa.app.AppsMainPageProvider
@@ -34,8 +35,8 @@
import com.android.settings.spa.app.specialaccess.NfcTagAppsSettingsProvider
import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
import com.android.settings.spa.app.specialaccess.SpecialAppAccessPageProvider
-import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
import com.android.settings.spa.app.specialaccess.UseFullScreenIntentAppListProvider
+import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
import com.android.settings.spa.app.storage.StorageAppListPageProvider
import com.android.settings.spa.core.instrumentation.SpaLogProvider
import com.android.settings.spa.development.UsageStatsPageProvider
@@ -95,6 +96,7 @@
AboutPhonePageProvider,
StorageAppListPageProvider.Apps,
StorageAppListPageProvider.Games,
+ ApnEditPageProvider,
) + togglePermissionAppListTemplate.createPageProviders(),
rootPages = listOf(
HomePageProvider.createSettingsPage()
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
index 4640efe..b16d336 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
@@ -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.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.Implements;
import org.robolectric.util.ReflectionHelpers;
-import java.util.ArrayList;
-import java.util.List;
-
@RunWith(RobolectricTestRunner.class)
public class DataUsageListTest {
@@ -196,34 +188,6 @@
}
@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);
final View header = getHeader();
@@ -255,7 +219,6 @@
mDataUsageList.onPause();
verify(mLoaderManager).destroyLoader(DataUsageList.LOADER_CHART_DATA);
- verify(mLoaderManager).destroyLoader(DataUsageList.LOADER_SUMMARY);
}
private View getHeader() {
diff --git a/tests/spa_unit/src/com/android/settings/datausage/DataUsageListAppsControllerTest.kt b/tests/spa_unit/src/com/android/settings/datausage/DataUsageListAppsControllerTest.kt
new file mode 100644
index 0000000..af5dc89
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/datausage/DataUsageListAppsControllerTest.kt
@@ -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
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/datausage/lib/AppDataUsageRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/datausage/lib/AppDataUsageRepositoryTest.kt
index 016d6d2..531e6e7 100644
--- a/tests/spa_unit/src/com/android/settings/datausage/lib/AppDataUsageRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/datausage/lib/AppDataUsageRepositoryTest.kt
@@ -20,12 +20,13 @@
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 @@
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 @@
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 @@
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>()
}
}