summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2012-04-03 21:13:25 -0700
committerJeff Sharkey <jsharkey@android.com>2012-04-05 14:31:43 -0700
commit313f7d8c5759fd29a98c710ceb9339d27b8e62fa (patch)
tree9275d0f9e2627535813e517a8e99319a7941c5d5
parent9f55ae28789754dafeed5c68468d45135d46199e (diff)
downloadpackages_apps_Settings-313f7d8c5759fd29a98c710ceb9339d27b8e62fa.zip
packages_apps_Settings-313f7d8c5759fd29a98c710ceb9339d27b8e62fa.tar.gz
packages_apps_Settings-313f7d8c5759fd29a98c710ceb9339d27b8e62fa.tar.bz2
Controls to set expensive (metered) networks.
Add UI to change metered flag on NetworkPolicy, and support Wi-Fi policies per-SSID. Create Wi-Fi policies as needed, but leave cycle undefined. Only show and mutate mobile policies when SIM state is ready. Bug: 3001465, 3291052 Change-Id: I481a202fe0e68fc2f5adfd3b3a6f40347d2b168c
-rw-r--r--res/menu/data_usage.xml3
-rw-r--r--res/values/strings.xml11
-rw-r--r--res/xml/data_usage_metered_prefs.xml34
-rw-r--r--src/com/android/settings/DataUsageSummary.java169
-rw-r--r--src/com/android/settings/net/DataUsageMeteredSettings.java133
-rw-r--r--src/com/android/settings/net/NetworkPolicyEditor.java99
6 files changed, 336 insertions, 113 deletions
diff --git a/res/menu/data_usage.xml b/res/menu/data_usage.xml
index 4e938aa..7847f3b 100644
--- a/res/menu/data_usage.xml
+++ b/res/menu/data_usage.xml
@@ -35,4 +35,7 @@
android:id="@+id/data_usage_menu_show_ethernet"
android:title="@string/data_usage_menu_show_ethernet"
android:checkable="true" />
+ <item
+ android:id="@+id/data_usage_menu_metered"
+ android:title="@string/data_usage_menu_metered" />
</menu>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d080d59..1bf5763 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3603,6 +3603,8 @@
<string name="data_usage_menu_show_wifi">Show Wi-Fi usage</string>
<!-- Title for checkbox menu option to show Ethernet data usage. [CHAR LIMIT=32] -->
<string name="data_usage_menu_show_ethernet">Show Ethernet usage</string>
+ <!-- Title for menu option to configure expensive networks. [CHAR LIMIT=32] -->
+ <string name="data_usage_menu_metered">Expensive networks</string>
<!-- Title for option to change data usage cycle day. [CHAR LIMIT=32] -->
<string name="data_usage_change_cycle">Change cycle\u2026</string>
<!-- Body of dialog prompting user to change numerical day of month that data usage cycle should reset. [CHAR LIMIT=64] -->
@@ -3704,6 +3706,15 @@
<!-- Label displaying total network data transferred during a specific time period. [CHAR LIMIT=64] -->
<string name="data_usage_total_during_range"><xliff:g id="range" example="Jul 1 - Jul 31">%2$s</xliff:g>: about <xliff:g id="total" example="128KB">%1$s</xliff:g> used</string>
+ <!-- Dialog title for selecting paid networks. [CHAR LIMIT=25] -->
+ <string name="data_usage_metered_title">Expensive networks</string>
+ <!-- Dialog body for selecting paid networks. [CHAR LIMIT=NONE] -->
+ <string name="data_usage_metered_body">Select the networks for which data usage is expensive. Apps can be restricted from using these networks when in the background. Apps may also warn before using these networks for large downloads.</string>
+ <!-- Header for list of mobile networks. [CHAR LIMIT=32] -->
+ <string name="data_usage_metered_mobile">Mobile networks</string>
+ <!-- Header for list of Wi-Fi networks. [CHAR LIMIT=32] -->
+ <string name="data_usage_metered_wifi">Wi-Fi networks</string>
+
<!-- Button at the bottom of the CryptKeeper screen to make an emergency call. -->
<string name="cryptkeeper_emergency_call">Emergency call</string>
<!-- Button at the bottom of the CryptKeeper screen that lets the user return to a call -->
diff --git a/res/xml/data_usage_metered_prefs.xml b/res/xml/data_usage_metered_prefs.xml
new file mode 100644
index 0000000..7ec3059
--- /dev/null
+++ b/res/xml/data_usage_metered_prefs.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <Preference
+ android:summary="@string/data_usage_metered_body"
+ android:persistent="false"
+ android:selectable="false" />
+
+ <PreferenceCategory
+ android:key="mobile"
+ android:title="@string/data_usage_metered_mobile"
+ android:persistent="false" />
+
+ <PreferenceCategory
+ android:key="wifi"
+ android:title="@string/data_usage_metered_wifi"
+ android:persistent="false" />
+
+</PreferenceScreen>
diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java
index d398e0b..656288a 100644
--- a/src/com/android/settings/DataUsageSummary.java
+++ b/src/com/android/settings/DataUsageSummary.java
@@ -35,11 +35,12 @@ import static android.net.NetworkTemplate.buildTemplateEthernet;
import static android.net.NetworkTemplate.buildTemplateMobile3gLower;
import static android.net.NetworkTemplate.buildTemplateMobile4g;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.net.NetworkTemplate.buildTemplateWifi;
+import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
import static android.net.TrafficStats.GB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.net.TrafficStats.UID_REMOVED;
import static android.net.TrafficStats.UID_TETHERING;
+import static android.telephony.TelephonyManager.SIM_STATE_READY;
import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
@@ -83,6 +84,7 @@ import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserId;
import android.preference.Preference;
+import android.preference.PreferenceActivity;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -127,6 +129,7 @@ import com.android.internal.telephony.Phone;
import com.android.settings.drawable.InsetBoundsDrawable;
import com.android.settings.net.ChartData;
import com.android.settings.net.ChartDataLoader;
+import com.android.settings.net.DataUsageMeteredSettings;
import com.android.settings.net.NetworkPolicyEditor;
import com.android.settings.net.SummaryForAllUidLoader;
import com.android.settings.net.UidDetail;
@@ -144,8 +147,8 @@ import java.util.Locale;
import libcore.util.Objects;
/**
- * Panel show data usage history across various networks, including options to
- * inspect based on usage cycle and control through {@link NetworkPolicy}.
+ * Panel showing data usage history across various networks, including options
+ * to inspect based on usage cycle and control through {@link NetworkPolicy}.
*/
public class DataUsageSummary extends Fragment {
private static final String TAG = "DataUsage";
@@ -180,7 +183,7 @@ public class DataUsageSummary extends Fragment {
private INetworkManagementService mNetworkService;
private INetworkStatsService mStatsService;
- private INetworkPolicyManager mPolicyService;
+ private NetworkPolicyManager mPolicyManager;
private ConnectivityManager mConnService;
private static final String PREF_FILE = "data_usage";
@@ -253,19 +256,18 @@ public class DataUsageSummary extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ final Context context = getActivity();
mNetworkService = INetworkManagementService.Stub.asInterface(
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
mStatsService = INetworkStatsService.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
- mPolicyService = INetworkPolicyManager.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
- mConnService = (ConnectivityManager) getActivity().getSystemService(
- Context.CONNECTIVITY_SERVICE);
+ mPolicyManager = NetworkPolicyManager.from(context);
+ mConnService = ConnectivityManager.from(context);
mPrefs = getActivity().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
- mPolicyEditor = new NetworkPolicyEditor(mPolicyService);
+ mPolicyEditor = new NetworkPolicyEditor(mPolicyManager);
mPolicyEditor.read();
mShowWifi = mPrefs.getBoolean(PREF_SHOW_WIFI, false);
@@ -431,19 +433,19 @@ public class DataUsageSummary extends Fragment {
final boolean appDetailMode = isAppDetailMode();
mMenuDataRoaming = menu.findItem(R.id.data_usage_menu_roaming);
- mMenuDataRoaming.setVisible(hasMobileRadio(context) && !appDetailMode);
+ mMenuDataRoaming.setVisible(hasReadyMobileRadio(context) && !appDetailMode);
mMenuDataRoaming.setChecked(getDataRoaming());
mMenuRestrictBackground = menu.findItem(R.id.data_usage_menu_restrict_background);
- mMenuRestrictBackground.setVisible(hasMobileRadio(context) && !appDetailMode);
- mMenuRestrictBackground.setChecked(getRestrictBackground());
+ mMenuRestrictBackground.setVisible(hasReadyMobileRadio(context) && !appDetailMode);
+ mMenuRestrictBackground.setChecked(mPolicyManager.getRestrictBackground());
final MenuItem split4g = menu.findItem(R.id.data_usage_menu_split_4g);
split4g.setVisible(hasMobile4gRadio(context) && !appDetailMode);
split4g.setChecked(isMobilePolicySplit());
final MenuItem showWifi = menu.findItem(R.id.data_usage_menu_show_wifi);
- if (hasWifiRadio(context) && hasMobileRadio(context)) {
+ if (hasWifiRadio(context) && hasReadyMobileRadio(context)) {
showWifi.setVisible(!appDetailMode);
showWifi.setChecked(mShowWifi);
} else {
@@ -452,13 +454,20 @@ public class DataUsageSummary extends Fragment {
}
final MenuItem showEthernet = menu.findItem(R.id.data_usage_menu_show_ethernet);
- if (hasEthernet(context) && hasMobileRadio(context)) {
+ if (hasEthernet(context) && hasReadyMobileRadio(context)) {
showEthernet.setVisible(!appDetailMode);
showEthernet.setChecked(mShowEthernet);
} else {
showEthernet.setVisible(false);
mShowEthernet = true;
}
+
+ final MenuItem metered = menu.findItem(R.id.data_usage_menu_metered);
+ if (hasReadyMobileRadio(context) || hasWifiRadio(context)) {
+ metered.setVisible(!appDetailMode);
+ } else {
+ metered.setVisible(false);
+ }
}
@Override
@@ -505,6 +514,12 @@ public class DataUsageSummary extends Fragment {
updateTabs();
return true;
}
+ case R.id.data_usage_menu_metered: {
+ final PreferenceActivity activity = (PreferenceActivity) getActivity();
+ activity.startPreferencePanel(DataUsageMeteredSettings.class.getCanonicalName(), null,
+ R.string.data_usage_metered_title, null, this, 0);
+ return true;
+ }
}
return false;
}
@@ -572,7 +587,7 @@ public class DataUsageSummary extends Fragment {
if (mobileSplit && hasMobile4gRadio(context)) {
mTabHost.addTab(buildTabSpec(TAB_3G, R.string.data_usage_tab_3g));
mTabHost.addTab(buildTabSpec(TAB_4G, R.string.data_usage_tab_4g));
- } else if (hasMobileRadio(context)) {
+ } else if (hasReadyMobileRadio(context)) {
mTabHost.addTab(buildTabSpec(TAB_MOBILE, R.string.data_usage_tab_mobile));
}
if (mShowWifi && hasWifiRadio(context)) {
@@ -650,6 +665,9 @@ public class DataUsageSummary extends Fragment {
mDataEnabledView.setVisibility(View.VISIBLE);
+ // TODO: remove mobile tabs when SIM isn't ready
+ final TelephonyManager tele = TelephonyManager.from(context);
+
if (TAB_MOBILE.equals(currentTab)) {
setPreferenceTitle(mDataEnabledView, R.string.data_usage_enable_mobile);
setPreferenceTitle(mDisableAtLimitView, R.string.data_usage_disable_mobile_limit);
@@ -671,7 +689,7 @@ public class DataUsageSummary extends Fragment {
// wifi doesn't have any controls
mDataEnabledView.setVisibility(View.GONE);
mDisableAtLimitView.setVisibility(View.GONE);
- mTemplate = buildTemplateWifi();
+ mTemplate = buildTemplateWifiWildcard();
} else if (TAB_ETHERNET.equals(currentTab)) {
// ethernet doesn't have any controls
@@ -755,8 +773,8 @@ public class DataUsageSummary extends Fragment {
updateDetailData();
- if (UserId.isApp(appId) && !getRestrictBackground() && isBandwidthControlEnabled()
- && hasMobileRadio(context)) {
+ if (UserId.isApp(appId) && !mPolicyManager.getRestrictBackground()
+ && isBandwidthControlEnabled() && hasReadyMobileRadio(context)) {
setPreferenceTitle(mAppRestrictView, R.string.data_usage_app_restrict_background);
setPreferenceSummary(mAppRestrictView,
getString(R.string.data_usage_app_restrict_background_summary));
@@ -829,48 +847,22 @@ public class DataUsageSummary extends Fragment {
mMenuDataRoaming.setChecked(enabled);
}
- private boolean getRestrictBackground() {
- try {
- return mPolicyService.getRestrictBackground();
- } catch (RemoteException e) {
- Log.w(TAG, "problem talking with policy service: " + e);
- return false;
- }
- }
-
- private void setRestrictBackground(boolean restrictBackground) {
- if (LOGD) Log.d(TAG, "setRestrictBackground()");
- try {
- mPolicyService.setRestrictBackground(restrictBackground);
- mMenuRestrictBackground.setChecked(restrictBackground);
- } catch (RemoteException e) {
- Log.w(TAG, "problem talking with policy service: " + e);
- }
+ public void setRestrictBackground(boolean restrictBackground) {
+ mPolicyManager.setRestrictBackground(restrictBackground);
+ mMenuRestrictBackground.setChecked(restrictBackground);
}
private boolean getAppRestrictBackground() {
final int appId = mCurrentApp.appId;
- final int uidPolicy;
- try {
- uidPolicy = mPolicyService.getAppPolicy(appId);
- } catch (RemoteException e) {
- // since we can't do much without policy, we bail hard.
- throw new RuntimeException("problem reading network policy", e);
- }
-
+ final int uidPolicy = mPolicyManager.getAppPolicy(appId);
return (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
}
private void setAppRestrictBackground(boolean restrictBackground) {
if (LOGD) Log.d(TAG, "setAppRestrictBackground()");
final int appId = mCurrentApp.appId;
- try {
- mPolicyService.setAppPolicy(appId,
- restrictBackground ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
- } catch (RemoteException e) {
- throw new RuntimeException("unable to save policy", e);
- }
-
+ mPolicyManager.setAppPolicy(appId,
+ restrictBackground ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
mAppRestrict.setChecked(restrictBackground);
}
@@ -1201,23 +1193,25 @@ public class DataUsageSummary extends Fragment {
private boolean isMobilePolicySplit() {
final Context context = getActivity();
- if (hasMobileRadio(context)) {
- final String subscriberId = getActiveSubscriberId(context);
- return mPolicyEditor.isMobilePolicySplit(subscriberId);
+ if (hasReadyMobileRadio(context)) {
+ final TelephonyManager tele = TelephonyManager.from(context);
+ return mPolicyEditor.isMobilePolicySplit(getActiveSubscriberId(context));
} else {
return false;
}
}
private void setMobilePolicySplit(boolean split) {
- final String subscriberId = getActiveSubscriberId(getActivity());
- mPolicyEditor.setMobilePolicySplit(subscriberId, split);
+ final Context context = getActivity();
+ if (hasReadyMobileRadio(context)) {
+ final TelephonyManager tele = TelephonyManager.from(context);
+ mPolicyEditor.setMobilePolicySplit(getActiveSubscriberId(context), split);
+ }
}
private static String getActiveSubscriberId(Context context) {
- final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
- Context.TELEPHONY_SERVICE);
- final String actualSubscriberId = telephony.getSubscriberId();
+ final TelephonyManager tele = TelephonyManager.from(context);
+ final String actualSubscriberId = tele.getSubscriberId();
return SystemProperties.get(TEST_SUBSCRIBER_PROP, actualSubscriberId);
}
@@ -2048,22 +2042,24 @@ public class DataUsageSummary extends Fragment {
}
/**
- * Test if device has a mobile data radio.
+ * Test if device has a mobile data radio with SIM in ready state.
*/
- private static boolean hasMobileRadio(Context context) {
+ public static boolean hasReadyMobileRadio(Context context) {
if (TEST_RADIOS) {
return SystemProperties.get(TEST_RADIOS_PROP).contains("mobile");
}
- final ConnectivityManager conn = (ConnectivityManager) context.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- return conn.isNetworkSupported(TYPE_MOBILE);
+ final ConnectivityManager conn = ConnectivityManager.from(context);
+ final TelephonyManager tele = TelephonyManager.from(context);
+
+ // require both supported network and ready SIM
+ return conn.isNetworkSupported(TYPE_MOBILE) && tele.getSimState() == SIM_STATE_READY;
}
/**
* Test if device has a mobile 4G data radio.
*/
- private static boolean hasMobile4gRadio(Context context) {
+ public static boolean hasMobile4gRadio(Context context) {
if (!NetworkPolicyEditor.ENABLE_SPLIT_POLICIES) {
return false;
}
@@ -2071,39 +2067,35 @@ public class DataUsageSummary extends Fragment {
return SystemProperties.get(TEST_RADIOS_PROP).contains("4g");
}
- final ConnectivityManager conn = (ConnectivityManager) context.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
- Context.TELEPHONY_SERVICE);
+ final ConnectivityManager conn = ConnectivityManager.from(context);
+ final TelephonyManager tele = TelephonyManager.from(context);
final boolean hasWimax = conn.isNetworkSupported(TYPE_WIMAX);
- final boolean hasLte = telephony.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE;
+ final boolean hasLte = tele.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE;
return hasWimax || hasLte;
}
/**
* Test if device has a Wi-Fi data radio.
*/
- private static boolean hasWifiRadio(Context context) {
+ public static boolean hasWifiRadio(Context context) {
if (TEST_RADIOS) {
return SystemProperties.get(TEST_RADIOS_PROP).contains("wifi");
}
- final ConnectivityManager conn = (ConnectivityManager) context.getSystemService(
- Context.CONNECTIVITY_SERVICE);
+ final ConnectivityManager conn = ConnectivityManager.from(context);
return conn.isNetworkSupported(TYPE_WIFI);
}
/**
* Test if device has an ethernet network connection.
*/
- private static boolean hasEthernet(Context context) {
+ public static boolean hasEthernet(Context context) {
if (TEST_RADIOS) {
return SystemProperties.get(TEST_RADIOS_PROP).contains("ethernet");
}
- final ConnectivityManager conn = (ConnectivityManager) context.getSystemService(
- Context.CONNECTIVITY_SERVICE);
+ final ConnectivityManager conn = ConnectivityManager.from(context);
return conn.isNetworkSupported(TYPE_ETHERNET);
}
@@ -2138,6 +2130,7 @@ public class DataUsageSummary extends Fragment {
* Build string describing currently limited networks, which defines when
* background data is restricted.
*/
+ @Deprecated
private CharSequence buildLimitedNetworksString() {
final List<CharSequence> limited = buildLimitedNetworksList();
@@ -2153,22 +2146,28 @@ public class DataUsageSummary extends Fragment {
* Build list of currently limited networks, which defines when background
* data is restricted.
*/
+ @Deprecated
private List<CharSequence> buildLimitedNetworksList() {
final Context context = getActivity();
- final String subscriberId = getActiveSubscriberId(context);
// build combined list of all limited networks
final ArrayList<CharSequence> limited = Lists.newArrayList();
- if (mPolicyEditor.hasLimitedPolicy(buildTemplateMobileAll(subscriberId))) {
- limited.add(getText(R.string.data_usage_list_mobile));
- }
- if (mPolicyEditor.hasLimitedPolicy(buildTemplateMobile3gLower(subscriberId))) {
- limited.add(getText(R.string.data_usage_tab_3g));
- }
- if (mPolicyEditor.hasLimitedPolicy(buildTemplateMobile4g(subscriberId))) {
- limited.add(getText(R.string.data_usage_tab_4g));
+
+ final TelephonyManager tele = TelephonyManager.from(context);
+ if (tele.getSimState() == SIM_STATE_READY) {
+ final String subscriberId = getActiveSubscriberId(context);
+ if (mPolicyEditor.hasLimitedPolicy(buildTemplateMobileAll(subscriberId))) {
+ limited.add(getText(R.string.data_usage_list_mobile));
+ }
+ if (mPolicyEditor.hasLimitedPolicy(buildTemplateMobile3gLower(subscriberId))) {
+ limited.add(getText(R.string.data_usage_tab_3g));
+ }
+ if (mPolicyEditor.hasLimitedPolicy(buildTemplateMobile4g(subscriberId))) {
+ limited.add(getText(R.string.data_usage_tab_4g));
+ }
}
- if (mPolicyEditor.hasLimitedPolicy(buildTemplateWifi())) {
+
+ if (mPolicyEditor.hasLimitedPolicy(buildTemplateWifiWildcard())) {
limited.add(getText(R.string.data_usage_tab_wifi));
}
if (mPolicyEditor.hasLimitedPolicy(buildTemplateEthernet())) {
diff --git a/src/com/android/settings/net/DataUsageMeteredSettings.java b/src/com/android/settings/net/DataUsageMeteredSettings.java
new file mode 100644
index 0000000..d069a71
--- /dev/null
+++ b/src/com/android/settings/net/DataUsageMeteredSettings.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2012 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.net;
+
+import static com.android.settings.DataUsageSummary.hasReadyMobileRadio;
+import static com.android.settings.DataUsageSummary.hasWifiRadio;
+
+import android.content.Context;
+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.preference.CheckBoxPreference;
+import android.preference.Preference;
+import android.preference.PreferenceCategory;
+import android.telephony.TelephonyManager;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+/**
+ * Panel to configure {@link NetworkPolicy#metered} for networks.
+ */
+public class DataUsageMeteredSettings extends SettingsPreferenceFragment {
+
+ private NetworkPolicyManager mPolicyManager;
+ private WifiManager mWifiManager;
+
+ private NetworkPolicyEditor mPolicyEditor;
+
+ private PreferenceCategory mMobileCategory;
+ private PreferenceCategory mWifiCategory;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ final Context context = getActivity();
+
+ mPolicyManager = NetworkPolicyManager.from(context);
+ mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+
+ mPolicyEditor = new NetworkPolicyEditor(mPolicyManager);
+ mPolicyEditor.read();
+
+ addPreferencesFromResource(R.xml.data_usage_metered_prefs);
+ mMobileCategory = (PreferenceCategory) findPreference("mobile");
+ mWifiCategory = (PreferenceCategory) findPreference("wifi");
+
+ updateNetworks(context);
+
+ }
+
+ private void updateNetworks(Context context) {
+ if (hasReadyMobileRadio(context)) {
+ mMobileCategory.removeAll();
+ mMobileCategory.addPreference(buildMobilePref(context));
+ } else {
+ getPreferenceScreen().removePreference(mMobileCategory);
+ }
+
+ if (hasWifiRadio(context)) {
+ mWifiCategory.removeAll();
+ for (WifiConfiguration config : mWifiManager.getConfiguredNetworks()) {
+ if (config.SSID != null) {
+ mWifiCategory.addPreference(buildWifiPref(context, config));
+ }
+ }
+ } else {
+ getPreferenceScreen().removePreference(mWifiCategory);
+ }
+ }
+
+ private Preference buildMobilePref(Context context) {
+ final TelephonyManager tele = TelephonyManager.from(context);
+ final NetworkTemplate template = NetworkTemplate.buildTemplateMobileAll(
+ tele.getSubscriberId());
+ final MeteredPreference pref = new MeteredPreference(context, template);
+ pref.setTitle(tele.getNetworkOperatorName());
+ return pref;
+ }
+
+ private Preference buildWifiPref(Context context, WifiConfiguration config) {
+ final String networkId = removeDoubleQuotes(config.SSID);
+ final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(networkId);
+ final MeteredPreference pref = new MeteredPreference(context, template);
+ pref.setTitle(networkId);
+ return pref;
+ }
+
+ private class MeteredPreference extends CheckBoxPreference {
+ private final NetworkTemplate mTemplate;
+
+ public MeteredPreference(Context context, NetworkTemplate template) {
+ super(context);
+ mTemplate = template;
+
+ setPersistent(false);
+ setChecked(mPolicyEditor.getPolicyMetered(mTemplate));
+ }
+
+ @Override
+ protected void notifyChanged() {
+ super.notifyChanged();
+ mPolicyEditor.setPolicyMetered(mTemplate, isChecked());
+ }
+ }
+
+
+ private static String removeDoubleQuotes(String string) {
+ final int length = string.length();
+ if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
+ return string.substring(1, length - 1);
+ }
+ return string;
+ }
+
+}
diff --git a/src/com/android/settings/net/NetworkPolicyEditor.java b/src/com/android/settings/net/NetworkPolicyEditor.java
index 80fcdb5..07a2afb 100644
--- a/src/com/android/settings/net/NetworkPolicyEditor.java
+++ b/src/com/android/settings/net/NetworkPolicyEditor.java
@@ -16,6 +16,7 @@
package com.android.settings.net;
+import static android.net.NetworkPolicy.CYCLE_NONE;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -27,11 +28,10 @@ import static android.net.NetworkTemplate.buildTemplateMobile4g;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static com.android.internal.util.Preconditions.checkNotNull;
-import android.net.INetworkPolicyManager;
import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
import android.net.NetworkTemplate;
import android.os.AsyncTask;
-import android.os.RemoteException;
import android.text.format.Time;
import com.android.internal.util.Objects;
@@ -43,27 +43,23 @@ import java.util.HashSet;
/**
* Utility class to modify list of {@link NetworkPolicy}. Specifically knows
- * about which policies can coexist. Not thread safe.
+ * about which policies can coexist. This editor offers thread safety when
+ * talking with {@link NetworkPolicyManager}.
*/
public class NetworkPolicyEditor {
// TODO: be more robust when missing policies from service
public static final boolean ENABLE_SPLIT_POLICIES = false;
- private INetworkPolicyManager mPolicyService;
+ private NetworkPolicyManager mPolicyManager;
private ArrayList<NetworkPolicy> mPolicies = Lists.newArrayList();
- public NetworkPolicyEditor(INetworkPolicyManager policyService) {
- mPolicyService = checkNotNull(policyService);
+ public NetworkPolicyEditor(NetworkPolicyManager policyManager) {
+ mPolicyManager = checkNotNull(policyManager);
}
public void read() {
- final NetworkPolicy[] policies;
- try {
- policies = mPolicyService.getNetworkPolicies();
- } catch (RemoteException e) {
- throw new RuntimeException("problem reading policies", e);
- }
+ final NetworkPolicy[] policies = mPolicyManager.getNetworkPolicies();
boolean modified = false;
mPolicies.clear();
@@ -78,12 +74,6 @@ public class NetworkPolicyEditor {
modified = true;
}
- // drop any WIFI policies that were defined
- if (policy.template.getMatchRule() == MATCH_WIFI) {
- modified = true;
- continue;
- }
-
mPolicies.add(policy);
}
@@ -109,11 +99,7 @@ public class NetworkPolicyEditor {
}
public void write(NetworkPolicy[] policies) {
- try {
- mPolicyService.setNetworkPolicies(policies);
- } catch (RemoteException e) {
- throw new RuntimeException("problem writing policies", e);
- }
+ mPolicyManager.setNetworkPolicies(policies);
}
public boolean hasLimitedPolicy(NetworkTemplate template) {
@@ -142,13 +128,24 @@ public class NetworkPolicyEditor {
@Deprecated
private static NetworkPolicy buildDefaultPolicy(NetworkTemplate template) {
// TODO: move this into framework to share with NetworkPolicyManagerService
- final Time time = new Time();
- time.setToNow();
- final int cycleDay = time.monthDay;
- final String cycleTimezone = time.timezone;
+ final int cycleDay;
+ final String cycleTimezone;
+ final boolean metered;
+
+ if (template.getMatchRule() == MATCH_WIFI) {
+ cycleDay = CYCLE_NONE;
+ cycleTimezone = Time.TIMEZONE_UTC;
+ metered = false;
+ } else {
+ final Time time = new Time();
+ time.setToNow();
+ cycleDay = time.monthDay;
+ cycleTimezone = time.timezone;
+ metered = true;
+ }
return new NetworkPolicy(template, cycleDay, cycleTimezone, WARNING_DISABLED,
- LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, false);
+ LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, metered, true);
}
public int getPolicyCycleDay(NetworkTemplate template) {
@@ -188,6 +185,52 @@ public class NetworkPolicyEditor {
writeAsync();
}
+ public boolean getPolicyMetered(NetworkTemplate template) {
+ final NetworkPolicy policy = getPolicy(template);
+ if (policy != null) {
+ return policy.metered;
+ } else {
+ return false;
+ }
+ }
+
+ public void setPolicyMetered(NetworkTemplate template, boolean metered) {
+ boolean modified = false;
+
+ NetworkPolicy policy = getPolicy(template);
+ if (metered) {
+ if (policy == null) {
+ policy = buildDefaultPolicy(template);
+ policy.metered = true;
+ policy.inferred = false;
+ mPolicies.add(policy);
+ modified = true;
+ } else if (!policy.metered) {
+ policy.metered = true;
+ policy.inferred = false;
+ modified = true;
+ }
+
+ } else {
+ if (policy == null) {
+ // ignore when policy doesn't exist
+ } else if (policy.template.getMatchRule() == MATCH_WIFI
+ && policy.warningBytes == WARNING_DISABLED
+ && policy.limitBytes == LIMIT_DISABLED) {
+ // when WIFI goes unmetered, and no other warning/limit for
+ // policy, clean it up.
+ mPolicies.remove(policy);
+ modified = true;
+ } else if (policy.metered) {
+ policy.metered = false;
+ policy.inferred = false;
+ modified = true;
+ }
+ }
+
+ if (modified) writeAsync();
+ }
+
/**
* Remove any split {@link NetworkPolicy}.
*/