Merge changes from topic "AppDataUsage" into main
* changes:
[Expressive design] Update AppDataUsage.
[Expressive design] Rename ComposeMainSwitchPreference to ComposeGroupSectionPreference.
diff --git a/res/xml/app_data_usage.xml b/res/xml/app_data_usage.xml
index 88f60ef..3135f59 100644
--- a/res/xml/app_data_usage.xml
+++ b/res/xml/app_data_usage.xml
@@ -20,11 +20,15 @@
android:key="app_data_usage_screen"
android:title="@string/data_usage_app_summary_title">
+ <com.android.settingslib.widget.IntroPreference
+ android:key="app_header"
+ android:order="-10000"/>
+
<com.android.settings.datausage.SpinnerPreference
android:key="cycle"
settings:controller="com.android.settings.datausage.AppDataUsageCycleController" />
- <com.android.settings.spa.preference.ComposePreference
+ <com.android.settings.spa.preference.ComposeGroupSectionPreference
android:key="app_data_usage_summary"
settings:controller="com.android.settings.datausage.AppDataUsageSummaryController"/>
diff --git a/res/xml/mobile_network_settings.xml b/res/xml/mobile_network_settings.xml
index a1a2276..8c948ff 100644
--- a/res/xml/mobile_network_settings.xml
+++ b/res/xml/mobile_network_settings.xml
@@ -18,7 +18,7 @@
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="mobile_network_pref_screen">
- <com.android.settings.spa.preference.ComposeMainSwitchPreference
+ <com.android.settings.spa.preference.ComposeGroupSectionPreference
android:key="use_sim_switch"
settings:controller="com.android.settings.network.telephony.MobileNetworkSwitchController"/>
diff --git a/src/com/android/settings/datausage/AppDataUsage.java b/src/com/android/settings/datausage/AppDataUsage.java
index 8480c5c..d8e238c 100644
--- a/src/com/android/settings/datausage/AppDataUsage.java
+++ b/src/com/android/settings/datausage/AppDataUsage.java
@@ -18,6 +18,7 @@
import static com.android.settings.datausage.lib.AppDataUsageRepository.getAppUid;
import static com.android.settings.datausage.lib.AppDataUsageRepository.getAppUidList;
+import static com.android.settings.spa.app.appinfo.AppInfoSettingsProvider.startAppInfoSettings;
import android.app.Activity;
import android.app.settings.SettingsEnums;
@@ -45,13 +46,14 @@
import com.android.settings.datausage.lib.NetworkTemplates;
import com.android.settings.fuelgauge.datasaver.DynamicDenylistManager;
import com.android.settings.network.SubscriptionUtil;
-import com.android.settings.widget.EntityHeaderController;
+import com.android.settings.overlay.FeatureFactory;
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.UidDetail;
import com.android.settingslib.net.UidDetailProvider;
+import com.android.settingslib.widget.IntroPreference;
import kotlin.Unit;
@@ -65,6 +67,8 @@
private static final String TAG = "AppDataUsage";
static final String ARG_APP_ITEM = "app_item";
+ @VisibleForTesting
+ static final String ARG_APP_HEADER = "app_header";
static final String ARG_NETWORK_TEMPLATE = "network_template";
static final String ARG_NETWORK_CYCLES = "network_cycles";
static final String ARG_SELECTED_CYCLE = "selected_cycle";
@@ -176,7 +180,7 @@
removePreference(KEY_RESTRICT_BACKGROUND);
}
- addEntityHeader();
+ setupIntroPreference();
}
@Override
@@ -320,32 +324,32 @@
}
@VisibleForTesting
- void addEntityHeader() {
- String pkg = mPackages.size() != 0 ? mPackages.valueAt(0) : null;
- int uid = 0;
- if (pkg != null) {
+ void setupIntroPreference() {
+ final Preference pref = getPreferenceScreen().findPreference(ARG_APP_HEADER);
+ if (pref != null) {
+ pref.setIcon(mIcon);
+ pref.setTitle(mLabel);
+ pref.setSelectable(true);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(Preference preference) {
+ if (!(preference instanceof IntroPreference)) return false;
+
+ String pkg = !mPackages.isEmpty() ? mPackages.valueAt(0) : null;
+ if (mAppItem.key > 0 && pkg != null) {
try {
- uid = mPackageManager.getPackageUidAsUser(pkg,
+ int uid = mPackageManager.getPackageUidAsUser(pkg,
UserHandle.getUserId(mAppItem.key));
+ startAppInfoSettings(pkg, uid, this, 0 /* request */,
+ FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
+ .getMetricsCategory(this));
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Skipping UID because cannot find package " + pkg);
}
}
-
- final boolean showInfoButton = mAppItem.key > 0;
-
- final Activity activity = getActivity();
- final Preference pref = EntityHeaderController
- .newInstance(activity, this, null /* header */)
- .setUid(uid)
- .setHasAppInfoLink(showInfoButton)
- .setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
- EntityHeaderController.ActionType.ACTION_NONE)
- .setIcon(mIcon)
- .setLabel(mLabel)
- .setPackageName(pkg)
- .done(getPrefContext());
- getPreferenceScreen().addPreference(pref);
+ return true;
}
@Override
diff --git a/src/com/android/settings/datausage/AppDataUsageSummaryController.kt b/src/com/android/settings/datausage/AppDataUsageSummaryController.kt
index 233e107..fb7101d 100644
--- a/src/com/android/settings/datausage/AppDataUsageSummaryController.kt
+++ b/src/com/android/settings/datausage/AppDataUsageSummaryController.kt
@@ -17,7 +17,6 @@
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
@@ -28,6 +27,7 @@
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.spa.widget.ui.Category
import com.android.settingslib.spaprivileged.framework.compose.getPlaceholder
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map
@@ -60,7 +60,7 @@
@Composable
override fun Content() {
- Column {
+ Category {
val totalUsage by totalUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
val foregroundUsage by foregroundUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
val backgroundUsage by backgroundUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
diff --git a/src/com/android/settings/datausage/SpinnerPreference.java b/src/com/android/settings/datausage/SpinnerPreference.java
index febdead..a1b0f90 100644
--- a/src/com/android/settings/datausage/SpinnerPreference.java
+++ b/src/com/android/settings/datausage/SpinnerPreference.java
@@ -25,8 +25,10 @@
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
+import com.android.settingslib.widget.GroupSectionDividerMixin;
-public class SpinnerPreference extends Preference implements CycleAdapter.SpinnerInterface {
+public class SpinnerPreference extends Preference implements CycleAdapter.SpinnerInterface,
+ GroupSectionDividerMixin {
private CycleAdapter mAdapter;
@Nullable
diff --git a/src/com/android/settings/spa/preference/ComposePreference.kt b/src/com/android/settings/spa/preference/ComposePreference.kt
index 91b2d8a..57aa386 100644
--- a/src/com/android/settings/spa/preference/ComposePreference.kt
+++ b/src/com/android/settings/spa/preference/ComposePreference.kt
@@ -28,7 +28,7 @@
import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.widget.GroupSectionDividerMixin
-open class ComposeMainSwitchPreference @JvmOverloads constructor(
+open class ComposeGroupSectionPreference @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
diff --git a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
index 4b8c9de..ce33401 100644
--- a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
@@ -28,11 +28,13 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
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.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -42,6 +44,7 @@
import android.os.Process;
import android.telephony.SubscriptionManager;
import android.util.ArraySet;
+import android.util.FeatureFlagUtils;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceManager;
@@ -51,22 +54,20 @@
import com.android.settings.applications.AppInfoBase;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowDataUsageUtils;
-import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
import com.android.settings.testutils.shadow.ShadowFragment;
import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
-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.core.AbstractPreferenceController;
import com.android.settingslib.net.UidDetail;
import com.android.settingslib.net.UidDetailProvider;
+import com.android.settingslib.widget.IntroPreference;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
@@ -79,27 +80,25 @@
import java.util.List;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowEntityHeaderController.class, ShadowRestrictedLockUtilsInternal.class})
+@Config(shadows = {ShadowRestrictedLockUtilsInternal.class})
public class AppDataUsageTest {
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private EntityHeaderController mHeaderController;
@Mock
private PackageManager mPackageManager;
+ private IntroPreference mIntroPreference;
+
private AppDataUsage mFragment;
+ private Context mContext;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- ShadowEntityHeaderController.setUseMock(mHeaderController);
- when(mHeaderController.setUid(anyInt())).thenReturn(mHeaderController);
- }
-
- @After
- public void tearDown() {
- ShadowEntityHeaderController.reset();
+ mContext = spy(RuntimeEnvironment.application);
+ mIntroPreference = new IntroPreference(mContext);
+ FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_ENABLE_SPA, true);
}
@Test
@@ -161,6 +160,7 @@
}
@Test
+ @Config(shadows = ShadowFragment.class)
public void bindAppHeader_allWorkApps_shouldNotShowAppInfoLink() {
mFragment = spy(new TestFragment());
@@ -169,12 +169,20 @@
doReturn(mock(PreferenceScreen.class)).when(mFragment).getPreferenceScreen();
ReflectionHelpers.setField(mFragment, "mAppItem", mock(AppItem.class));
- mFragment.addEntityHeader();
+ when(mFragment.getPreferenceScreen().findPreference(AppDataUsage.ARG_APP_HEADER))
+ .thenReturn(mIntroPreference);
+ when(mFragment.getContext()).thenReturn(mContext);
+ doNothing().when(mContext).startActivity(any());
- verify(mHeaderController).setHasAppInfoLink(false);
+ mFragment.setupIntroPreference();
+ mFragment.onPreferenceTreeClick(mIntroPreference);
+
+ verify(mFragment, never()).getActivity();
+ verify(mContext, never()).startActivity(any(Intent.class));
}
@Test
+ @Config(shadows = ShadowFragment.class)
public void bindAppHeader_workApp_shouldSetWorkAppUid()
throws PackageManager.NameNotFoundException {
final int fakeUserId = 100;
@@ -188,19 +196,21 @@
ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
ReflectionHelpers.setField(mFragment, "mPackages", packages);
- when(mPackageManager.getPackageUidAsUser(anyString(), anyInt()))
- .thenReturn(fakeUserId);
-
- when(mHeaderController.setHasAppInfoLink(anyBoolean())).thenReturn(mHeaderController);
-
+ when(mPackageManager.getPackageUidAsUser(anyString(), anyInt())).thenReturn(fakeUserId);
when(mFragment.getPreferenceManager())
.thenReturn(mock(PreferenceManager.class, RETURNS_DEEP_STUBS));
doReturn(mock(PreferenceScreen.class)).when(mFragment).getPreferenceScreen();
- mFragment.addEntityHeader();
+ when(mFragment.getPreferenceScreen().findPreference(AppDataUsage.ARG_APP_HEADER))
+ .thenReturn(mIntroPreference);
+ when(mFragment.getContext()).thenReturn(mContext);
+ doNothing().when(mContext).startActivity(any());
- verify(mHeaderController).setHasAppInfoLink(true);
- verify(mHeaderController).setUid(fakeUserId);
+ mFragment.setupIntroPreference();
+ mFragment.onPreferenceTreeClick(mIntroPreference);
+
+ ArgumentCaptor<Intent> argumentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).startActivity(argumentCaptor.capture());
}
@Test