Merge changes from topic "AppDataUsage" into main
* changes: [Expressive design] Update AppDataUsage. [Expressive design] Rename ComposeMainSwitchPreference to ComposeGroupSectionPreference.
This commit is contained in:
@@ -20,11 +20,15 @@
|
|||||||
android:key="app_data_usage_screen"
|
android:key="app_data_usage_screen"
|
||||||
android:title="@string/data_usage_app_summary_title">
|
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
|
<com.android.settings.datausage.SpinnerPreference
|
||||||
android:key="cycle"
|
android:key="cycle"
|
||||||
settings:controller="com.android.settings.datausage.AppDataUsageCycleController" />
|
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"
|
android:key="app_data_usage_summary"
|
||||||
settings:controller="com.android.settings.datausage.AppDataUsageSummaryController"/>
|
settings:controller="com.android.settings.datausage.AppDataUsageSummaryController"/>
|
||||||
|
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||||
android:key="mobile_network_pref_screen">
|
android:key="mobile_network_pref_screen">
|
||||||
|
|
||||||
<com.android.settings.spa.preference.ComposeMainSwitchPreference
|
<com.android.settings.spa.preference.ComposeGroupSectionPreference
|
||||||
android:key="use_sim_switch"
|
android:key="use_sim_switch"
|
||||||
settings:controller="com.android.settings.network.telephony.MobileNetworkSwitchController"/>
|
settings:controller="com.android.settings.network.telephony.MobileNetworkSwitchController"/>
|
||||||
|
|
||||||
|
@@ -18,6 +18,7 @@ import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
|
|||||||
|
|
||||||
import static com.android.settings.datausage.lib.AppDataUsageRepository.getAppUid;
|
import static com.android.settings.datausage.lib.AppDataUsageRepository.getAppUid;
|
||||||
import static com.android.settings.datausage.lib.AppDataUsageRepository.getAppUidList;
|
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.Activity;
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
@@ -45,13 +46,14 @@ import com.android.settings.datausage.lib.AppDataUsageDetailsRepository;
|
|||||||
import com.android.settings.datausage.lib.NetworkTemplates;
|
import com.android.settings.datausage.lib.NetworkTemplates;
|
||||||
import com.android.settings.fuelgauge.datasaver.DynamicDenylistManager;
|
import com.android.settings.fuelgauge.datasaver.DynamicDenylistManager;
|
||||||
import com.android.settings.network.SubscriptionUtil;
|
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.AppItem;
|
||||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||||
import com.android.settingslib.RestrictedSwitchPreference;
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
import com.android.settingslib.net.UidDetail;
|
import com.android.settingslib.net.UidDetail;
|
||||||
import com.android.settingslib.net.UidDetailProvider;
|
import com.android.settingslib.net.UidDetailProvider;
|
||||||
|
import com.android.settingslib.widget.IntroPreference;
|
||||||
|
|
||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
|
|
||||||
@@ -65,6 +67,8 @@ public class AppDataUsage extends DataUsageBaseFragment implements OnPreferenceC
|
|||||||
private static final String TAG = "AppDataUsage";
|
private static final String TAG = "AppDataUsage";
|
||||||
|
|
||||||
static final String ARG_APP_ITEM = "app_item";
|
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_TEMPLATE = "network_template";
|
||||||
static final String ARG_NETWORK_CYCLES = "network_cycles";
|
static final String ARG_NETWORK_CYCLES = "network_cycles";
|
||||||
static final String ARG_SELECTED_CYCLE = "selected_cycle";
|
static final String ARG_SELECTED_CYCLE = "selected_cycle";
|
||||||
@@ -176,7 +180,7 @@ public class AppDataUsage extends DataUsageBaseFragment implements OnPreferenceC
|
|||||||
removePreference(KEY_RESTRICT_BACKGROUND);
|
removePreference(KEY_RESTRICT_BACKGROUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
addEntityHeader();
|
setupIntroPreference();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -320,32 +324,32 @@ public class AppDataUsage extends DataUsageBaseFragment implements OnPreferenceC
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void addEntityHeader() {
|
void setupIntroPreference() {
|
||||||
String pkg = mPackages.size() != 0 ? mPackages.valueAt(0) : null;
|
final Preference pref = getPreferenceScreen().findPreference(ARG_APP_HEADER);
|
||||||
int uid = 0;
|
if (pref != null) {
|
||||||
if (pkg != 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 {
|
try {
|
||||||
uid = mPackageManager.getPackageUidAsUser(pkg,
|
int uid = mPackageManager.getPackageUidAsUser(pkg,
|
||||||
UserHandle.getUserId(mAppItem.key));
|
UserHandle.getUserId(mAppItem.key));
|
||||||
|
startAppInfoSettings(pkg, uid, this, 0 /* request */,
|
||||||
|
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
|
||||||
|
.getMetricsCategory(this));
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
Log.w(TAG, "Skipping UID because cannot find package " + pkg);
|
Log.w(TAG, "Skipping UID because cannot find package " + pkg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -17,7 +17,6 @@
|
|||||||
package com.android.settings.datausage
|
package com.android.settings.datausage
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@@ -28,6 +27,7 @@ import com.android.settings.datausage.lib.NetworkUsageDetailsData
|
|||||||
import com.android.settings.spa.preference.ComposePreferenceController
|
import com.android.settings.spa.preference.ComposePreferenceController
|
||||||
import com.android.settingslib.spa.widget.preference.Preference
|
import com.android.settingslib.spa.widget.preference.Preference
|
||||||
import com.android.settingslib.spa.widget.preference.PreferenceModel
|
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 com.android.settingslib.spaprivileged.framework.compose.getPlaceholder
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
@@ -60,7 +60,7 @@ class AppDataUsageSummaryController(context: Context, preferenceKey: String) :
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
Column {
|
Category {
|
||||||
val totalUsage by totalUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
|
val totalUsage by totalUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
|
||||||
val foregroundUsage by foregroundUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
|
val foregroundUsage by foregroundUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
|
||||||
val backgroundUsage by backgroundUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
|
val backgroundUsage by backgroundUsageFlow.collectAsStateWithLifecycle(emptyDataUsage)
|
||||||
|
@@ -25,8 +25,10 @@ import androidx.preference.Preference;
|
|||||||
import androidx.preference.PreferenceViewHolder;
|
import androidx.preference.PreferenceViewHolder;
|
||||||
|
|
||||||
import com.android.settings.R;
|
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;
|
private CycleAdapter mAdapter;
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@@ -28,7 +28,7 @@ import com.android.settings.R
|
|||||||
import com.android.settingslib.spa.framework.theme.SettingsTheme
|
import com.android.settingslib.spa.framework.theme.SettingsTheme
|
||||||
import com.android.settingslib.widget.GroupSectionDividerMixin
|
import com.android.settingslib.widget.GroupSectionDividerMixin
|
||||||
|
|
||||||
open class ComposeMainSwitchPreference @JvmOverloads constructor(
|
open class ComposeGroupSectionPreference @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = 0,
|
defStyleAttr: Int = 0,
|
||||||
|
@@ -28,11 +28,13 @@ import static org.mockito.Mockito.doNothing;
|
|||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.eq;
|
import static org.mockito.Mockito.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
@@ -42,6 +44,7 @@ import android.os.Bundle;
|
|||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.telephony.SubscriptionManager;
|
import android.telephony.SubscriptionManager;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
|
import android.util.FeatureFlagUtils;
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
@@ -51,22 +54,20 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import com.android.settings.applications.AppInfoBase;
|
import com.android.settings.applications.AppInfoBase;
|
||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
import com.android.settings.testutils.shadow.ShadowDataUsageUtils;
|
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.ShadowFragment;
|
||||||
import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
|
import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
|
||||||
import com.android.settings.widget.EntityHeaderController;
|
|
||||||
import com.android.settingslib.AppItem;
|
import com.android.settingslib.AppItem;
|
||||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||||
import com.android.settingslib.RestrictedSwitchPreference;
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
import com.android.settingslib.core.AbstractPreferenceController;
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
import com.android.settingslib.net.UidDetail;
|
import com.android.settingslib.net.UidDetail;
|
||||||
import com.android.settingslib.net.UidDetailProvider;
|
import com.android.settingslib.net.UidDetailProvider;
|
||||||
|
import com.android.settingslib.widget.IntroPreference;
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Answers;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.Robolectric;
|
import org.robolectric.Robolectric;
|
||||||
@@ -79,27 +80,25 @@ import org.robolectric.util.ReflectionHelpers;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
@Config(shadows = {ShadowEntityHeaderController.class, ShadowRestrictedLockUtilsInternal.class})
|
@Config(shadows = {ShadowRestrictedLockUtilsInternal.class})
|
||||||
public class AppDataUsageTest {
|
public class AppDataUsageTest {
|
||||||
|
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
|
||||||
private EntityHeaderController mHeaderController;
|
|
||||||
@Mock
|
@Mock
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
|
|
||||||
|
private IntroPreference mIntroPreference;
|
||||||
|
|
||||||
private AppDataUsage mFragment;
|
private AppDataUsage mFragment;
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
ShadowEntityHeaderController.setUseMock(mHeaderController);
|
mContext = spy(RuntimeEnvironment.application);
|
||||||
when(mHeaderController.setUid(anyInt())).thenReturn(mHeaderController);
|
mIntroPreference = new IntroPreference(mContext);
|
||||||
}
|
FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_ENABLE_SPA, true);
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() {
|
|
||||||
ShadowEntityHeaderController.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -161,6 +160,7 @@ public class AppDataUsageTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Config(shadows = ShadowFragment.class)
|
||||||
public void bindAppHeader_allWorkApps_shouldNotShowAppInfoLink() {
|
public void bindAppHeader_allWorkApps_shouldNotShowAppInfoLink() {
|
||||||
mFragment = spy(new TestFragment());
|
mFragment = spy(new TestFragment());
|
||||||
|
|
||||||
@@ -169,12 +169,20 @@ public class AppDataUsageTest {
|
|||||||
doReturn(mock(PreferenceScreen.class)).when(mFragment).getPreferenceScreen();
|
doReturn(mock(PreferenceScreen.class)).when(mFragment).getPreferenceScreen();
|
||||||
ReflectionHelpers.setField(mFragment, "mAppItem", mock(AppItem.class));
|
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
|
@Test
|
||||||
|
@Config(shadows = ShadowFragment.class)
|
||||||
public void bindAppHeader_workApp_shouldSetWorkAppUid()
|
public void bindAppHeader_workApp_shouldSetWorkAppUid()
|
||||||
throws PackageManager.NameNotFoundException {
|
throws PackageManager.NameNotFoundException {
|
||||||
final int fakeUserId = 100;
|
final int fakeUserId = 100;
|
||||||
@@ -188,19 +196,21 @@ public class AppDataUsageTest {
|
|||||||
ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
|
ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
|
||||||
ReflectionHelpers.setField(mFragment, "mPackages", packages);
|
ReflectionHelpers.setField(mFragment, "mPackages", packages);
|
||||||
|
|
||||||
when(mPackageManager.getPackageUidAsUser(anyString(), anyInt()))
|
when(mPackageManager.getPackageUidAsUser(anyString(), anyInt())).thenReturn(fakeUserId);
|
||||||
.thenReturn(fakeUserId);
|
|
||||||
|
|
||||||
when(mHeaderController.setHasAppInfoLink(anyBoolean())).thenReturn(mHeaderController);
|
|
||||||
|
|
||||||
when(mFragment.getPreferenceManager())
|
when(mFragment.getPreferenceManager())
|
||||||
.thenReturn(mock(PreferenceManager.class, RETURNS_DEEP_STUBS));
|
.thenReturn(mock(PreferenceManager.class, RETURNS_DEEP_STUBS));
|
||||||
doReturn(mock(PreferenceScreen.class)).when(mFragment).getPreferenceScreen();
|
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);
|
mFragment.setupIntroPreference();
|
||||||
verify(mHeaderController).setUid(fakeUserId);
|
mFragment.onPreferenceTreeClick(mIntroPreference);
|
||||||
|
|
||||||
|
ArgumentCaptor<Intent> argumentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||||
|
verify(mContext).startActivity(argumentCaptor.capture());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Reference in New Issue
Block a user