Create AppDataUsageSummaryController
Content description for usage will be added later.
Bug: 318780411
Test: manual - on AppDataUsage
Test: unit test
Change-Id: I3990218395dfd7553554346ea8ef00368ba57589
diff --git a/res/xml/app_data_usage.xml b/res/xml/app_data_usage.xml
index 034015c..88f60ef 100644
--- a/res/xml/app_data_usage.xml
+++ b/res/xml/app_data_usage.xml
@@ -24,31 +24,9 @@
android:key="cycle"
settings:controller="com.android.settings.datausage.AppDataUsageCycleController" />
- <PreferenceCategory
- android:key="app_data_usage_summary_category">
-
- <Preference
- android:key="total_usage"
- android:title="@string/total_size_label"
- android:selectable="false"
- android:layout="@layout/horizontal_preference"
- android:summary="@string/summary_placeholder" />
-
- <Preference
- android:key="foreground_usage"
- android:title="@string/data_usage_label_foreground"
- android:selectable="false"
- android:layout="@layout/horizontal_preference"
- android:summary="@string/summary_placeholder" />
-
- <Preference
- android:key="background_usage"
- android:title="@string/data_usage_label_background"
- android:selectable="false"
- android:layout="@layout/horizontal_preference"
- android:summary="@string/summary_placeholder" />
-
- </PreferenceCategory>
+ <com.android.settings.spa.preference.ComposePreference
+ android:key="app_data_usage_summary"
+ settings:controller="com.android.settings.datausage.AppDataUsageSummaryController"/>
<PreferenceCategory
android:key="app_data_usage_settings_category"
diff --git a/src/com/android/settings/datausage/AppDataUsage.java b/src/com/android/settings/datausage/AppDataUsage.java
index dbc0bc7..8480c5c 100644
--- a/src/com/android/settings/datausage/AppDataUsage.java
+++ b/src/com/android/settings/datausage/AppDataUsage.java
@@ -43,7 +43,6 @@
import com.android.settings.applications.AppInfoBase;
import com.android.settings.datausage.lib.AppDataUsageDetailsRepository;
import com.android.settings.datausage.lib.NetworkTemplates;
-import com.android.settings.datausage.lib.NetworkUsageDetailsData;
import com.android.settings.fuelgauge.datasaver.DynamicDenylistManager;
import com.android.settings.network.SubscriptionUtil;
import com.android.settings.widget.EntityHeaderController;
@@ -70,17 +69,11 @@
static final String ARG_NETWORK_CYCLES = "network_cycles";
static final String ARG_SELECTED_CYCLE = "selected_cycle";
- private static final String KEY_TOTAL_USAGE = "total_usage";
- private static final String KEY_FOREGROUND_USAGE = "foreground_usage";
- private static final String KEY_BACKGROUND_USAGE = "background_usage";
private static final String KEY_RESTRICT_BACKGROUND = "restrict_background";
private static final String KEY_UNRESTRICTED_DATA = "unrestricted_data_saver";
private PackageManager mPackageManager;
private final ArraySet<String> mPackages = new ArraySet<>();
- private Preference mTotalUsage;
- private Preference mForegroundUsage;
- private Preference mBackgroundUsage;
private RestrictedSwitchPreference mRestrictBackground;
private Drawable mIcon;
@@ -139,10 +132,6 @@
}
}
- mTotalUsage = findPreference(KEY_TOTAL_USAGE);
- mForegroundUsage = findPreference(KEY_FOREGROUND_USAGE);
- mBackgroundUsage = findPreference(KEY_BACKGROUND_USAGE);
-
final List<Integer> uidList = getAppUidList(mAppItem.uids);
initCycle(uidList);
@@ -255,15 +244,17 @@
@VisibleForTesting
void initCycle(List<Integer> uidList) {
- var controller = use(AppDataUsageCycleController.class);
+ var cycleController = use(AppDataUsageCycleController.class);
+ var summaryController = use(AppDataUsageSummaryController.class);
var repository = new AppDataUsageDetailsRepository(mContext, mTemplate, mCycles, uidList);
- controller.init(repository, data -> {
- bindData(data);
+ cycleController.init(repository, data -> {
+ mIsLoading = false;
+ summaryController.update(data);
return Unit.INSTANCE;
});
if (mCycles != null) {
Log.d(TAG, "setInitialCycles: " + mCycles + " " + mSelectedCycle);
- controller.setInitialCycles(mCycles, mSelectedCycle);
+ cycleController.setInitialCycles(mCycles, mSelectedCycle);
}
}
@@ -314,16 +305,6 @@
}
}
- @VisibleForTesting
- void bindData(@NonNull NetworkUsageDetailsData data) {
- mIsLoading = false;
- mTotalUsage.setSummary(DataUsageUtils.formatDataUsage(mContext, data.getTotalUsage()));
- mForegroundUsage.setSummary(
- DataUsageUtils.formatDataUsage(mContext, data.getForegroundUsage()));
- mBackgroundUsage.setSummary(
- DataUsageUtils.formatDataUsage(mContext, data.getBackgroundUsage()));
- }
-
private boolean getAppRestrictBackground() {
final int uid = mAppItem.key;
final int uidPolicy = services.mPolicyManager.getUidPolicy(uid);
diff --git a/src/com/android/settings/datausage/AppDataUsageSummaryController.kt b/src/com/android/settings/datausage/AppDataUsageSummaryController.kt
new file mode 100644
index 0000000..a764c1d
--- /dev/null
+++ b/src/com/android/settings/datausage/AppDataUsageSummaryController.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2024 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 androidx.compose.foundation.layout.Column
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.res.stringResource
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.settings.R
+import com.android.settings.datausage.lib.NetworkUsageDetailsData
+import com.android.settings.spa.preference.ComposePreferenceController
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spaprivileged.framework.compose.placeholder
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.map
+
+class AppDataUsageSummaryController(context: Context, preferenceKey: String) :
+ ComposePreferenceController(context, preferenceKey) {
+
+ private val dataFlow = MutableStateFlow(NetworkUsageDetailsData.AllZero)
+
+ private val totalUsageFlow = dataFlow.map {
+ DataUsageUtils.formatDataUsage(mContext, it.totalUsage).toString()
+ }
+
+ private val foregroundUsageFlow = dataFlow.map {
+ DataUsageUtils.formatDataUsage(mContext, it.foregroundUsage).toString()
+ }
+
+ private val backgroundUsageFlow = dataFlow.map {
+ DataUsageUtils.formatDataUsage(mContext, it.backgroundUsage).toString()
+ }
+
+ override fun getAvailabilityStatus() = AVAILABLE
+
+ fun update(data: NetworkUsageDetailsData) {
+ dataFlow.value = data
+ }
+
+ @Composable
+ override fun Content() {
+ Column {
+ val totalUsage by totalUsageFlow.collectAsStateWithLifecycle(placeholder())
+ val foregroundUsage by foregroundUsageFlow.collectAsStateWithLifecycle(placeholder())
+ val backgroundUsage by backgroundUsageFlow.collectAsStateWithLifecycle(placeholder())
+ Preference(object : PreferenceModel {
+ override val title = stringResource(R.string.total_size_label)
+ override val summary = { totalUsage }
+ })
+ Preference(object : PreferenceModel {
+ override val title = stringResource(R.string.data_usage_label_foreground)
+ override val summary = { foregroundUsage }
+ })
+ Preference(object : PreferenceModel {
+ override val title = stringResource(R.string.data_usage_label_background)
+ override val summary = { backgroundUsage }
+ })
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
index 1d841fa..4b8c9de 100644
--- a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
@@ -42,16 +42,13 @@
import android.os.Process;
import android.telephony.SubscriptionManager;
import android.util.ArraySet;
-import android.util.Range;
import androidx.fragment.app.FragmentActivity;
-import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.applications.AppInfoBase;
-import com.android.settings.datausage.lib.NetworkUsageDetailsData;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowDataUsageUtils;
import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
@@ -253,34 +250,6 @@
}
@Test
- public void bindData_shouldUpdateUsageSummary() {
- mFragment = spy(new TestFragment());
- final Context context = RuntimeEnvironment.application;
- ReflectionHelpers.setField(mFragment, "mContext", context);
- final long backgroundBytes = 1234L;
- final long foregroundBytes = 5678L;
- final NetworkUsageDetailsData appUsage = new NetworkUsageDetailsData(
- new Range<>(1L, 2L),
- backgroundBytes + foregroundBytes,
- foregroundBytes,
- backgroundBytes
- );
- 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);
-
- mFragment.bindData(appUsage);
-
- verify(totalPref).setSummary(
- DataUsageUtils.formatDataUsage(context, backgroundBytes + foregroundBytes));
- verify(backgroundPref).setSummary(DataUsageUtils.formatDataUsage(context, backgroundBytes));
- verify(foregroundPref).setSummary(DataUsageUtils.formatDataUsage(context, foregroundBytes));
- }
-
- @Test
@Config(shadows = {ShadowDataUsageUtils.class, ShadowSubscriptionManager.class,
ShadowFragment.class})
public void onCreate_noNetworkTemplateAndInvalidDataSubscription_shouldUseWifiTemplate() {
diff --git a/tests/spa_unit/src/com/android/settings/datausage/AppDataUsageSummaryControllerTest.kt b/tests/spa_unit/src/com/android/settings/datausage/AppDataUsageSummaryControllerTest.kt
new file mode 100644
index 0000000..5842956
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/datausage/AppDataUsageSummaryControllerTest.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 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.util.Range
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.datausage.lib.NetworkUsageDetailsData
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class AppDataUsageSummaryControllerTest {
+
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ private val controller = AppDataUsageSummaryController(context, TEST_KEY)
+
+ @Test
+ fun summary() {
+ val appUsage = NetworkUsageDetailsData(
+ range = Range(1L, 2L),
+ totalUsage = BACKGROUND_BYTES + FOREGROUND_BYTES,
+ foregroundUsage = FOREGROUND_BYTES,
+ backgroundUsage = BACKGROUND_BYTES,
+ )
+
+ controller.update(appUsage)
+ composeTestRule.setContent {
+ controller.Content()
+ }
+
+ composeTestRule.onNodeWithText("6.75 kB").assertIsDisplayed()
+ composeTestRule.onNodeWithText("5.54 kB").assertIsDisplayed()
+ composeTestRule.onNodeWithText("1.21 kB").assertIsDisplayed()
+ }
+
+ private companion object {
+ const val TEST_KEY = "test_key"
+ const val BACKGROUND_BYTES = 1234L
+ const val FOREGROUND_BYTES = 5678L
+ }
+}