From 625787b391d6e426d3c38c7a396db150f93651c5 Mon Sep 17 00:00:00 2001 From: Antony Sargent Date: Thu, 17 Jan 2019 12:59:30 -0800 Subject: [PATCH] Add data usage header to mobile network details page As a part of the work for subscriptions UI improvements, we want to show data usage information at the top of the mobile network details page, and those details need to be specific to the particular subscription we're showing details for, even if that SIM isn't the current default one. This is useful for seeing data usage across your SIMs in dual-SIM devices. This CL adapts our already existing DataUsageSummaryPreferenceController class so that if can be used on any fragment instead of just the DataUsageSummary one, and changes it to take an explicit subscription id instead of assuming it should use the default one. Bug: 122670283 Test: make RunSettingsRoboTests Change-Id: I41e307b0f32580c73b08adec7cabf01c96d7e835 --- res/xml/mobile_network_settings_v2.xml | 155 ++++++++++++++++++ .../settings/datausage/DataUsageSummary.java | 3 +- .../DataUsageSummaryPreferenceController.java | 52 +++--- .../telephony/MobileNetworkSettings.java | 27 ++- ...aUsageSummaryPreferenceControllerTest.java | 23 ++- .../telephony/MobileNetworkSettingsTest.java | 113 +++++++++++++ 6 files changed, 336 insertions(+), 37 deletions(-) create mode 100644 res/xml/mobile_network_settings_v2.xml create mode 100644 tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java diff --git a/res/xml/mobile_network_settings_v2.xml b/res/xml/mobile_network_settings_v2.xml new file mode 100644 index 00000000000..7a19c325334 --- /dev/null +++ b/res/xml/mobile_network_settings_v2.xml @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/android/settings/datausage/DataUsageSummary.java b/src/com/android/settings/datausage/DataUsageSummary.java index 97715db0f63..a4cab82b930 100644 --- a/src/com/android/settings/datausage/DataUsageSummary.java +++ b/src/com/android/settings/datausage/DataUsageSummary.java @@ -141,7 +141,8 @@ public class DataUsageSummary extends DataUsageBaseFragment implements DataUsage final Activity activity = getActivity(); final ArrayList controllers = new ArrayList<>(); mSummaryController = - new DataUsageSummaryPreferenceController(activity, getSettingsLifecycle(), this); + new DataUsageSummaryPreferenceController(activity, getSettingsLifecycle(), this, + DataUsageUtils.getDefaultSubscriptionId(activity)); controllers.add(mSummaryController); getSettingsLifecycle().addObserver(mSummaryController); return controllers; diff --git a/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java b/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java index d5707c4ac6f..353c5ee27bb 100644 --- a/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java +++ b/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java @@ -31,6 +31,7 @@ import android.util.RecurrenceRule; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; import androidx.recyclerview.widget.RecyclerView; import com.android.internal.util.CollectionUtils; @@ -47,9 +48,9 @@ import com.android.settingslib.net.DataUsageController; import java.util.List; /** - * This is the controller for the top of the data usage screen that retrieves carrier data from the - * new subscriptions framework API if available. The controller reads subscription information from - * the framework and falls back to legacy usage data if none are available. + * This is the controller for a data usage header that retrieves carrier data from the new + * subscriptions framework API if available. The controller reads subscription information from the + * framework and falls back to legacy usage data if none are available. */ public class DataUsageSummaryPreferenceController extends BasePreferenceController implements PreferenceControllerMixin, LifecycleObserver, OnStart { @@ -63,7 +64,7 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll private final Activity mActivity; private final EntityHeaderController mEntityHeaderController; private final Lifecycle mLifecycle; - private final DataUsageSummary mDataUsageSummary; + private final PreferenceFragmentCompat mFragment; private final DataUsageController mDataUsageController; private final DataUsageInfoController mDataInfoController; private final NetworkTemplate mDefaultTemplate; @@ -94,28 +95,31 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll private long mCycleStart; /** The ending time of the billing cycle in ms since the epoch */ private long mCycleEnd; + /** The subscription that we should show usage for. */ + private int mSubscriptionId; private Intent mManageSubscriptionIntent; public DataUsageSummaryPreferenceController(Activity activity, - Lifecycle lifecycle, DataUsageSummary dataUsageSummary) { + Lifecycle lifecycle, PreferenceFragmentCompat fragment, int subscriptionId) { super(activity, KEY); mActivity = activity; mEntityHeaderController = EntityHeaderController.newInstance(activity, - dataUsageSummary, null); + fragment, null); mLifecycle = lifecycle; - mDataUsageSummary = dataUsageSummary; + mFragment = fragment; + mSubscriptionId = subscriptionId; - final int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(activity); - mDefaultTemplate = DataUsageUtils.getDefaultTemplate(activity, defaultSubId); - NetworkPolicyManager policyManager = NetworkPolicyManager.from(activity); + mDefaultTemplate = DataUsageUtils.getDefaultTemplate(activity, mSubscriptionId); + NetworkPolicyManager policyManager = activity.getSystemService(NetworkPolicyManager.class); mPolicyEditor = new NetworkPolicyEditor(policyManager); mHasMobileData = DataUsageUtils.hasMobileData(activity) - && defaultSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID; + && mSubscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID; mDataUsageController = new DataUsageController(activity); + mDataUsageController.setSubscriptionId(mSubscriptionId); mDataInfoController = new DataUsageInfoController(); if (mHasMobileData) { @@ -142,7 +146,8 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll Activity activity, Lifecycle lifecycle, EntityHeaderController entityHeaderController, - DataUsageSummary dataUsageSummary) { + PreferenceFragmentCompat fragment, + int subscriptionId) { super(activity, KEY); mDataUsageController = dataUsageController; mDataInfoController = dataInfoController; @@ -154,12 +159,13 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll mActivity = activity; mLifecycle = lifecycle; mEntityHeaderController = entityHeaderController; - mDataUsageSummary = dataUsageSummary; + mFragment = fragment; + mSubscriptionId = subscriptionId; } @Override public void onStart() { - RecyclerView view = mDataUsageSummary.getListView(); + RecyclerView view = mFragment.getListView(); mEntityHeaderController.setRecyclerView(view, mLifecycle); mEntityHeaderController.styleActionBar(mActivity); } @@ -260,12 +266,18 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll mCycleEnd = info.cycleEnd; mSnapshotTime = -1L; - final int defaultSubId = SubscriptionManager.getDefaultSubscriptionId(); - final SubscriptionInfo subInfo = mSubscriptionManager.getDefaultDataSubscriptionInfo(); + SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(mSubscriptionId); + if (subInfo == null) { + subInfo = mSubscriptionManager.getAllSubscriptionInfoList().stream().filter( + i -> i.getSubscriptionId() == mSubscriptionId).findFirst().orElse(null); + } if (subInfo != null && mHasMobileData) { mCarrierName = subInfo.getCarrierName(); - List plans = mSubscriptionManager.getSubscriptionPlans(defaultSubId); - final SubscriptionPlan primaryPlan = getPrimaryPlan(mSubscriptionManager, defaultSubId); + List plans = mSubscriptionManager.getSubscriptionPlans( + mSubscriptionId); + final SubscriptionPlan primaryPlan = getPrimaryPlan(mSubscriptionManager, + mSubscriptionId); + if (primaryPlan != null) { mDataplanCount = plans.size(); mDataplanSize = primaryPlan.getDataLimitBytes(); @@ -284,8 +296,8 @@ public class DataUsageSummaryPreferenceController extends BasePreferenceControll } } mManageSubscriptionIntent = - mSubscriptionManager.createManageSubscriptionIntent(defaultSubId); - Log.i(TAG, "Have " + mDataplanCount + " plans, dflt sub-id " + defaultSubId + mSubscriptionManager.createManageSubscriptionIntent(mSubscriptionId); + Log.i(TAG, "Have " + mDataplanCount + " plans, dflt sub-id " + mSubscriptionId + ", intent " + mManageSubscriptionIntent); } diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java index 6e5dece5a01..9665c093da5 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java @@ -34,7 +34,10 @@ import androidx.preference.Preference; import com.android.internal.telephony.TelephonyIntents; import com.android.settings.R; +import com.android.settings.core.FeatureFlags; import com.android.settings.dashboard.RestrictedDashboardFragment; +import com.android.settings.datausage.DataUsageSummaryPreferenceController; +import com.android.settings.development.featureflags.FeatureFlagPersistent; import com.android.settings.network.telephony.cdma.CdmaSubscriptionPreferenceController; import com.android.settings.network.telephony.cdma.CdmaSystemSelectPreferenceController; import com.android.settings.network.telephony.gsm.AutoSelectPreferenceController; @@ -42,6 +45,7 @@ import com.android.settings.network.telephony.gsm.OpenNetworkSelectPagePreferenc import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settings.widget.PreferenceCategoryController; +import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.search.SearchIndexable; import java.util.ArrayList; @@ -105,12 +109,23 @@ public class MobileNetworkSettings extends RestrictedDashboardFragment { } @Override - public void onAttach(Context context) { - super.onAttach(context); - + protected List createPreferenceControllers(Context context) { mSubId = getArguments().getInt(Settings.EXTRA_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); + if (FeatureFlagPersistent.isEnabled(getContext(), FeatureFlags.NETWORK_INTERNET_V2) && + mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + return Arrays.asList( + new DataUsageSummaryPreferenceController(getActivity(), getSettingsLifecycle(), + this, mSubId)); + } + return Arrays.asList(); + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + use(MobileDataPreferenceController.class).init(getFragmentManager(), mSubId); use(RoamingPreferenceController.class).init(getFragmentManager(), mSubId); use(ApnPreferenceController.class).init(mSubId); @@ -163,7 +178,11 @@ public class MobileNetworkSettings extends RestrictedDashboardFragment { @Override protected int getPreferenceScreenResId() { - return R.xml.mobile_network_settings; + if (FeatureFlagPersistent.isEnabled(getContext(), FeatureFlags.NETWORK_INTERNET_V2)) { + return R.xml.mobile_network_settings_v2; + } else { + return R.xml.mobile_network_settings; + } } @Override diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java index d1cb63ed177..43476371423 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java @@ -34,11 +34,11 @@ import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkTemplate; -import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import androidx.fragment.app.FragmentActivity; +import androidx.preference.PreferenceFragmentCompat; import androidx.recyclerview.widget.RecyclerView; import com.android.internal.logging.nano.MetricsProto; @@ -92,7 +92,7 @@ public class DataUsageSummaryPreferenceControllerTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) private EntityHeaderController mHeaderController; @Mock - private DataUsageSummary mDataUsageSummary; + private PreferenceFragmentCompat mPreferenceFragment; @Mock private TelephonyManager mTelephonyManager; @Mock @@ -104,6 +104,7 @@ public class DataUsageSummaryPreferenceControllerTest { private FragmentActivity mActivity; private Context mContext; private DataUsageSummaryPreferenceController mController; + private int mDefaultSubscriptionId; @Before public void setUp() { @@ -125,6 +126,7 @@ public class DataUsageSummaryPreferenceControllerTest { .thenReturn(mConnectivityManager); when(mTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_READY); when(mConnectivityManager.isNetworkSupported(TYPE_WIFI)).thenReturn(false); + mDefaultSubscriptionId = 1234; mController = new DataUsageSummaryPreferenceController( mDataUsageController, mDataInfoController, @@ -133,7 +135,7 @@ public class DataUsageSummaryPreferenceControllerTest { R.string.cell_data_template, true, null, - mActivity, null, null, null); + mActivity, null, null, null, mDefaultSubscriptionId); } @After @@ -355,11 +357,7 @@ public class DataUsageSummaryPreferenceControllerTest { R.string.cell_data_template, true, mSubscriptionManager, - mActivity, null, null, null); - - final SubscriptionInfo subInfo = new SubscriptionInfo(0, "123456", 0, "name", "carrier", - 0, 0, "number", 0, null, "123", "456", "ZX", false, null, null); - when(mSubscriptionManager.getDefaultDataSubscriptionInfo()).thenReturn(subInfo); + mActivity, null, null, null, mDefaultSubscriptionId); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @@ -373,7 +371,7 @@ public class DataUsageSummaryPreferenceControllerTest { R.string.cell_data_template, true, mSubscriptionManager, - mActivity, null, null, null); + mActivity, null, null, null, mDefaultSubscriptionId); when(mTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_ABSENT); when(mConnectivityManager.isNetworkSupported(TYPE_WIFI)).thenReturn(false); @@ -390,7 +388,7 @@ public class DataUsageSummaryPreferenceControllerTest { R.string.cell_data_template, true, mSubscriptionManager, - mActivity, null, null, null); + mActivity, null, null, null, mDefaultSubscriptionId); when(mTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_ABSENT); when(mConnectivityManager.isNetworkSupported(TYPE_WIFI)).thenReturn(true); @@ -409,9 +407,10 @@ public class DataUsageSummaryPreferenceControllerTest { R.string.cell_data_template, true, mSubscriptionManager, - mActivity, mLifecycle, mHeaderController, mDataUsageSummary); + mActivity, mLifecycle, mHeaderController, mPreferenceFragment, + mDefaultSubscriptionId); - when(mDataUsageSummary.getListView()).thenReturn(recyclerView); + when(mPreferenceFragment.getListView()).thenReturn(recyclerView); mController.onStart(); diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java new file mode 100644 index 00000000000..0240bd834f8 --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2019 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.telephony; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.app.usage.NetworkStatsManager; +import android.content.Context; +import android.net.NetworkPolicyManager; +import android.os.Bundle; +import android.provider.Settings; +import android.telephony.TelephonyManager; + +import com.android.settings.core.FeatureFlags; +import com.android.settings.datausage.DataUsageSummaryPreferenceController; +import com.android.settings.development.featureflags.FeatureFlagPersistent; +import com.android.settings.testutils.shadow.ShadowEntityHeaderController; +import com.android.settings.widget.EntityHeaderController; +import com.android.settingslib.core.AbstractPreferenceController; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import java.util.List; + +import androidx.fragment.app.FragmentActivity; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = ShadowEntityHeaderController.class) +public class MobileNetworkSettingsTest { + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private NetworkStatsManager mNetworkStatsManager; + @Mock + private NetworkPolicyManager mNetworkPolicyManager; + @Mock + private FragmentActivity mActivity; + + private Context mContext; + private MobileNetworkSettings mFragment; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager); + when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager); + when(mContext.getSystemService(NetworkStatsManager.class)).thenReturn(mNetworkStatsManager); + ShadowEntityHeaderController.setUseMock(mock(EntityHeaderController.class)); + + mFragment = spy(new MobileNetworkSettings()); + final Bundle args = new Bundle(); + final int subscriptionId = 1234; + args.putInt(Settings.EXTRA_SUB_ID, subscriptionId); + mFragment.setArguments(args); + when(mFragment.getActivity()).thenReturn(mActivity); + when(mActivity.getSystemService(NetworkPolicyManager.class)).thenReturn( + mNetworkPolicyManager); + } + + @Test + public void onAttach_noCrash() { + mFragment.onAttach(mContext); + } + + @Test + public void createPreferenceControllers_noV2Flag_noDataUsageSummaryController() { + final List controllers = + mFragment.createPreferenceControllers(mContext); + assertThat(controllers.stream().filter( + c -> c.getClass().equals(DataUsageSummaryPreferenceController.class)) + .count()) + .isEqualTo(0); + } + + @Test + public void createPreferenceControllers_v2Flag_createsDataUsageSummaryController() { + FeatureFlagPersistent.setEnabled(mContext, FeatureFlags.NETWORK_INTERNET_V2, true); + + final List controllers = + mFragment.createPreferenceControllers(mContext); + assertThat(controllers.stream().filter( + c -> c.getClass().equals(DataUsageSummaryPreferenceController.class)) + .count()) + .isEqualTo(1); + } +}