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
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.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.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.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 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 @@
 
     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 @@
     @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 @@
         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 @@
         }
 
         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 @@
                 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 @@
         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 @@
 
         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 @@
             // 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 @@
 
         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 @@
         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 @@
 
     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 @@
     }
 
     /**
-     * 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 @@
             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 @@
      * 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 @@
      * 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));
+
+        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(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())) {