Merge "Check carrier privilege for subId"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 011f7cf..1b2e99a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -42,6 +42,10 @@
     <string name="payphone">Payphone</string>
     <!-- In-call screen: status label for a call that's on hold -->
     <string name="onHold">On hold</string>
+    <!-- Title for carrier MMI message -->
+    <string name="carrier_mmi_msg_title">(<xliff:g id="mmicarrier" example="T-Mobile">%s</xliff:g>) Message</string>
+    <!-- Default title for carrier MMI message -->
+    <string name="default_carrier_mmi_msg_title">Carrier Message</string>
     <!-- Possible error messages with outgoing calls --><skip/>
     <string name="mmiStarted">MMI code started</string>
     <!-- Dialog label when a USSD code starts running -->
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 3e742bf..1c4b1c3 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -174,7 +174,7 @@
         @Override
         public void handleMessage(Message msg) {
             final int phoneId = msg.arg1;
-            log("mHandler: " + msg.what + " phoneId: " + phoneId);
+            logWithLocalLog("mHandler: " + msg.what + " phoneId: " + phoneId);
             switch (msg.what) {
                 case EVENT_CLEAR_CONFIG:
                 {
@@ -924,8 +924,12 @@
 
     @Override
     public void overrideConfig(int subscriptionId, PersistableBundle overrides) {
+        // SHELL UID already has MODIFY_PHONE_STATE implicitly so we do not have to check it, but
+        // the API signature explicitly declares that the method caller have MODIFY_PHONE_STATE, so
+        // calling this as well to be safe.
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.MODIFY_PHONE_STATE, null);
+        TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(), "overrideConfig");
         int phoneId = SubscriptionManager.getPhoneId(subscriptionId);
         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
             log("Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId);
@@ -942,7 +946,8 @@
         } else {
             mOverrideConfigs[phoneId].putAll(overrides);
         }
-        broadcastConfigChangedIntent(phoneId);
+
+        notifySubscriptionInfoUpdater(phoneId);
     }
 
     @Override
@@ -971,7 +976,7 @@
     public void updateConfigForPhoneId(int phoneId, String simState) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.MODIFY_PHONE_STATE, null);
-        log("update config for phoneId: " + phoneId + " simState: " + simState);
+        logWithLocalLog("update config for phoneId: " + phoneId + " simState: " + simState);
         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
             return;
         }
diff --git a/src/com/android/phone/NetworkScanHelper.java b/src/com/android/phone/NetworkScanHelper.java
index a21f547..fcfbf22 100644
--- a/src/com/android/phone/NetworkScanHelper.java
+++ b/src/com/android/phone/NetworkScanHelper.java
@@ -31,6 +31,7 @@
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
 import com.google.common.util.concurrent.SettableFuture;
 
 import java.lang.annotation.Retention;
@@ -180,7 +181,7 @@
                     int errCode = Integer.parseInt(t.getMessage());
                     onError(errCode);
                 }
-            });
+            }, MoreExecutors.directExecutor());
             mExecutor.execute(new NetworkScanSyncTask(
                     mTelephonyManager, (SettableFuture) mNetworkScanFuture));
         } else if (type == NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS) {
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index f118133..46c2847 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -141,6 +141,7 @@
 import com.android.internal.telephony.SmsApplication.SmsApplicationData;
 import com.android.internal.telephony.SubscriptionController;
 import com.android.internal.telephony.TelephonyPermissions;
+import com.android.internal.telephony.dataconnection.ApnSettingUtils;
 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.euicc.EuiccConnector;
 import com.android.internal.telephony.ims.ImsResolver;
@@ -4448,9 +4449,14 @@
                 }
             }
         }
-        return mNetworkScanRequestTracker.startNetworkScan(
-                request, messenger, binder, getPhone(subId),
-                callingPackage);
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return mNetworkScanRequestTracker.startNetworkScan(
+                    request, messenger, binder, getPhone(subId),
+                    callingPackage);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
     private SecurityException checkNetworkRequestForSanitizedLocationAccess(
@@ -5539,6 +5545,7 @@
                                 .setCallingPid(Binder.getCallingPid())
                                 .setCallingUid(Binder.getCallingUid())
                                 .setMethod("getServiceStateForSubscriber")
+                                .setLogAsInfo(true)
                                 .setMinSdkVersionForFine(Build.VERSION_CODES.Q)
                                 .build());
 
@@ -5549,6 +5556,7 @@
                                 .setCallingPid(Binder.getCallingPid())
                                 .setCallingUid(Binder.getCallingUid())
                                 .setMethod("getServiceStateForSubscriber")
+                                .setLogAsInfo(true)
                                 .setMinSdkVersionForCoarse(Build.VERSION_CODES.Q)
                                 .build());
         // We don't care about hard or soft here -- all we need to know is how much info to scrub.
@@ -6926,4 +6934,56 @@
         if (hv.equals(HalVersion.UNKNOWN)) return -1;
         return hv.major * 100 + hv.minor;
     }
+
+    /**
+     * Return whether data is enabled for certain APN type. This will tell if framework will accept
+     * corresponding network requests on a subId.
+     *
+     *  Data is enabled if:
+     *  1) user data is turned on, or
+     *  2) APN is un-metered for this subscription, or
+     *  3) APN type is whitelisted. E.g. MMS is whitelisted if
+     *  {@link SubscriptionManager#setAlwaysAllowMmsData} is turned on.
+     *
+     * @return whether data is allowed for a apn type.
+     *
+     * @hide
+     */
+    @Override
+    public boolean isDataEnabledForApn(int apnType, int subId, String callingPackage) {
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
+                mApp, subId, callingPackage, "isDataEnabledForApn")) {
+            throw new SecurityException("Needs READ_PHONE_STATE for isDataEnabledForApn");
+        }
+
+        // Now that all security checks passes, perform the operation as ourselves.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Phone phone = getPhone(subId);
+            if (phone == null) return false;
+
+            boolean isMetered = ApnSettingUtils.isMeteredApnType(ApnSetting.getApnTypeString(
+                    apnType), phone);
+            return !isMetered || phone.getDataEnabledSettings().isDataEnabled(apnType);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public boolean isApnMetered(int apnType, int subId) {
+        enforceReadPrivilegedPermission("isApnMetered");
+
+        // Now that all security checks passes, perform the operation as ourselves.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Phone phone = getPhone(subId);
+            if (phone == null) return true; // By default return true.
+
+            return ApnSettingUtils.isMeteredApnType(ApnSetting.getApnTypeString(
+                    apnType), phone);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
 }
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index d3f780f..e6f657e 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -429,7 +429,7 @@
             app.setPukEntryProgressDialog(pd);
 
         } else if ((app.getPUKEntryActivity() != null) && (state == MmiCode.State.FAILED)) {
-            createUssdDialog(app, context, text,
+            createUssdDialog(app, context, text, phone,
                     WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
             // In case of failure to unlock, we'll need to reset the
             // PUK unlock activity, so that the user may try again.
@@ -444,7 +444,7 @@
             // A USSD in a pending state means that it is still
             // interacting with the user.
             if (state != MmiCode.State.PENDING) {
-                createUssdDialog(app, context, text,
+                createUssdDialog(app, context, text, phone,
                         WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
             } else {
                 log("displayMMIComplete: USSD code has requested user input. Constructing input "
@@ -559,8 +559,17 @@
         }
     }
 
-    private static void createUssdDialog(PhoneGlobals app, Context context, CharSequence text,
-            int windowType) {
+    /**
+     * It displays the message dialog for user about the mmi code result message.
+     *
+     * @param app This is {@link PhoneGlobals}
+     * @param context Context to get strings.
+     * @param text This is message's result.
+     * @param phone This is phone to create sssd dialog.
+     * @param windowType The new window type. {@link WindowManager.LayoutParams}.
+     */
+    public static void createUssdDialog(PhoneGlobals app, Context context, CharSequence text,
+            Phone phone, int windowType) {
         log("displayMMIComplete: MMI code has finished running.");
 
         log("displayMMIComplete: Extended NW displayMMIInitiate (" + text + ")");
@@ -594,6 +603,13 @@
                     .insert(0, app.getResources().getString(R.string.ussd_dialog_sep))
                     .insert(0, "\n");
         }
+        if (phone != null && phone.getCarrierName() != null) {
+            sUssdDialog.setTitle(app.getResources().getString(R.string.carrier_mmi_msg_title,
+                    phone.getCarrierName()));
+        } else {
+            sUssdDialog
+                    .setTitle(app.getResources().getString(R.string.default_carrier_mmi_msg_title));
+        }
         sUssdMsg.insert(0, text);
         sUssdDialog.setMessage(sUssdMsg.toString());
         sUssdDialog.show();
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index cada504..1f157e3 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -209,6 +209,11 @@
             Log.v(this, "onExtrasRemoved: c=" + c + " key=" + keys);
             removeExtras(keys);
         }
+
+        @Override
+        public void onConnectionEvent(Connection c, String event, Bundle extras) {
+            sendConnectionEvent(event, extras);
+        }
     };
 
     /**