Merge "Reset a network mode of each SIM from system property"
diff --git a/res/xml/cdma_options.xml b/res/xml/cdma_options.xml
index 8a41f87..6ac5dae 100644
--- a/res/xml/cdma_options.xml
+++ b/res/xml/cdma_options.xml
@@ -38,7 +38,7 @@
     <PreferenceCategory
         android:key="category_cdma_apn_key">
         <!-- The launching Intent will be defined thru code as we need to pass some Extra -->
-        <Preference
+        <com.android.phone.RestrictedPreference
             android:key="button_cdma_apn_key"
             android:title="@string/apn_settings"
             android:persistent="false"/>
diff --git a/res/xml/gsm_umts_options.xml b/res/xml/gsm_umts_options.xml
index e6ddc37..e3e2617 100644
--- a/res/xml/gsm_umts_options.xml
+++ b/res/xml/gsm_umts_options.xml
@@ -37,7 +37,7 @@
     <!--we want user to change it with caution.-->
     <PreferenceCategory
         android:key="category_gsm_apn_key">
-        <Preference
+        <com.android.phone.RestrictedPreference
             android:key="button_gsm_apn_key"
             android:title="@string/apn_settings"
             android:persistent="false" />
diff --git a/src/com/android/phone/CdmaOptions.java b/src/com/android/phone/CdmaOptions.java
index 7c09265..ff37c70 100644
--- a/src/com/android/phone/CdmaOptions.java
+++ b/src/com/android/phone/CdmaOptions.java
@@ -29,6 +29,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.Phone;
+import com.android.settingslib.RestrictedLockUtils;
 
 /**
  * List of Phone-specific settings screens.
@@ -38,7 +39,7 @@
 
     private CdmaSystemSelectListPreference mButtonCdmaSystemSelect;
     private CdmaSubscriptionListPreference mButtonCdmaSubscription;
-    private Preference mButtonAPNExpand;
+    private RestrictedPreference mButtonAPNExpand;
     private Preference mCategoryAPNExpand;
     private Preference mButtonCarrierSettings;
 
@@ -63,7 +64,7 @@
         mButtonCdmaSubscription = (CdmaSubscriptionListPreference) mPrefScreen
                 .findPreference(BUTTON_CDMA_SUBSCRIPTION_KEY);
         mButtonCarrierSettings = mPrefScreen.findPreference(BUTTON_CARRIER_SETTINGS_KEY);
-        mButtonAPNExpand = mPrefScreen.findPreference(BUTTON_APN_EXPAND_KEY);
+        mButtonAPNExpand = (RestrictedPreference) mPrefScreen.findPreference(BUTTON_APN_EXPAND_KEY);
         mCategoryAPNExpand = mPrefScreen.findPreference(CATEGORY_APN_EXPAND_KEY);
 
         update(phone);
@@ -93,6 +94,10 @@
         // Calling add or remove explicitly to make sure they are updated.
 
         if (addAPNExpand) {
+            mButtonAPNExpand.setDisabledByAdmin(
+                    MobileNetworkSettings.isDpcApnEnforced(mButtonAPNExpand.getContext())
+                            ? RestrictedLockUtils.getDeviceOwner(mButtonAPNExpand.getContext())
+                            : null);
             mButtonAPNExpand.setOnPreferenceClickListener(
                     new Preference.OnPreferenceClickListener() {
                         @Override
diff --git a/src/com/android/phone/GsmUmtsOptions.java b/src/com/android/phone/GsmUmtsOptions.java
index 5cf19ad..220cf34 100644
--- a/src/com/android/phone/GsmUmtsOptions.java
+++ b/src/com/android/phone/GsmUmtsOptions.java
@@ -28,6 +28,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneFactory;
+import com.android.settingslib.RestrictedLockUtils;
 
 /**
  * List of Network-specific settings screens.
@@ -35,7 +36,7 @@
 public class GsmUmtsOptions {
     private static final String LOG_TAG = "GsmUmtsOptions";
 
-    private Preference mButtonAPNExpand;
+    private RestrictedPreference mButtonAPNExpand;
     private Preference mCategoryAPNExpand;
     Preference mCarrierSettingPref;
 
@@ -54,7 +55,7 @@
         mPrefFragment = prefFragment;
         mPrefScreen = prefScreen;
         mPrefFragment.addPreferencesFromResource(R.xml.gsm_umts_options);
-        mButtonAPNExpand = mPrefScreen.findPreference(BUTTON_APN_EXPAND_KEY);
+        mButtonAPNExpand = (RestrictedPreference) mPrefScreen.findPreference(BUTTON_APN_EXPAND_KEY);
         mCategoryAPNExpand = mPrefScreen.findPreference(CATEGORY_APN_EXPAND_KEY);
         mNetworkOperator = (NetworkOperators) mPrefScreen
                 .findPreference(NetworkOperators.CATEGORY_NETWORK_OPERATORS_KEY);
@@ -113,6 +114,10 @@
         // Calling add or remove explicitly to make sure they are updated.
 
         if (addAPNExpand) {
+            mButtonAPNExpand.setDisabledByAdmin(
+                    MobileNetworkSettings.isDpcApnEnforced(mButtonAPNExpand.getContext())
+                            ? RestrictedLockUtils.getDeviceOwner(mButtonAPNExpand.getContext())
+                            : null);
             mButtonAPNExpand.setOnPreferenceClickListener(
                     new Preference.OnPreferenceClickListener() {
                         @Override
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 5dc57dd..47d9f05 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -16,6 +16,8 @@
 
 package com.android.phone;
 
+import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
+
 import android.app.ActionBar;
 import android.app.Activity;
 import android.app.DialogFragment;
@@ -30,6 +32,8 @@
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.database.ContentObserver;
+import android.database.Cursor;
 import android.net.Uri;
 import android.os.AsyncResult;
 import android.os.Bundle;
@@ -172,6 +176,20 @@
         return true;
     }
 
+    /**
+     * Returns if DPC APNs are enforced.
+     */
+    public static boolean isDpcApnEnforced(Context context) {
+        try (Cursor enforceCursor = context.getContentResolver().query(ENFORCE_MANAGED_URI,
+                null, null, null, null)) {
+            if (enforceCursor == null || enforceCursor.getCount() != 1) {
+                return false;
+            }
+            enforceCursor.moveToFirst();
+            return enforceCursor.getInt(0) > 0;
+        }
+    }
+
     public static class MobileNetworkFragment extends PreferenceFragment implements
             Preference.OnPreferenceChangeListener, RoamingDialogFragment.RoamingDialogListener {
 
@@ -213,6 +231,7 @@
         private static final String BUTTON_CDMA_APN_EXPAND_KEY = "button_cdma_apn_key";
 
         private final BroadcastReceiver mPhoneChangeReceiver = new PhoneChangeReceiver();
+        private final ContentObserver mDpcEnforcedContentObserver = new DpcApnEnforcedObserver();
 
         static final int preferredNetworkMode = Phone.PREFERRED_NT_MODE;
 
@@ -701,6 +720,9 @@
                     TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
             activity.registerReceiver(mPhoneChangeReceiver, intentFilter);
 
+            activity.getContentResolver().registerContentObserver(ENFORCE_MANAGED_URI, false,
+                    mDpcEnforcedContentObserver);
+
             Log.i(LOG_TAG, "onCreate:-");
         }
 
@@ -732,12 +754,26 @@
             }
         }
 
+        private class DpcApnEnforcedObserver extends ContentObserver {
+            DpcApnEnforcedObserver() {
+                super(null);
+            }
+
+            @Override
+            public void onChange(boolean selfChange) {
+                Log.i(LOG_TAG, "DPC enforced onChange:");
+                updateBody();
+            }
+        }
+
         @Override
         public void onDestroy() {
             unbindNetworkQueryService();
             super.onDestroy();
             if (getActivity() != null) {
                 getActivity().unregisterReceiver(mPhoneChangeReceiver);
+                getActivity().getContentResolver().unregisterContentObserver(
+                        mDpcEnforcedContentObserver);
             }
         }
 
diff --git a/src/com/android/phone/RestrictedPreference.java b/src/com/android/phone/RestrictedPreference.java
new file mode 100644
index 0000000..b8b6fe7
--- /dev/null
+++ b/src/com/android/phone/RestrictedPreference.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2018 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.phone;
+
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+import android.content.Context;
+import android.preference.Preference;
+import android.preference.PreferenceScreen;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.settingslib.RestrictedLockUtils;
+
+/**
+ * Preference class that supports being disabled by a device admin.
+ *
+ * <p>This class is a mimic of ../../../frameworks/base/packages/SettingsLib/src/com/android
+ * /settingslib/RestrictedPreference.java,
+ * but support framework {@link Preference}.
+ */
+public class RestrictedPreference extends Preference {
+    private final Context mContext;
+
+    private boolean mDisabledByAdmin;
+    private EnforcedAdmin mEnforcedAdmin;
+
+    public RestrictedPreference(Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mContext = context;
+
+        setLayoutResource(com.android.settingslib.R.layout.preference_two_target);
+        setWidgetLayoutResource(R.layout.restricted_icon);
+    }
+
+    public RestrictedPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public RestrictedPreference(Context context, AttributeSet attrs) {
+        this(context, attrs, android.R.attr.preferenceStyle);
+    }
+
+    public RestrictedPreference(Context context) {
+        this(context, null);
+    }
+
+    @Override
+    public void performClick(PreferenceScreen preferenceScreen) {
+        if (mDisabledByAdmin) {
+            RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, mEnforcedAdmin);
+        } else {
+            super.performClick(preferenceScreen);
+        }
+    }
+
+    @Override
+    protected void onBindView(View view) {
+        super.onBindView(view);
+
+        final View divider = view.findViewById(com.android.settingslib.R.id.two_target_divider);
+        final View widgetFrame = view.findViewById(android.R.id.widget_frame);
+        final View restrictedIcon = view.findViewById(R.id.restricted_icon);
+        final TextView summaryView = view.findViewById(android.R.id.summary);
+        if (divider != null) {
+            divider.setVisibility(mDisabledByAdmin ? View.VISIBLE : View.GONE);
+        }
+        if (widgetFrame != null) {
+            widgetFrame.setVisibility(mDisabledByAdmin ? View.VISIBLE : View.GONE);
+        }
+        if (restrictedIcon != null) {
+            restrictedIcon.setVisibility(mDisabledByAdmin ? View.VISIBLE : View.GONE);
+        }
+        if (summaryView != null && mDisabledByAdmin) {
+            summaryView.setText(com.android.settingslib.R.string.disabled_by_admin_summary_text);
+            summaryView.setVisibility(View.VISIBLE);
+        }
+
+        if (mDisabledByAdmin) {
+            view.setEnabled(true);
+        }
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        if (enabled && mDisabledByAdmin) {
+            setDisabledByAdmin(null);
+            return;
+        }
+        super.setEnabled(enabled);
+    }
+
+    /**
+     * Disable this preference based on the enforce admin.
+     *
+     * @param admin Details of the admin who enforced the restriction. If it is {@code null}, then
+     * this preference will be enabled. Otherwise, it will be disabled.
+     */
+    public void setDisabledByAdmin(EnforcedAdmin admin) {
+        final boolean disabled = admin != null;
+        mEnforcedAdmin = admin;
+        boolean changed = false;
+        if (mDisabledByAdmin != disabled) {
+            mDisabledByAdmin = disabled;
+            changed = true;
+        }
+        setEnabled(!disabled);
+        if (changed) {
+            notifyChanged();
+        }
+    }
+}