Merge "Add Test for missing absent SIM + PIN lock case"
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index fca8acf..8d84baf 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -15,6 +15,21 @@
 -->
 
 <resources>
+    <!-- Base attributes available to CheckBoxPreference. Copied from frameworks/base/core/res. -->
+    <declare-styleable name="CheckBoxPreference">
+        <!-- The summary for the Preference in a PreferenceActivity screen when the
+             CheckBoxPreference is checked. If separate on/off summaries are not
+             needed, the summary attribute can be used instead. -->
+        <attr name="android:summaryOn" />
+        <!-- The summary for the Preference in a PreferenceActivity screen when the
+             CheckBoxPreference is unchecked. If separate on/off summaries are not
+             needed, the summary attribute can be used instead. -->
+        <attr name="android:summaryOff" />
+        <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
+             dependents will be disabled when this is unchecked, so the value of this preference is false. -->
+        <attr name="android:disableDependentsState" />
+    </declare-styleable>
+
     <declare-styleable name="EditPhoneNumberPreference">
         <!-- The enable button text. -->
         <attr name="enableButtonText" format="string" />
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 3858595..e5e02fa 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.os.UserManager;
@@ -181,9 +182,9 @@
                                 startActivity(intent);
                             }
                         };
-                builder.setMessage(getResources().getString(
+                builder.setMessage(getResourcesForSubId().getString(
                                 R.string.enable_video_calling_dialog_msg))
-                        .setNeutralButton(getResources().getString(
+                        .setNeutralButton(getResourcesForSubId().getString(
                                 R.string.enable_video_calling_dialog_settings),
                                 networkSettingsClickListener)
                         .setPositiveButton(android.R.string.ok, null)
@@ -211,9 +212,9 @@
         }
 
         mSubscriptionInfoHelper = new SubscriptionInfoHelper(this, getIntent());
-        mSubscriptionInfoHelper.setActionBarTitle(
-                getActionBar(), getResources(), R.string.call_settings_with_label);
         mPhone = mSubscriptionInfoHelper.getPhone();
+        mSubscriptionInfoHelper.setActionBarTitle(
+                getActionBar(), getResourcesForSubId(), R.string.call_settings_with_label);
         mTelecomManager = getSystemService(TelecomManager.class);
     }
 
@@ -315,7 +316,7 @@
         mButtonAutoRetry = (SwitchPreference) findPreference(BUTTON_RETRY_KEY);
 
         mEnableVideoCalling = (SwitchPreference) findPreference(ENABLE_VIDEO_CALLING_KEY);
-        mButtonWifiCalling = findPreference(getResources().getString(
+        mButtonWifiCalling = findPreference(getResourcesForSubId().getString(
                 R.string.wifi_calling_settings_key));
 
         PersistableBundle carrierConfig =
@@ -424,8 +425,7 @@
         } else if (!mImsMgr.isWfcEnabledByPlatform() || !mImsMgr.isWfcProvisionedOnDevice()) {
             prefSet.removePreference(mButtonWifiCalling);
         } else {
-            String title = SubscriptionManager.getResourcesForSubId(mPhone.getContext(),
-                    mPhone.getSubId()).getString(R.string.wifi_calling);
+            String title = getResourcesForSubId().getString(R.string.wifi_calling);
             mButtonWifiCalling.setTitle(title);
 
             int resId = com.android.internal.R.string.wifi_calling_off_summary;
@@ -447,7 +447,7 @@
                         if (DBG) log("Unexpected WFC mode value: " + wfcMode);
                 }
             }
-            mButtonWifiCalling.setSummary(resId);
+            mButtonWifiCalling.setSummary(getResourcesForSubId().getString(resId));
             Intent intent = mButtonWifiCalling.getIntent();
             if (intent != null) {
                 intent.putExtra(Settings.EXTRA_SUB_ID, mPhone.getSubId());
@@ -509,9 +509,9 @@
         setIntent(newIntent);
 
         mSubscriptionInfoHelper = new SubscriptionInfoHelper(this, getIntent());
-        mSubscriptionInfoHelper.setActionBarTitle(
-                getActionBar(), getResources(), R.string.call_settings_with_label);
         mPhone = mSubscriptionInfoHelper.getPhone();
+        mSubscriptionInfoHelper.setActionBarTitle(
+                getActionBar(), getResourcesForSubId(), R.string.call_settings_with_label);
     }
 
     private static void log(String msg) {
@@ -540,4 +540,12 @@
         activity.startActivity(intent);
         activity.finish();
     }
+
+    private Resources getResourcesForSubId() {
+        if (mPhone != null) {
+            return SubscriptionManager.getResourcesForSubId(mPhone.getContext(), mPhone.getSubId());
+        } else {
+            return getResources();
+        }
+    }
 }
diff --git a/src/com/android/phone/EditPhoneNumberPreference.java b/src/com/android/phone/EditPhoneNumberPreference.java
index 74b8a45..35af20d 100644
--- a/src/com/android/phone/EditPhoneNumberPreference.java
+++ b/src/com/android/phone/EditPhoneNumberPreference.java
@@ -136,9 +136,9 @@
         a.recycle();
 
         //get the summary settings, use CheckBoxPreference as the standard.
-        a = context.obtainStyledAttributes(attrs, android.R.styleable.CheckBoxPreference, 0, 0);
-        mSummaryOn = a.getString(android.R.styleable.CheckBoxPreference_summaryOn);
-        mSummaryOff = a.getString(android.R.styleable.CheckBoxPreference_summaryOff);
+        a = context.obtainStyledAttributes(attrs, R.styleable.CheckBoxPreference, 0, 0);
+        mSummaryOn = a.getString(R.styleable.CheckBoxPreference_summaryOn);
+        mSummaryOff = a.getString(R.styleable.CheckBoxPreference_summaryOff);
         a.recycle();
     }
 
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 3ddb267..27c1a0b 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -57,6 +57,7 @@
 import android.os.UserManager;
 import android.os.WorkSource;
 import android.preference.PreferenceManager;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.provider.Telephony;
 import android.telecom.PhoneAccount;
@@ -262,6 +263,8 @@
     private static final int EVENT_GET_MODEM_STATUS_DONE = 71;
     private static final int CMD_SET_FORBIDDEN_PLMNS = 72;
     private static final int EVENT_SET_FORBIDDEN_PLMNS_DONE = 73;
+    private static final int CMD_ERASE_MODEM_CONFIG = 74;
+    private static final int EVENT_ERASE_MODEM_CONFIG_DONE = 75;
 
     // Parameters of select command.
     private static final int SELECT_COMMAND = 0xA4;
@@ -302,6 +305,12 @@
     private static final int MANUFACTURER_CODE_LENGTH = 8;
 
     /**
+     * Experiment flag to enable erase modem config on reset network, default value is false
+     */
+    public static final String RESET_NETWORK_ERASE_MODEM_CONFIG_ENABLED =
+            "reset_network_erase_modem_config_enabled";
+
+    /**
      * A request object to use for transmitting data to an ICC.
      */
     private static final class IccAPDUArgument {
@@ -1214,6 +1223,13 @@
                         ((SIMRecords) uiccApp.getIccRecords())
                                 .setForbiddenPlmns(onCompleted, fplmns);
                     }
+                case CMD_ERASE_MODEM_CONFIG:
+                    request = (MainThreadRequest) msg.obj;
+                    onCompleted = obtainMessage(EVENT_ERASE_MODEM_CONFIG_DONE, request);
+                    defaultPhone.eraseModemConfig(onCompleted);
+                    break;
+                case EVENT_ERASE_MODEM_CONFIG_DONE:
+                    handleNullReturnEvent(msg, "eraseModemConfig");
                     break;
                 default:
                     Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
@@ -1423,6 +1439,20 @@
         return PhoneFactory.getPhone(mSubscriptionController.getPhoneId(subId));
     }
 
+    private void sendEraseModemConfig(Phone phone) {
+        if (phone != null) {
+            TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+                  mApp, phone.getSubId(), "eraseModemConfig");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                Boolean success = (Boolean) sendRequest(CMD_ERASE_MODEM_CONFIG, null);
+                if (DBG) log("eraseModemConfig:" + ' ' + (success ? "ok" : "fail"));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
     public void dial(String number) {
         dialForSubscriber(getPreferredVoiceSubscription(), number);
     }
@@ -4900,7 +4930,7 @@
      * @hide
      */
     @Override
-    public boolean isTetherApnRequiredForSubscriber(int subId) {
+    public boolean isTetheringApnRequiredForSubscriber(int subId) {
         enforceModifyPermission();
         final long identity = Binder.clearCallingIdentity();
         final Phone phone = getPhone(subId);
@@ -5836,6 +5866,13 @@
             if (slotId > SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
                 ImsManager.getInstance(mApp, slotId).factoryReset();
             }
+
+            // Erase modem config if erase modem on network setting is enabled.
+            String configValue = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_TELEPHONY,
+                    RESET_NETWORK_ERASE_MODEM_CONFIG_ENABLED);
+            if (configValue != null && Boolean.parseBoolean(configValue)) {
+              sendEraseModemConfig(getDefaultPhone());
+            }
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 428c006..ebadf88 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.os.Binder;
-import android.os.Build;
 import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
@@ -31,6 +30,7 @@
 
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
+import com.android.internal.telephony.util.TelephonyUtils;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -623,7 +623,7 @@
     private int handleCcCommand() {
         // Verify that the user is allowed to run the command. Only allowed in rooted device in a
         // non user build.
-        if (Binder.getCallingUid() != Process.ROOT_UID || Build.IS_USER) {
+        if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
             getErrPrintWriter().println("cc: Permission denied.");
             return -1;
         }
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index d8e9c32..fdece42 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.AsyncResult;
@@ -36,11 +37,13 @@
 import android.telecom.StatusHints;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
+import android.telephony.Annotation.RilRadioTechnology;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsCallProfile;
 import android.text.TextUtils;
@@ -136,7 +139,7 @@
                         if (connection != null &&
                             ((connection.getAddress() != null &&
                             mOriginalConnection.getAddress() != null &&
-                            mOriginalConnection.getAddress().contains(connection.getAddress())) ||
+                            mOriginalConnection.getAddress().equals(connection.getAddress())) ||
                             connection.getState() == mOriginalConnection.getStateBeforeHandover())) {
                             Log.d(TelephonyConnection.this,
                                     "SettingOriginalConnection " + mOriginalConnection.toString()
@@ -404,7 +407,9 @@
             }
         }
         if (messageId != -1 && getPhone() != null && getPhone().getContext() != null) {
-            return getPhone().getContext().getText(messageId);
+            Resources res = SubscriptionManager.getResourcesForSubId(
+                    getPhone().getContext(), getPhone().getSubId());
+            return res.getText(messageId);
         } else {
             return null;
         }
@@ -502,7 +507,7 @@
          * @param vrat the RIL Voice Radio Technology used for current connection.
          */
         @Override
-        public void onCallRadioTechChanged(@ServiceState.RilRadioTechnology int vrat) {
+        public void onCallRadioTechChanged(@RilRadioTechnology int vrat) {
             mHandler.obtainMessage(MSG_SET_CALL_RADIO_TECH, vrat).sendToTarget();
         }
 
@@ -645,6 +650,7 @@
         @Override
         public void onRttTerminated() {
             updateConnectionProperties();
+            refreshConferenceSupported();
             sendRttSessionRemotelyTerminated();
         }
 
@@ -2198,8 +2204,10 @@
                     : R.string.status_hint_label_wifi_call;
 
             Context context = getPhone().getContext();
+            Resources res =
+                    SubscriptionManager.getResourcesForSubId(context, getPhone().getSubId());
             setTelephonyStatusHints(new StatusHints(
-                    context.getString(labelId),
+                    res.getString(labelId),
                     Icon.createWithResource(
                             context, R.drawable.ic_signal_wifi_4_bar_24dp),
                     null /* extras */));
@@ -2579,7 +2587,7 @@
      * @param vrat the RIL Voice Radio Technology used for current connection,
      *             see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
      */
-    public final void setCallRadioTech(@ServiceState.RilRadioTechnology int vrat) {
+    public final void setCallRadioTech(@RilRadioTechnology int vrat) {
         Bundle extras = getExtras();
         if (extras == null) {
             extras = new Bundle();
@@ -2605,7 +2613,7 @@
      * @return the RIL voice radio technology used for current connection,
      *         see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
      */
-    public final @ServiceState.RilRadioTechnology int getCallRadioTech() {
+    public final @RilRadioTechnology int getCallRadioTech() {
         int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
         Bundle extras = getExtras();
         if (extras != null) {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 61e06e9..2cfc8dc 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -182,6 +182,8 @@
         public boolean isLocked = false;
         // Is the emergency number associated with the slot
         public boolean hasDialedEmergencyNumber = false;
+        //SimState
+        public int simState;
 
         public SlotStatus(int slotId, int capabilities) {
             this.slotId = slotId;
@@ -1663,6 +1665,8 @@
             // 4)
             // Report Slot's PIN/PUK lock status for sorting later.
             int simState = mSubscriptionManagerProxy.getSimStateForSlotIdx(i);
+            // Record SimState.
+            status.simState = simState;
             if (simState == TelephonyManager.SIM_STATE_PIN_REQUIRED ||
                     simState == TelephonyManager.SIM_STATE_PUK_REQUIRED) {
                 status.isLocked = true;
@@ -1708,6 +1712,15 @@
                         if (o1.hasDialedEmergencyNumber && !o2.hasDialedEmergencyNumber) {
                             return 1;
                         }
+                        // Sort by non-absent SIM.
+                        if (o1.simState == TelephonyManager.SIM_STATE_ABSENT
+                                && o2.simState != TelephonyManager.SIM_STATE_ABSENT) {
+                            return -1;
+                        }
+                        if (o2.simState == TelephonyManager.SIM_STATE_ABSENT
+                                && o1.simState != TelephonyManager.SIM_STATE_ABSENT) {
+                            return 1;
+                        }
                         // First start by seeing if either of the phone slots are locked. If they
                         // are, then sort by non-locked SIM first. If they are both locked, sort
                         // by capability instead.
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index 2dee0e1..bcc4fd3 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -23,11 +23,13 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.Context;
 import android.net.Uri;
 import android.os.AsyncResult;
 import android.os.Bundle;
@@ -39,6 +41,7 @@
 import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -801,6 +804,11 @@
         Phone phone = c.getPhone();
         c.setOriginalConnection(c.getOriginalConnection());
 
+        // Use a real context since the method SubscriptionManager.getResourcesForSubId()
+        // needs to interact with a real context.
+        Context targetContext = InstrumentationRegistry.getTargetContext();
+        doReturn(targetContext).when(phone).getContext();
+
         // When the registration occurs, we'll capture the handler and message so we can post our
         // own messages to it.
         ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);