Merge "Tidy up uses of Integer.valueOf." into nyc-dev
diff --git a/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java b/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java
index b495917..66ae2da 100644
--- a/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java
+++ b/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java
@@ -53,11 +53,7 @@
 
         SipAccountRegistry sipAccountRegistry = SipAccountRegistry.getInstance();
         if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
-            Context phoneGlobalsContext = PhoneGlobals.getInstance();
-            // Migrate SIP database from DE->CE storage if the device has just upgraded.
-            SipUtil.possiblyMigrateSipDb(phoneGlobalsContext);
-            // Wait until boot complete to start SIP so that it has access to CE storage.
-            SipService.start(phoneGlobalsContext);
+            SipUtil.startSipService();
         } else if (action.equals(SipManager.ACTION_SIP_INCOMING_CALL)) {
             takeCall(context, intent);
         } else if (action.equals(SipManager.ACTION_SIP_SERVICE_UP) ||
diff --git a/sip/src/com/android/services/telephony/sip/SipSettings.java b/sip/src/com/android/services/telephony/sip/SipSettings.java
index 2044d49..0d87798 100644
--- a/sip/src/com/android/services/telephony/sip/SipSettings.java
+++ b/sip/src/com/android/services/telephony/sip/SipSettings.java
@@ -238,7 +238,12 @@
     }
 
     private void processActiveProfilesFromSipService() {
-        SipProfile[] activeList = mSipManager.getListOfProfiles();
+        SipProfile[] activeList = {};
+        try {
+            activeList = mSipManager.getListOfProfiles();
+        } catch (SipException e) {
+            log("SipManager could not retrieve SIP profiles: " + e);
+        }
         for (SipProfile activeProfile : activeList) {
             SipProfile profile = getProfileFromList(activeProfile);
             if (profile == null) {
diff --git a/sip/src/com/android/services/telephony/sip/SipUtil.java b/sip/src/com/android/services/telephony/sip/SipUtil.java
index 5076f6f..3678c46 100644
--- a/sip/src/com/android/services/telephony/sip/SipUtil.java
+++ b/sip/src/com/android/services/telephony/sip/SipUtil.java
@@ -31,7 +31,9 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.phone.PhoneGlobals;
 import com.android.phone.R;
+import com.android.server.sip.SipService;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -142,7 +144,7 @@
      * Checks if the Sip Db is in DE storage. If it is, the Db is moved to CE storage and
      * deleted.
      */
-    public static void possiblyMigrateSipDb(Context context) {
+    private static void possiblyMigrateSipDb(Context context) {
         SipProfileDb dbDeStorage = new SipProfileDb(context);
         dbDeStorage.accessDEStorageForMigration();
         List<SipProfile> profilesDeStorage = dbDeStorage.retrieveSipProfileList();
@@ -170,6 +172,17 @@
     }
 
     /**
+     * Migrates the DB files over from CE->DE storage and starts the SipService.
+     */
+    public static void startSipService() {
+        Context phoneGlobalsContext = PhoneGlobals.getInstance();
+        // Migrate SIP database from DE->CE storage if the device has just upgraded.
+        possiblyMigrateSipDb(phoneGlobalsContext);
+        // Wait until boot complete to start SIP so that it has access to CE storage.
+        SipService.start(phoneGlobalsContext);
+    }
+
+    /**
      * Determines if the user has chosen to use SIP for PSTN calls as well as SIP calls.
      * @param context The context.
      * @return {@code True} if SIP should be used for PSTN calls.
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 6823927..783878c 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -34,9 +34,12 @@
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.os.PowerManager;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.SystemService;
 import android.os.UpdateLock;
+import android.os.UserManager;
 import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
@@ -56,7 +59,9 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.phone.common.CallLogAsync;
 import com.android.phone.settings.SettingsConstants;
+import com.android.server.sip.SipService;
 import com.android.services.telephony.activation.SimActivationManager;
+import com.android.services.telephony.sip.SipUtil;
 
 /**
  * Global state for the telephony subsystem when running in the primary
@@ -93,6 +98,7 @@
     private static final int EVENT_DATA_ROAMING_DISCONNECTED = 10;
     private static final int EVENT_DATA_ROAMING_OK = 11;
     private static final int EVENT_UNSOL_CDMA_INFO_RECORD = 12;
+    private static final int EVENT_RESTART_SIP = 13;
 
     // The MMI codes are also used by the InCallScreen.
     public static final int MMI_INITIATE = 51;
@@ -238,6 +244,16 @@
                 case EVENT_UNSOL_CDMA_INFO_RECORD:
                     //TODO: handle message here;
                     break;
+                case EVENT_RESTART_SIP:
+                    // This should only run if the Phone process crashed and was restarted. We do
+                    // not want this running if the device is still in the FBE encrypted state.
+                    // This is the same procedure that is triggered in the SipBroadcastReceiver
+                    // upon BOOT_COMPLETED.
+                    UserManager userManager = UserManager.get(sMe);
+                    if (userManager != null && userManager.isUserUnlocked()) {
+                        SipUtil.startSipService();
+                    }
+                    break;
             }
         }
     };
@@ -279,6 +295,9 @@
             // status bar icons and control other status bar behavior.
             notificationMgr = NotificationMgr.init(this);
 
+            // If PhoneGlobals has crashed and is being restarted, then restart.
+            mHandler.sendEmptyMessage(EVENT_RESTART_SIP);
+
             // Create an instance of CdmaPhoneCallState and initialize it to IDLE
             cdmaPhoneCallState = new CdmaPhoneCallState();
             cdmaPhoneCallState.CdmaPhoneCallStateInit();
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index b697f2b..7738b77 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -32,6 +32,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
+import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -51,7 +52,6 @@
 import android.telephony.TelephonyManager;
 import android.telephony.ModemActivityInfo;
 import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Pair;
@@ -2979,12 +2979,20 @@
     }
 
     /**
-     * {@hide}
-     * Returns the modem stats
+     * Responds to the ResultReceiver with the {@link android.telephony.ModemActivityInfo} object
+     * representing the state of the modem.
+     *
+     * NOTE: This clears the modem state, so there should only every be one caller.
+     * @hide
      */
     @Override
-    public ModemActivityInfo getModemActivityInfo() {
-        return (ModemActivityInfo) sendRequest(CMD_GET_MODEM_ACTIVITY_INFO, null);
+    public void requestModemActivityInfo(ResultReceiver result) {
+        enforceModifyPermission();
+
+        ModemActivityInfo info = (ModemActivityInfo) sendRequest(CMD_GET_MODEM_ACTIVITY_INFO, null);
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(TelephonyManager.MODEM_ACTIVITY_RESULT_KEY, info);
+        result.send(0, bundle);
     }
 
     /**
diff --git a/src/com/android/services/telephony/PstnIncomingCallNotifier.java b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
index c0fe2fb..b4733dd 100644
--- a/src/com/android/services/telephony/PstnIncomingCallNotifier.java
+++ b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
@@ -25,6 +25,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.os.SystemClock;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
@@ -184,10 +185,9 @@
 
         if (!maybeSwapAnyWithUnknownConnection(connection)) {
             Log.i(this, "determined new connection is: %s", connection);
-            Bundle extras = null;
+            Bundle extras = new Bundle();
             if (connection.getNumberPresentation() == TelecomManager.PRESENTATION_ALLOWED &&
                     !TextUtils.isEmpty(connection.getAddress())) {
-                extras = new Bundle();
                 Uri uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, connection.getAddress(), null);
                 extras.putParcelable(TelecomManager.EXTRA_UNKNOWN_CALL_HANDLE, uri);
             }
@@ -196,13 +196,15 @@
             // TelephonyConnectionService, we will be able to determine which unknown connection is
             // being added.
             if (connection instanceof ImsExternalConnection) {
-                if (extras == null) {
-                    extras = new Bundle();
-                }
                 ImsExternalConnection externalConnection = (ImsExternalConnection) connection;
                 extras.putInt(ImsExternalCallTracker.EXTRA_IMS_EXTERNAL_CALL_ID,
                         externalConnection.getCallId());
             }
+
+            // Specifies the time the call was added. This is used by the dialer for analytics.
+            extras.putLong(TelecomManager.EXTRA_CALL_CREATED_TIME_MILLIS,
+                    SystemClock.elapsedRealtime());
+
             PhoneAccountHandle handle = findCorrectPhoneAccountHandle();
             if (handle == null) {
                 try {
@@ -222,13 +224,17 @@
      * Sends the incoming call intent to telecom.
      */
     private void sendIncomingCallIntent(Connection connection) {
-        Bundle extras = null;
+        Bundle extras = new Bundle();
         if (connection.getNumberPresentation() == TelecomManager.PRESENTATION_ALLOWED &&
                 !TextUtils.isEmpty(connection.getAddress())) {
-            extras = new Bundle();
             Uri uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, connection.getAddress(), null);
             extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, uri);
         }
+
+        // Specifies the time the call was added. This is used by the dialer for analytics.
+        extras.putLong(TelecomManager.EXTRA_CALL_CREATED_TIME_MILLIS,
+                SystemClock.elapsedRealtime());
+
         PhoneAccountHandle handle = findCorrectPhoneAccountHandle();
         if (handle == null) {
             try {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 311e58c..91ee5a0 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -606,7 +606,7 @@
     }
 
     private Phone getFirstPhoneForEmergencyCall() {
-        Phone selectPhone = null;
+        Phone firstPhoneWithSim = null;
         for (int i = 0; i < TelephonyManager.getDefault().getSimCount(); i++) {
             int[] subIds = SubscriptionController.getInstance().getSubIdUsingSlotId(i);
             if (subIds.length == 0)
@@ -618,28 +618,28 @@
                 continue;
 
             if (ServiceState.STATE_IN_SERVICE == phone.getServiceState().getState()) {
-                // the slot is radio on & state is in service
+                // the slot has the radio on & state is in service. This will be quicker,
+                // so just shortcut and use this option.
                 Log.d(this, "getFirstPhoneForEmergencyCall, radio on & in service, slotId:" + i);
                 return phone;
-            } else if (ServiceState.STATE_POWER_OFF != phone.getServiceState().getState()) {
-                // the slot is radio on & with SIM card inserted.
-                if (TelephonyManager.getDefault().hasIccCard(i)) {
-                    Log.d(this, "getFirstPhoneForEmergencyCall," +
-                            "radio on and SIM card inserted, slotId:" + i);
-                    selectPhone = phone;
-                } else if (selectPhone == null) {
-                    Log.d(this, "getFirstPhoneForEmergencyCall, radio on, slotId:" + i);
-                    selectPhone = phone;
-                }
+            }
+
+            if (firstPhoneWithSim == null && TelephonyManager.getDefault().hasIccCard(i)) {
+                // The slot has a SIM card inserted, but is not in service, so keep track of this
+                // Phone. Do not return because we want to make sure that none of the other Phones
+                // are in service (because that is always faster).
+                Log.d(this, "getFirstPhoneForEmergencyCall, SIM card inserted, slotId:" + i);
+                firstPhoneWithSim = phone;
             }
         }
 
-        if (selectPhone == null) {
+        if (firstPhoneWithSim == null) {
+            // No SIMs inserted, get the default.
             Log.d(this, "getFirstPhoneForEmergencyCall, return default phone");
-            selectPhone = PhoneFactory.getDefaultPhone();
+            return PhoneFactory.getDefaultPhone();
+        } else {
+            return firstPhoneWithSim;
         }
-
-        return selectPhone;
     }
 
     /**