diff --git a/res/xml/data_plan_usage.xml b/res/xml/data_plan_usage.xml new file mode 100644 index 00000000000..4691198bf77 --- /dev/null +++ b/res/xml/data_plan_usage.xml @@ -0,0 +1,25 @@ + + + + + + + + + diff --git a/res/xml/data_plan_usage_cell_data_preference_screen.xml b/res/xml/data_plan_usage_cell_data_preference_screen.xml new file mode 100644 index 00000000000..08f21c55ca4 --- /dev/null +++ b/res/xml/data_plan_usage_cell_data_preference_screen.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + diff --git a/src/com/android/settings/datausage/DataPlanUsageSummary.java b/src/com/android/settings/datausage/DataPlanUsageSummary.java new file mode 100644 index 00000000000..5132d553b1b --- /dev/null +++ b/src/com/android/settings/datausage/DataPlanUsageSummary.java @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2017 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 static android.net.NetworkPolicy.LIMIT_DISABLED; + +import android.annotation.IdRes; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.net.NetworkPolicy; +import android.net.NetworkPolicyManager; +import android.net.NetworkTemplate; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.os.UserManager; +import android.provider.SearchIndexableResource; +import android.provider.Settings; +import android.support.annotation.VisibleForTesting; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceCategory; +import android.support.v7.preference.PreferenceScreen; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.text.TextUtils; +import android.text.format.Formatter; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.dashboard.SummaryLoader; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.Indexable; +import com.android.settingslib.NetworkPolicyEditor; +import com.android.settingslib.net.DataUsageController; +import java.util.ArrayList; +import java.util.List; + +public class DataPlanUsageSummary extends DataUsageBase implements Indexable { + + public static final String KEY_RESTRICT_BACKGROUND = "restrict_background"; + public static final String KEY_NETWORK_RESTRICTIONS = "network_restrictions"; + private static final String KEY_DATA_PLAN_USAGE = "data_plan_usage"; + + private static final String KEY_STATUS_HEADER = "status_header"; + private static final String KEY_LIMIT_SUMMARY = "plan_summary"; + private static final String KEY_MOBILE_USAGE_TITLE = "data_usage_mobile_category"; + private static final String KEY_WIFI_USAGE_TITLE = "wifi_category"; + + private DataUsageController mDataUsageController; + private DataUsageInfoController mDataInfoController; + private List mDataPlanSummaryPreferenceList; + private Preference mLimitPreference; + private NetworkTemplate mDefaultTemplate; + private NetworkRestrictionsPreference mNetworkRestrictionPreference; + private WifiManager mWifiManager; + private NetworkPolicyEditor mPolicyEditor; + + @Override + protected int getHelpResource() { + return R.string.help_url_data_usage; + } + + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + + final Context context = getContext(); + NetworkPolicyManager policyManager = NetworkPolicyManager.from(context); + mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + mPolicyEditor = new NetworkPolicyEditor(policyManager); + mDataUsageController = new DataUsageController(context); + mDataInfoController = new DataUsageInfoController(); + + int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(context); + boolean hasMobileData = DataUsageUtils.hasMobileData(context); + if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + hasMobileData = false; + } + mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId); + + if (!hasMobileData || !isAdmin()) { + removePreference(KEY_RESTRICT_BACKGROUND); + } + + if (hasMobileData) { + addDataPlanSection(defaultSubId); + } + + if (DataUsageUtils.hasWifiRadio(context)) { + addWifiSection(); + } + + if (hasEthernet(context)) { + addEthernetSection(); + } + setHasOptionsMenu(true); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + if (UserManager.get(getContext()).isAdminUser()) { + inflater.inflate(R.menu.data_usage, menu); + } + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.data_usage_menu_cellular_networks: { + final Intent intent = new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS); + startActivity(intent); + return true; + } + } + return false; + } + + private void addDataPlanSection(int defaultSubId) { + Context context = getPrefContext(); + addPreferencesFromResource(R.xml.data_plan_usage); + PreferenceScreen screen = getPreferenceScreen(); + screen.setTitle(context.getString(R.string.data_usage_summary_title)); + + PreferenceCategory preferenceCategory = + (PreferenceCategory) findPreference(KEY_DATA_PLAN_USAGE); + screen.addPreference(preferenceCategory); + + Preference dataPlansSyncTimePreference = new Preference(context); + dataPlansSyncTimePreference.setLayoutResource(R.layout.data_plans_sync_time_preference); + dataPlansSyncTimePreference.setTitle(MockDataPlanUsage.SYNC_TIME); + preferenceCategory.addPreference(dataPlansSyncTimePreference); + + mDataPlanSummaryPreferenceList = new ArrayList<>(MockDataPlanUsage.DATA_PLAN_USAGES.length); + for (int i = 0; i < MockDataPlanUsage.DATA_PLAN_USAGES.length; i++) { + DataPlanSummaryPreference dataPlanSummaryPreference = + new DataPlanSummaryPreference(context); + dataPlanSummaryPreference.setKey(KEY_STATUS_HEADER + (i + 1)); + mDataPlanSummaryPreferenceList.add(dataPlanSummaryPreference); + preferenceCategory.addPreference(dataPlanSummaryPreference); + } + + Preference preference = new Preference(context); + preference.setLayoutResource(R.layout.manage_data_plans_preference); + preferenceCategory.addPreference(preference); + setPreferenceScreen(screen); + + mLimitPreference = findPreference(KEY_LIMIT_SUMMARY); + List subscriptions = + services.mSubscriptionManager.getActiveSubscriptionInfoList(); + + if (subscriptions == null || subscriptions.isEmpty()) { + addMobileSection(defaultSubId); + } + + for (int i = 0, subscriptionsSize = subscriptions != null ? subscriptions.size() : 0; + i < subscriptionsSize; i++) { + SubscriptionInfo subInfo = subscriptions.get(i); + if (subscriptionsSize > 1) { + addMobileSection(subInfo.getSubscriptionId(), subInfo); + } else { + addMobileSection(subInfo.getSubscriptionId()); + } + } + } + + private void addMobileSection(int subId) { + addMobileSection(subId, null); + } + + private void addMobileSection(int subId, SubscriptionInfo subInfo) { + TemplatePreferenceCategory category = (TemplatePreferenceCategory) + inflatePreferences(R.xml.data_plan_usage_cell_data_preference_screen); + category.setTemplate(getNetworkTemplate(subId), subId, services); + category.pushTemplates(services); + if (subInfo != null && !TextUtils.isEmpty(subInfo.getDisplayName())) { + Preference title = category.findPreference(KEY_MOBILE_USAGE_TITLE); + title.setTitle(subInfo.getDisplayName()); + } + } + + private void addWifiSection() { + TemplatePreferenceCategory category = (TemplatePreferenceCategory) + inflatePreferences(R.xml.data_usage_wifi); + category.setTemplate(NetworkTemplate.buildTemplateWifiWildcard(), 0 /* subId */, services); + mNetworkRestrictionPreference = + (NetworkRestrictionsPreference) category.findPreference(KEY_NETWORK_RESTRICTIONS); + } + + private void addEthernetSection() { + TemplatePreferenceCategory category = (TemplatePreferenceCategory) + inflatePreferences(R.xml.data_usage_ethernet); + category.setTemplate(NetworkTemplate.buildTemplateEthernet(), 0 /* subId */, services); + } + + private Preference inflatePreferences(@IdRes int resId) { + PreferenceScreen rootPreferences = getPreferenceManager().inflateFromResource( + getPrefContext(), resId, null); + Preference pref = rootPreferences.getPreference(0); + rootPreferences.removeAll(); + + PreferenceScreen screen = getPreferenceScreen(); + pref.setOrder(screen.getPreferenceCount()); + screen.addPreference(pref); + + return pref; + } + + private NetworkTemplate getNetworkTemplate(int subscriptionId) { + NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll( + services.mTelephonyManager.getSubscriberId(subscriptionId)); + return NetworkTemplate.normalize(mobileAll, + services.mTelephonyManager.getMergedSubscriberIds()); + } + + @Override + public void onResume() { + super.onResume(); + updateState(); + } + + private void updateState() { + DataUsageController.DataUsageInfo info = mDataUsageController.getDataUsageInfo( + mDefaultTemplate); + + Context context = getContext(); + mDataInfoController.updateDataLimit(info, + services.mPolicyEditor.getPolicy(mDefaultTemplate)); + + // TODO(b/63391323): Get rid of MockDataPlanUsage once we integrate with data plan APIs + if (mDataPlanSummaryPreferenceList != null && !mDataPlanSummaryPreferenceList.isEmpty()) { + MockDataPlanUsage[] dataPlanUsages = MockDataPlanUsage.getDataPlanUsage(); + for (int i = 0; i < dataPlanUsages.length; i++) { + DataPlanSummaryPreference dataPlanSummaryPreference = + mDataPlanSummaryPreferenceList.get(i); + MockDataPlanUsage dataPlanUsage = dataPlanUsages[i]; + dataPlanSummaryPreference.setTitle(dataPlanUsage.mUsage); + dataPlanSummaryPreference.setUsageTextColor(dataPlanUsage.mUsageTextColor); + dataPlanSummaryPreference.setName(dataPlanUsage.mName); + dataPlanSummaryPreference.setPercentageUsage(dataPlanUsage.mPercentageUsage); + dataPlanSummaryPreference + .setMeterBackgroundColor(dataPlanUsage.mMeterBackgroundColor); + dataPlanSummaryPreference.setMeterConsumedColor(dataPlanUsage.mMeterConsumedColor); + dataPlanSummaryPreference.setDescription(dataPlanUsage.mDescription); + } + } + + if (mLimitPreference != null && (info.warningLevel > 0 || info.limitLevel > 0)) { + String warning = Formatter.formatFileSize(context, info.warningLevel); + String limit = Formatter.formatFileSize(context, info.limitLevel); + mLimitPreference.setSummary(getString(info.limitLevel <= 0 ? R.string.cell_warning_only + : R.string.cell_warning_and_limit, warning, limit)); + } else if (mLimitPreference != null) { + mLimitPreference.setSummary(null); + } + + updateNetworkRestrictionSummary(mNetworkRestrictionPreference); + + PreferenceScreen screen = getPreferenceScreen(); + for (int i = 1, preferenceCount = screen.getPreferenceCount(); i < preferenceCount; i++) { + ((TemplatePreferenceCategory) screen.getPreference(i)).pushTemplates(services); + } + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.DATA_USAGE_SUMMARY; + } + + @VisibleForTesting + void updateNetworkRestrictionSummary(NetworkRestrictionsPreference preference) { + if (preference == null) { + return; + } + mPolicyEditor.read(); + int count = 0; + List configuredNetworks = mWifiManager.getConfiguredNetworks(); + for (int i = 0, configuredNetworksSize = configuredNetworks.size(); + i < configuredNetworksSize; i++) { + WifiConfiguration config = configuredNetworks.get(i); + if (isMetered(config)) { + count++; + } + } + preference.setSummary(getResources().getQuantityString( + R.plurals.network_restrictions_summary, count, count)); + } + + @VisibleForTesting + boolean isMetered(WifiConfiguration config) { + if (config.SSID == null) { + return false; + } + final String networkId = config.isPasspoint() ? config.providerFriendlyName : config.SSID; + final NetworkPolicy policy = + mPolicyEditor.getPolicyMaybeUnquoted(NetworkTemplate.buildTemplateWifi(networkId)); + if (policy == null) { + return false; + } + if (policy.limitBytes != LIMIT_DISABLED) { + return true; + } + return policy.metered; + } + + private static class SummaryProvider + implements SummaryLoader.SummaryProvider { + + private final Activity mActivity; + private final SummaryLoader mSummaryLoader; + private final DataUsageController mDataController; + + public SummaryProvider(Activity activity, SummaryLoader summaryLoader) { + mActivity = activity; + mSummaryLoader = summaryLoader; + mDataController = new DataUsageController(activity); + } + + @Override + public void setListening(boolean listening) { + if (listening) { + DataUsageController.DataUsageInfo info = mDataController.getDataUsageInfo(); + String used; + if (info == null) { + used = Formatter.formatFileSize(mActivity, 0); + } else if (info.limitLevel <= 0) { + used = Formatter.formatFileSize(mActivity, info.usageLevel); + } else { + used = Utils.formatPercentage(info.usageLevel, info.limitLevel); + } + mSummaryLoader.setSummary(this, + mActivity.getString(R.string.data_usage_summary_format, used)); + } + } + } + + public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY + = SummaryProvider::new; + + /** + * For search + */ + public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + List resources = new ArrayList<>(); + SearchIndexableResource resource = new SearchIndexableResource(context); + resource.xmlResId = R.xml.data_plan_usage; + resources.add(resource); + + if (DataUsageUtils.hasMobileData(context)) { + resource = new SearchIndexableResource(context); + resource.xmlResId = R.xml.data_plan_usage_cell_data_preference_screen; + resources.add(resource); + } + if (DataUsageUtils.hasWifiRadio(context)) { + resource = new SearchIndexableResource(context); + resource.xmlResId = R.xml.data_usage_wifi; + resources.add(resource); + } + return resources; + } + + @Override + public List getNonIndexableKeys(Context context) { + List keys = super.getNonIndexableKeys(context); + + if (DataUsageUtils.hasMobileData(context)) { + keys.add(KEY_RESTRICT_BACKGROUND); + } + if (DataUsageUtils.hasWifiRadio(context)) { + keys.add(KEY_NETWORK_RESTRICTIONS); + } + keys.add(KEY_WIFI_USAGE_TITLE); + + return keys; + } + }; +} + diff --git a/src/com/android/settings/datausage/DataUsageBase.java b/src/com/android/settings/datausage/DataUsageBase.java index 1325620a776..f08d534cf8a 100644 --- a/src/com/android/settings/datausage/DataUsageBase.java +++ b/src/com/android/settings/datausage/DataUsageBase.java @@ -14,14 +14,21 @@ package com.android.settings.datausage; +import static android.net.ConnectivityManager.TYPE_ETHERNET; + import android.content.Context; +import android.net.ConnectivityManager; import android.net.INetworkStatsService; +import android.net.INetworkStatsSession; import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; +import android.net.NetworkTemplate; +import android.net.TrafficStats; import android.os.Bundle; import android.os.INetworkManagementService; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; import android.os.UserManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -31,6 +38,7 @@ import com.android.settingslib.NetworkPolicyEditor; public abstract class DataUsageBase extends SettingsPreferenceFragment { private static final String TAG = "DataUsageBase"; + private static final String ETHERNET = "ethernet"; protected final TemplatePreference.NetworkServices services = new TemplatePreference.NetworkServices(); @@ -83,8 +91,38 @@ public abstract class DataUsageBase extends SettingsPreferenceFragment { try { return services.mNetworkService.isBandwidthControlEnabled(); } catch (RemoteException e) { - Log.w(TAG, "problem talking with INetworkManagementService: " + e); + Log.w(TAG, "problem talking with INetworkManagementService: ", e); return false; } } + + /** + * Test if device has an ethernet network connection. + */ + public boolean hasEthernet(Context context) { + if (DataUsageUtils.TEST_RADIOS) { + return SystemProperties.get(DataUsageUtils.TEST_RADIOS_PROP).contains(ETHERNET); + } + + final ConnectivityManager conn = ConnectivityManager.from(context); + final boolean hasEthernet = conn.isNetworkSupported(TYPE_ETHERNET); + + final long ethernetBytes; + try { + INetworkStatsSession statsSession = services.mStatsService.openSession(); + if (statsSession != null) { + ethernetBytes = statsSession.getSummaryForNetwork( + NetworkTemplate.buildTemplateEthernet(), Long.MIN_VALUE, Long.MAX_VALUE) + .getTotalBytes(); + TrafficStats.closeQuietly(statsSession); + } else { + ethernetBytes = 0; + } + } catch (RemoteException e) { + throw new RuntimeException(e); + } + + // only show ethernet when both hardware present and traffic has occurred + return hasEthernet && ethernetBytes > 0; + } } diff --git a/src/com/android/settings/datausage/DataUsageSummary.java b/src/com/android/settings/datausage/DataUsageSummary.java index c4d9d6f7749..ec47a4d1cff 100644 --- a/src/com/android/settings/datausage/DataUsageSummary.java +++ b/src/com/android/settings/datausage/DataUsageSummary.java @@ -58,6 +58,12 @@ import com.android.settingslib.net.DataUsageController; import java.util.ArrayList; import java.util.List; +/** + * Settings preference fragment that displays data usage summary. + * + * This class in deprecated use {@link DataPlanUsageSummary}. + */ +@Deprecated public class DataUsageSummary extends DataUsageBase implements Indexable, DataUsageEditController { static final boolean LOGD = false; @@ -311,36 +317,6 @@ public class DataUsageSummary extends DataUsageBase implements Indexable, DataUs updateState(); } - /** - * Test if device has an ethernet network connection. - */ - public boolean hasEthernet(Context context) { - if (DataUsageUtils.TEST_RADIOS) { - return SystemProperties.get(DataUsageUtils.TEST_RADIOS_PROP).contains("ethernet"); - } - - final ConnectivityManager conn = ConnectivityManager.from(context); - final boolean hasEthernet = conn.isNetworkSupported(TYPE_ETHERNET); - - final long ethernetBytes; - try { - INetworkStatsSession statsSession = services.mStatsService.openSession(); - if (statsSession != null) { - ethernetBytes = statsSession.getSummaryForNetwork( - NetworkTemplate.buildTemplateEthernet(), Long.MIN_VALUE, Long.MAX_VALUE) - .getTotalBytes(); - TrafficStats.closeQuietly(statsSession); - } else { - ethernetBytes = 0; - } - } catch (RemoteException e) { - throw new RuntimeException(e); - } - - // only show ethernet when both hardware present and traffic has occurred - return hasEthernet && ethernetBytes > 0; - } - @VisibleForTesting void updateNetworkRestrictionSummary(NetworkRestrictionsPreference preference) { if (preference == null) { diff --git a/src/com/android/settings/datausage/MockDataPlanUsage.java b/src/com/android/settings/datausage/MockDataPlanUsage.java new file mode 100644 index 00000000000..e3aa97af080 --- /dev/null +++ b/src/com/android/settings/datausage/MockDataPlanUsage.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2017 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.graphics.Color; + +/** + * Mock data plan usage data. + */ +@Deprecated // This class is only needed because we don't have working API yet. +final class MockDataPlanUsage { + static final MockDataPlanUsage[] DATA_PLAN_USAGES = new MockDataPlanUsage[3]; + static final String SYNC_TIME = "Today 12:24pm"; + final String mUsage; + final int mUsageTextColor; + final String mName; + final double mPercentageUsage; + final int mMeterBackgroundColor; + final int mMeterConsumedColor; + final String mDescription; + + private MockDataPlanUsage(String usage, int usageTextColor, String name, + double percentageUsage, int meterBackgroundColor, int meterConsumedColor, + String description) { + mUsage = usage; + mUsageTextColor = usageTextColor; + mName = name; + mPercentageUsage = percentageUsage; + mMeterBackgroundColor = meterBackgroundColor; + mMeterConsumedColor = meterConsumedColor; + mDescription = description; + } + + static MockDataPlanUsage[] getDataPlanUsage() { + DATA_PLAN_USAGES[0] = new MockDataPlanUsage("100 MB and 14 days left", + Color.parseColor("#FF5C94F1"), "GigaMaxLite / 1GB", 0.27D, + Color.parseColor("#FFDBDCDC"), Color.parseColor("#FF5C94F1"), + "Premium plan from Telekomsel"); + + DATA_PLAN_USAGES[1] = new MockDataPlanUsage("1.25 GB and 14 days left", + Color.parseColor("#FF673AB7"), "GigaMaxLite 4G / 5GB", 0.47D, + Color.parseColor("#FFDBDCDC"), Color.parseColor("#FF673AB7"), + "Plenty of 4G data"); + + DATA_PLAN_USAGES[2] = new MockDataPlanUsage("700 MB and 14 days left", + Color.parseColor("#FF4CAF50"), "GigaMaxLite Video / 7GB", 0.67D, + Color.parseColor("#FFDBDCDC"), Color.parseColor("#FF4CAF50"), + "Use certain video apps for free"); + return DATA_PLAN_USAGES; + } +} diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java index dccdc653908..d424299300e 100644 --- a/src/com/android/settings/search/SearchIndexableResources.java +++ b/src/com/android/settings/search/SearchIndexableResources.java @@ -21,7 +21,6 @@ import android.support.annotation.DrawableRes; import android.support.annotation.VisibleForTesting; import android.support.annotation.XmlRes; import android.text.TextUtils; - import com.android.settings.DateTimeSettings; import com.android.settings.DeviceInfoSettings; import com.android.settings.DisplaySettings; @@ -42,6 +41,7 @@ import com.android.settings.backup.BackupSettingsActivity; import com.android.settings.backup.BackupSettingsFragment; import com.android.settings.bluetooth.BluetoothSettings; import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment; +import com.android.settings.datausage.DataPlanUsageSummary; import com.android.settings.datausage.DataUsageMeteredSettings; import com.android.settings.datausage.DataUsageSummary; import com.android.settings.development.DevelopmentSettings; @@ -86,7 +86,6 @@ import com.android.settings.wallpaper.WallpaperTypeSettings; import com.android.settings.wifi.ConfigureWifiSettings; import com.android.settings.wifi.SavedAccessPointsWifiSettings; import com.android.settings.wifi.WifiSettings; - import java.util.Collection; import java.util.HashMap; @@ -133,6 +132,7 @@ public final class SearchIndexableResources { R.drawable.ic_settings_wireless); addIndex(BluetoothSettings.class, NO_DATA_RES_ID, R.drawable.ic_settings_bluetooth); addIndex(SimSettings.class, NO_DATA_RES_ID, R.drawable.ic_sim_sd); + addIndex(DataPlanUsageSummary.class, NO_DATA_RES_ID, R.drawable.ic_settings_data_usage); addIndex(DataUsageSummary.class, NO_DATA_RES_ID, R.drawable.ic_settings_data_usage); addIndex(DataUsageMeteredSettings.class, NO_DATA_RES_ID, R.drawable.ic_settings_data_usage); addIndex(ScreenZoomSettings.class, NO_DATA_RES_ID, R.drawable.ic_settings_display); diff --git a/tests/robotests/src/com/android/settings/datausage/DataPlanUsageSummaryTest.java b/tests/robotests/src/com/android/settings/datausage/DataPlanUsageSummaryTest.java new file mode 100644 index 00000000000..d2af22b6226 --- /dev/null +++ b/tests/robotests/src/com/android/settings/datausage/DataPlanUsageSummaryTest.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2017 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 static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkPolicy; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import com.android.settings.R; +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.XmlTestUtils; +import com.android.settings.testutils.shadow.ShadowConnectivityManager; +import com.android.settingslib.NetworkPolicyEditor; +import java.util.ArrayList; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowApplication; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class DataPlanUsageSummaryTest { + @Mock + private ConnectivityManager mManager; + + private Context mContext; + private DataPlanUsageSummary mDataUsageSummary; + private NetworkPolicyEditor mPolicyEditor; + private WifiConfiguration mWifiConfiguration; + private NetworkPolicy mNetworkPolicy; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + ShadowApplication shadowContext = ShadowApplication.getInstance(); + shadowContext.setSystemService(Context.CONNECTIVITY_SERVICE, mManager); + mContext = shadowContext.getApplicationContext(); + when(mManager.isNetworkSupported(anyInt())).thenReturn(true); + } + + @Test + public void testUpdateNetworkRestrictionSummary_shouldSetSummary() { + mDataUsageSummary = spy(new DataPlanUsageSummary()); + NetworkRestrictionsPreference preference = mock(NetworkRestrictionsPreference.class); + mPolicyEditor = mock(NetworkPolicyEditor.class); + WifiManager wifiManager = mock(WifiManager.class); + ReflectionHelpers.setField(mDataUsageSummary, "mPolicyEditor", mPolicyEditor); + ReflectionHelpers.setField(mDataUsageSummary, "mWifiManager", wifiManager); + when(wifiManager.getConfiguredNetworks()).thenReturn(new ArrayList<>()); + doReturn(mContext.getResources()).when(mDataUsageSummary).getResources(); + + mDataUsageSummary.updateNetworkRestrictionSummary(preference); + + verify(preference).setSummary(mContext.getResources().getQuantityString( + R.plurals.network_restrictions_summary, 0, 0)); + } + + @Test + public void testIsMetered_noSsid_shouldReturnFalse() { + initTest(); + + assertThat(mDataUsageSummary.isMetered(mWifiConfiguration)).isFalse(); + } + + @Test + public void testIsMetered_noNetworkPolicy_shouldReturnFalse() { + initTest(); + mWifiConfiguration.SSID = "network1"; + doReturn(null).when(mPolicyEditor).getPolicyMaybeUnquoted(any()); + + assertThat(mDataUsageSummary.isMetered(mWifiConfiguration)).isFalse(); + } + + @Test + public void testIsMetered_policyHasLimit_shouldReturnTrue() { + initTest(); + mWifiConfiguration.SSID = "network1"; + mNetworkPolicy = mock(NetworkPolicy.class); + mNetworkPolicy.limitBytes = 100; + doReturn(mNetworkPolicy).when(mPolicyEditor).getPolicyMaybeUnquoted(any()); + + assertThat(mDataUsageSummary.isMetered(mWifiConfiguration)).isTrue(); + } + + @Test + public void testIsMetered_noPolicyLimit_shouldReturnMeteredValue() { + initTest(); + mWifiConfiguration.SSID = "network1"; + mNetworkPolicy = mock(NetworkPolicy.class); + mNetworkPolicy.limitBytes = NetworkPolicy.LIMIT_DISABLED; + doReturn(mNetworkPolicy).when(mPolicyEditor).getPolicyMaybeUnquoted(any()); + + mNetworkPolicy.metered = true; + assertThat(mDataUsageSummary.isMetered(mWifiConfiguration)).isTrue(); + + mNetworkPolicy.metered = false; + assertThat(mDataUsageSummary.isMetered(mWifiConfiguration)).isFalse(); + } + + @Test + public void testNonIndexableKeys_existInXmlLayout() { + Context context = RuntimeEnvironment.application; + List niks = DataPlanUsageSummary.SEARCH_INDEX_DATA_PROVIDER + .getNonIndexableKeys(context); + List keys = new ArrayList<>(); + + keys.addAll(XmlTestUtils.getKeysFromPreferenceXml(context, R.xml.data_usage_wifi)); + keys.addAll(XmlTestUtils.getKeysFromPreferenceXml(context, R.xml.data_usage)); + + assertThat(keys).containsAllIn(niks); + } + + @Test + @Config(shadows = ShadowConnectivityManager.class) + public void testNonIndexableKeys_hasMobileData_restrictedAccessesAdded() { + ShadowConnectivityManager.setIsNetworkSupported(true); + List keys = DataPlanUsageSummary.SEARCH_INDEX_DATA_PROVIDER + .getNonIndexableKeys(mContext); + + assertThat(keys).contains(DataPlanUsageSummary.KEY_RESTRICT_BACKGROUND); + assertThat(keys).contains(DataPlanUsageSummary.KEY_NETWORK_RESTRICTIONS); + ShadowConnectivityManager.setIsNetworkSupported(false); + } + + private void initTest() { + mDataUsageSummary = new DataPlanUsageSummary(); + mPolicyEditor = mock(NetworkPolicyEditor.class); + ReflectionHelpers.setField(mDataUsageSummary, "mPolicyEditor", mPolicyEditor); + mWifiConfiguration = mock(WifiConfiguration.class); + } +} diff --git a/tests/robotests/src/com/android/settings/search/DataIntegrityTest.java b/tests/robotests/src/com/android/settings/search/DataIntegrityTest.java index ba2b63656c0..afc7d7a95ac 100644 --- a/tests/robotests/src/com/android/settings/search/DataIntegrityTest.java +++ b/tests/robotests/src/com/android/settings/search/DataIntegrityTest.java @@ -1,28 +1,28 @@ package com.android.settings.search; +import static com.google.common.truth.Truth.assertThat; + import android.content.Context; import android.provider.SearchIndexableResource; import android.util.ArraySet; import com.android.settings.DateTimeSettings; import com.android.settings.R; import com.android.settings.SecuritySettings; -import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.core.codeinspection.CodeInspector; +import com.android.settings.datausage.DataPlanUsageSummary; import com.android.settings.datausage.DataUsageSummary; +import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.XmlTestUtils; import com.android.settings.testutils.shadow.SettingsShadowResources; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import static com.google.common.truth.Truth.assertThat; - @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, assetDir = "/tests/robotests/assets") @@ -60,6 +60,7 @@ public class DataIntegrityTest { // Skip classes that are invalid or cannot be mocked. Add them as special Xml below. if (clazz == null || clazz == DateTimeSettings.class + || clazz == DataPlanUsageSummary.class || clazz == DataUsageSummary.class || clazz == SecuritySettings.class) { continue;