Merge "Change return value of getTetherApnRequired() to a boolean."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f68b72e..de1f0f3 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -458,6 +458,24 @@
             </intent-filter>
         </activity>
 
+        <!--
+            Handler for EuiccManager's privileged action intents. These are locked down so that only
+            privileged processes can start them.
+        -->
+        <activity android:name=".euicc.EuiccPrivilegedActionUiDispatcherActivity"
+                  android:permission="android.permission.CALL_PRIVILEGED">
+            <!-- Max out priority to ensure nobody else will handle these intents. -->
+            <intent-filter android:priority="1000">
+                <action android:name=
+                            "android.telephony.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED" />
+                <action android:name=
+                            "android.telephony.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED" />
+                <action android:name=
+                            "android.telephony.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="EmergencyCallbackModeExitDialog"
             android:excludeFromRecents="true"
             android:label="@string/ecm_exit_dialog"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8fd194a..d2845ae 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1761,6 +1761,9 @@
     <string name="call_barring_settings">Call barring settings</string>
     <!-- Call barring settings screen, deactivate all call barring settings -->
     <string name="call_barring_deactivate_all_no_password">Deactivate all call barring settings?</string>
+    <!-- In-call screen: error message shown when the user attempts to place a call, but the network
+         does not have enough resources (e.g. it is busy) and the call cannot be placed. -->
+    <string name="callFailed_NetworkBusy">Network is busy.  Please try your call again later.</string>
     <!-- Message displayed to the user when an outgoing call is deflected.  This means that the
          party the user is calling has chosen to send the call to another phone number. -->
     <string name="supp_service_notification_call_deflected">Call deflected.</string>
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 6c69a33..0cb93aa 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -37,6 +37,7 @@
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ProvisioningManager;
 import android.telephony.ims.feature.ImsFeature;
@@ -386,6 +387,10 @@
         } else if (!mImsMgr.isWfcEnabledByPlatform() || !mImsMgr.isWfcProvisionedOnDevice()) {
             prefSet.removePreference(mButtonWifiCalling);
         } else {
+            String title = SubscriptionManager.getResourcesForSubId(mPhone.getContext(),
+                    mPhone.getSubId()).getString(R.string.wifi_calling);
+            mButtonWifiCalling.setTitle(title);
+
             int resId = com.android.internal.R.string.wifi_calling_off_summary;
             if (mImsMgr.isWfcEnabledByUser()) {
                 boolean isRoaming = telephonyManager.isNetworkRoaming();
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 65edcf9..9e40ffe 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -111,13 +111,6 @@
         EmergencyInfoGroup.OnConfirmClickListener {
 
     private class MetricsWriter {
-        // Metrics constants indicating the entry type that user opened emergency dialer.
-        // This info is sent from system UI with EXTRA_ENTRY_TYPE. Please make them being
-        // in sync with those in com.android.systemui.util.EmergencyDialerConstants.
-        public static final int ENTRY_TYPE_UNKNOWN = 0;
-        public static final int ENTRY_TYPE_LOCKSCREEN_BUTTON = 1;
-        public static final int ENTRY_TYPE_POWER_MENU = 2;
-
         // Metrics constants indicating the UI that user made phone call.
         public static final int CALL_SOURCE_DIALPAD = 0;
         public static final int CALL_SOURCE_SHORTCUT = 1;
@@ -140,11 +133,10 @@
                 return;
             }
 
-            int entryType = getIntent().getIntExtra(EXTRA_ENTRY_TYPE, ENTRY_TYPE_UNKNOWN);
             KeyguardManager keyguard = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
             mMetricsLogger.write(new LogMaker(MetricsEvent.EMERGENCY_DIALER)
                     .setType(MetricsEvent.TYPE_OPEN)
-                    .setSubtype(entryType)
+                    .setSubtype(mEntryType)
                     .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_IS_SCREEN_LOCKED,
                             keyguard.isKeyguardLocked() ? 1 : 0));
         }
@@ -154,11 +146,10 @@
                 return;
             }
 
-            int entryType = getIntent().getIntExtra(EXTRA_ENTRY_TYPE, ENTRY_TYPE_UNKNOWN);
             long userStayDuration = SystemClock.elapsedRealtime() - mUserEnterTimeMillis;
             mMetricsLogger.write(new LogMaker(MetricsEvent.EMERGENCY_DIALER)
                     .setType(MetricsEvent.TYPE_CLOSE)
-                    .setSubtype(entryType)
+                    .setSubtype(mEntryType)
                     .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_USER_ACTIONS, mUserActions)
                     .addTaggedData(
                             MetricsEvent.FIELD_EMERGENCY_DIALER_DURATION_MS, userStayDuration));
@@ -195,6 +186,13 @@
     public static final String EXTRA_ENTRY_TYPE =
             "com.android.phone.EmergencyDialer.extra.ENTRY_TYPE";
 
+    // Constants indicating the entry type that user opened emergency dialer.
+    // This info is sent from system UI with EXTRA_ENTRY_TYPE. Please make them being
+    // in sync with those in com.android.systemui.util.EmergencyDialerConstants.
+    public static final int ENTRY_TYPE_UNKNOWN = 0;
+    public static final int ENTRY_TYPE_LOCKSCREEN_BUTTON = 1;
+    public static final int ENTRY_TYPE_POWER_MENU = 2;
+
     // List of dialer button IDs.
     private static final int[] DIALER_KEYS = new int[]{
             R.id.one, R.id.two, R.id.three,
@@ -292,6 +290,7 @@
     private boolean mIsWfcEmergencyCallingWarningEnabled;
     private float mDefaultDigitsTextSize;
 
+    private int mEntryType;
     private boolean mIsShortcutViewEnabled;
 
     private MetricsWriter mMetricsWriter;
@@ -344,6 +343,9 @@
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
+        mEntryType = getIntent().getIntExtra(EXTRA_ENTRY_TYPE, ENTRY_TYPE_UNKNOWN);
+        Log.d(LOG_TAG, "Launched from " + entryTypeToString(mEntryType));
+
         mMetricsWriter = new MetricsWriter();
         mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
         if (mSensorManager != null) {
@@ -810,6 +812,10 @@
     }
 
     private boolean canEnableShortcutView(PersistableBundle carrierConfig) {
+        if (mEntryType != ENTRY_TYPE_POWER_MENU) {
+            Log.d(LOG_TAG, "Disables shortcut view since it's not launched from power menu");
+            return false;
+        }
         if (!carrierConfig.getBoolean(
                 CarrierConfigManager.KEY_SUPPORT_EMERGENCY_DIALER_SHORTCUT_BOOL)) {
             Log.d(LOG_TAG, "Disables shortcut view by carrier requirement");
@@ -903,6 +909,9 @@
     }
 
     private void placeCall(String number, int callSource, ShortcutViewUtils.PhoneInfo phone) {
+        Log.d(LOG_TAG, "Place emergency call from " + callSourceToString(callSource)
+                + ", entry = " + entryTypeToString(mEntryType));
+
         Bundle extras = new Bundle();
         extras.putInt(TelecomManager.EXTRA_CALL_SOURCE, callSource);
         /**
@@ -1338,4 +1347,26 @@
         }
         return isShortcut;
     }
+
+    private String entryTypeToString(int entryType) {
+        switch (entryType) {
+            case ENTRY_TYPE_LOCKSCREEN_BUTTON:
+                return "LockScreen";
+            case ENTRY_TYPE_POWER_MENU:
+                return "PowerMenu";
+            default:
+                return "Unknown-" + entryType;
+        }
+    }
+
+    private String callSourceToString(int callSource) {
+        switch (callSource) {
+            case ParcelableCallAnalytics.CALL_SOURCE_EMERGENCY_DIALPAD:
+                return "DialPad";
+            case ParcelableCallAnalytics.CALL_SOURCE_EMERGENCY_SHORTCUT:
+                return "Shortcut";
+            default:
+                return "Unknown-" + callSource;
+        }
+    }
 }
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index a7da9db..6375f90 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -1925,6 +1925,10 @@
                 mWiFiCallingPref.setSummary(null);
                 mWiFiCallingPref.setIntent(intent);
             } else {
+                String title = SubscriptionManager.getResourcesForSubId(getContext(), mSubId)
+                        .getString(R.string.wifi_calling_settings_title);
+                mWiFiCallingPref.setTitle(title);
+
                 int resId = com.android.internal.R.string.wifi_calling_off_summary;
                 if (mImsMgr.isWfcEnabledByUser()) {
                     boolean isRoaming = mTelephonyManager.isNetworkRoaming();
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 02738c2..f729dcf 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -69,6 +69,7 @@
 import android.telephony.ModemActivityInfo;
 import android.telephony.NeighboringCellInfo;
 import android.telephony.NetworkScanRequest;
+import android.telephony.PhoneCapability;
 import android.telephony.PhoneNumberRange;
 import android.telephony.RadioAccessFamily;
 import android.telephony.Rlog;
@@ -2017,6 +2018,7 @@
                                 .setCallingPid(Binder.getCallingPid())
                                 .setCallingUid(Binder.getCallingUid())
                                 .setMethod("getAllCellInfo")
+                                .setMinSdkVersionForCoarse(Build.VERSION_CODES.BASE)
                                 .setMinSdkVersionForFine(Build.VERSION_CODES.Q)
                                 .build());
         switch (locationResult) {
@@ -2460,7 +2462,7 @@
         }
 
         timeoutMillis = Math.min(timeoutMillis,
-                TelephonyManager.MAX_NUMBER_VERIFICATION_TIMEOUT_MILLIS);
+                TelephonyManager.getMaxNumberVerificationTimeoutMillis());
 
         NumberVerificationManager.getInstance().requestVerification(range, callback, timeoutMillis);
     }
@@ -2894,9 +2896,9 @@
     }
 
     @Override
-    public void setAdvancedCallingSetting(int subId, boolean isEnabled) {
+    public void setAdvancedCallingSettingEnabled(int subId, boolean isEnabled) {
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
-                "setAdvancedCallingSetting");
+                "setAdvancedCallingSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -2921,9 +2923,9 @@
     }
 
     @Override
-    public void setVtSetting(int subId, boolean isEnabled) {
+    public void setVtSettingEnabled(int subId, boolean isEnabled) {
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
-                "setVtSetting");
+                "setVtSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -2947,9 +2949,9 @@
     }
 
     @Override
-    public void setVoWiFiSetting(int subId, boolean isEnabled) {
+    public void setVoWiFiSettingEnabled(int subId, boolean isEnabled) {
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
-                "setVoWiFiSetting");
+                "setVoWiFiSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -2973,9 +2975,9 @@
     }
 
     @Override
-    public void setVoWiFiRoamingSetting(int subId, boolean isEnabled) {
+    public void setVoWiFiRoamingSettingEnabled(int subId, boolean isEnabled) {
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
-                "setVoWiFiRoamingSetting");
+                "setVoWiFiRoamingSettingEnabled");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -6145,7 +6147,8 @@
                         cardId,
                         cardState,
                         slot.getPhoneId(),
-                        slot.isExtendedApduSupported());
+                        slot.isExtendedApduSupported(),
+                        slot.isRemovable());
             }
             return infos;
         } finally {
@@ -6566,20 +6569,38 @@
     }
 
     @Override
-    public boolean isMultisimCarrierRestricted() {
-        enforceReadPrivilegedPermission("isMultisimCarrierRestricted");
+    public boolean isMultisimSupported(String callingPackage) {
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp,
+                getDefaultPhone().getSubId(), callingPackage, "isMultisimSupported")) {
+            return false;
+        }
 
         final long identity = Binder.clearCallingIdentity();
         try {
             // If the device has less than 2 SIM cards, indicate that multisim is restricted.
             int numPhysicalSlots = UiccController.getInstance().getUiccSlots().length;
             if (numPhysicalSlots < 2) {
-                loge("isMultisimCarrierRestricted: requires at least 2 cards");
-                return true;
+                loge("isMultisimSupported: requires at least 2 cards");
+                return false;
+            }
+            // Check if the hardware supports multisim functionality. If usage of multisim is not
+            // supported by the modem, indicate that it is restricted.
+            PhoneCapability staticCapability =
+                    mPhoneConfigurationManager.getStaticPhoneCapability();
+            if (staticCapability == null) {
+                loge("isMultisimSupported: no static configuration available");
+                return false;
+            }
+            if (staticCapability.logicalModemList.size() < 2) {
+                loge("isMultisimSupported: maximum number of modem is < 2");
+                return false;
+            }
+            // Check if support of multiple SIMs is restricted by carrier
+            if (mTelephonySharedPreferences.getBoolean(PREF_MULTI_SIM_RESTRICTED, false)) {
+                return false;
             }
 
-            // Default value is false. Multi SIM is allowed unless explicitly restricted.
-            return mTelephonySharedPreferences.getBoolean(PREF_MULTI_SIM_RESTRICTED, false);
+            return true;
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/src/com/android/phone/euicc/EuiccPrivilegedActionUiDispatcherActivity.java b/src/com/android/phone/euicc/EuiccPrivilegedActionUiDispatcherActivity.java
new file mode 100644
index 0000000..389795b
--- /dev/null
+++ b/src/com/android/phone/euicc/EuiccPrivilegedActionUiDispatcherActivity.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 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.euicc;
+
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.service.euicc.EuiccService;
+import android.telephony.euicc.EuiccManager;
+import android.util.Log;
+
+/**
+ * Trampoline activity to forward privileged eUICC intents from the system to the active UI
+ * implementation.
+ *
+ * <p>Unlike {@link EuiccUiDispatcherActivity}, this activity requires a locked-down permission to
+ * start.
+ */
+public class EuiccPrivilegedActionUiDispatcherActivity extends EuiccUiDispatcherActivity {
+    private static final String TAG = "EuiccPrivUiDispatcher";
+
+    @Override
+    @Nullable
+    protected Intent getEuiccUiIntent() {
+        String action = getIntent().getAction();
+
+        Intent intent = new Intent();
+        // Propagate the extras from the original Intent.
+        intent.putExtras(getIntent());
+        switch (action) {
+            case EuiccManager.ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED:
+                intent.setAction(EuiccService.ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED);
+                break;
+            case EuiccManager.ACTION_DELETE_SUBSCRIPTION_PRIVILEGED:
+                intent.setAction(EuiccService.ACTION_DELETE_SUBSCRIPTION_PRIVILEGED);
+                break;
+            case EuiccManager.ACTION_RENAME_SUBSCRIPTION_PRIVILEGED:
+                intent.setAction(EuiccService.ACTION_RENAME_SUBSCRIPTION_PRIVILEGED);
+                break;
+            default:
+                Log.w(TAG, "Unsupported action: " + action);
+                return null;
+        }
+
+        return intent;
+    }
+}
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index a92dea7..8ef9565 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -249,6 +249,10 @@
                 resourceId = R.string.callFailed_userBusy;
                 break;
 
+            case android.telephony.DisconnectCause.CDMA_REORDER:
+                resourceId = R.string.callFailed_NetworkBusy;
+                break;
+
             case android.telephony.DisconnectCause.CONGESTION:
                 resourceId = R.string.callFailed_congestion;
                 break;
@@ -557,6 +561,10 @@
                 resourceId = R.string.callFailed_cdma_activation;
                 break;
 
+            case android.telephony.DisconnectCause.CDMA_REORDER:
+                resourceId = R.string.callFailed_NetworkBusy;
+                break;
+
             case android.telephony.DisconnectCause.FDN_BLOCKED:
                 resourceId = R.string.callFailed_fdn_only;
                 break;
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 85f0d48..7c09320 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -46,7 +46,6 @@
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallFailCause;
 import com.android.internal.telephony.CallStateException;
-import com.android.internal.telephony.Call.HoldingRequestState;
 import com.android.internal.telephony.Connection.Capability;
 import com.android.internal.telephony.Connection.PostDialListener;
 import com.android.internal.telephony.Phone;
@@ -953,7 +952,6 @@
                 // instead of actually putting it on hold.
                 if (ringingCall.getState() != Call.State.WAITING) {
                     phone.switchHoldingAndActive();
-                    mOriginalConnection.getCall().updateHoldingRequestState(HoldingRequestState.STARTED);
                 }
 
                 // TODO: Cdma calls are slightly different.
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
index 84ec7b9..50be698 100644
--- a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
@@ -121,8 +121,8 @@
         }
 
         @Override
-        public void onDeregistered(ImsReasonInfo info) {
-            Log.i("ImsRegistrationActivity", "onDeregistered: " + info);
+        public void onUnregistered(ImsReasonInfo info) {
+            Log.i("ImsRegistrationActivity", "onUnregistered: " + info);
             mRegItems.add(new RegItem("Deregistered", info.toString()));
             triggerAdapterChange();
         }