Merge "Remove onConnectionAdded/Removed from ConnectionService API (2/2)" into lmp-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 66821ee..45c1e82 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -490,6 +490,7 @@
                 <action android:name="com.android.phone.SIP_INCOMING_CALL" />
                 <action android:name="com.android.phone.SIP_ADD_PHONE" />
                 <action android:name="com.android.phone.SIP_REMOVE_PHONE" />
+                <action android:name="com.android.phone.SIP_CALL_OPTION_CHANGED" />
             </intent-filter>
         </receiver>
 
diff --git a/sip/res/values/array.xml b/sip/res/values/array.xml
index 245c09b..02940e8 100644
--- a/sip/res/values/array.xml
+++ b/sip/res/values/array.xml
@@ -24,19 +24,16 @@
     <string-array translatable="true" name="sip_call_options_entries">
         <item>@string/sip_call_options_entry_1</item>
         <item>@string/sip_call_options_entry_2</item>
-        <item>@string/sip_call_options_entry_3</item>
     </string-array>
 
     <string-array translatable="true" name="sip_call_options_wifi_only_entries">
         <item>@string/sip_call_options_wifi_only_entry_1</item>
         <item>@string/sip_call_options_entry_2</item>
-        <item>@string/sip_call_options_entry_3</item>
     </string-array>
 
     <string-array translatable="false" name="sip_call_options_values">
         <item>@string/sip_always</item>
         <item>@string/sip_address_only</item>
-        <item>@string/sip_ask_me_each_time</item>
     </string-array>
 
     <string-array translatable="false" name="phone_type_values">
diff --git a/sip/res/values/strings.xml b/sip/res/values/strings.xml
index e553700..8b85ff4 100644
--- a/sip/res/values/strings.xml
+++ b/sip/res/values/strings.xml
@@ -35,8 +35,6 @@
     <string name="sip_call_options_entry_1">For all calls when data network is available</string>
     <!-- Item of the SIP call option dialog: for routing a outgoing call via SIP if the destination is a SIP URI. [CHAR LIMIT=NONE] -->
     <string name="sip_call_options_entry_2">Only for SIP calls</string>
-    <!-- Item of the SIP call option dialog: for asking user to select the way for each outgoing call. [CHAR LIMIT=NONE] -->
-    <string name="sip_call_options_entry_3">Ask for each call</string>
     <!-- Item of the SIP call (Wi-Fi only) option dialog: for routing all outgoing calls via SIP. [CHAR LIMIT=NONE] -->
     <string name="sip_call_options_wifi_only_entry_1">For all calls</string>
 
@@ -190,7 +188,6 @@
     <!-- Do not translate the following strings. Used for the SIP call options. Need to be in-sync with Settings.System.SIP_ strings. -->
     <string translatable="false" name="sip_always">SIP_ALWAYS</string>
     <string translatable="false" name="sip_address_only">SIP_ADDRESS_ONLY</string>
-    <string translatable="false" name="sip_ask_me_each_time">SIP_ASK_ME_EACH_TIME</string>
 
     <!-- Do not translate the following strings. Used for the preference keys -->
     <string translatable="false" name="domain_address">SipDomain</string>
diff --git a/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java b/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
index 8aca613..f830f67 100644
--- a/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
+++ b/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
@@ -22,6 +22,7 @@
 import android.net.sip.SipException;
 import android.net.sip.SipManager;
 import android.net.sip.SipProfile;
+import android.provider.Settings;
 import android.telecomm.PhoneAccount;
 import android.telecomm.PhoneAccountHandle;
 import android.telecomm.TelecommManager;
@@ -65,16 +66,25 @@
         }
 
         private PhoneAccount createPhoneAccount(Context context) {
+            boolean useSipForPstnCalls = useSipForPstnCalls(context);
+
             PhoneAccountHandle accountHandle =
                     SipUtil.createAccountHandle(context, mProfile.getUriString());
-            return PhoneAccount.builder()
+
+            PhoneAccount.Builder builder = PhoneAccount.builder()
                     .withAccountHandle(accountHandle)
                     .withCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
                     .withHandle(Uri.parse(mProfile.getUriString()))
                     .withLabel(mProfile.getDisplayName())
                     .withShortDescription(mProfile.getDisplayName())
                     .withIconResId(R.drawable.ic_dialer_sip_black_24dp)
-                    .build();
+                    .withSupportedUriScheme(PhoneAccount.SCHEME_SIP);
+
+            if (useSipForPstnCalls) {
+                builder.withSupportedUriScheme(PhoneAccount.SCHEME_TEL);
+            }
+
+            return builder.build();
         }
     }
 
@@ -144,6 +154,7 @@
     private void registerAccountForProfile(
             SipProfile profile, SipManager sipManager, Context context) {
         AccountEntry entry = new AccountEntry(profile);
+
         if (entry.register(sipManager, context)) {
             mAccounts.add(entry);
         }
@@ -160,6 +171,16 @@
         }
     }
 
+    /**
+     * 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.
+     */
+    private boolean useSipForPstnCalls(Context context) {
+        final SipSharedPreferences sipSharedPreferences = new SipSharedPreferences(context);
+        return sipSharedPreferences.getSipCallOption().equals(Settings.System.SIP_ALWAYS);
+    }
+
     private void log(String message) {
         Log.d(SipUtil.LOG_TAG, PREFIX + message);
     }
diff --git a/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java b/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java
index 2adb61a..a113805 100644
--- a/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java
+++ b/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java
@@ -44,7 +44,8 @@
         SipAccountRegistry sipAccountRegistry = SipAccountRegistry.getInstance();
         if (action.equals(SipManager.ACTION_SIP_INCOMING_CALL)) {
             takeCall(context, intent);
-        } else if (action.equals(SipManager.ACTION_SIP_SERVICE_UP)) {
+        } else if (action.equals(SipManager.ACTION_SIP_SERVICE_UP) ||
+                action.equals(SipManager.ACTION_SIP_CALL_OPTION_CHANGED)) {
             sipAccountRegistry.setup(context);
         } else if (action.equals(SipManager.ACTION_SIP_ADD_PHONE)) {
             if (VERBOSE) log("SIP_ADD_PHONE " + intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
diff --git a/sip/src/com/android/services/telephony/sip/SipConnection.java b/sip/src/com/android/services/telephony/sip/SipConnection.java
index 2579159..534b27a 100644
--- a/sip/src/com/android/services/telephony/sip/SipConnection.java
+++ b/sip/src/com/android/services/telephony/sip/SipConnection.java
@@ -16,6 +16,7 @@
 
 package com.android.services.telephony.sip;
 
+import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
 import android.telecomm.AudioState;
@@ -26,8 +27,10 @@
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.sip.SipPhone;
+import com.android.phone.Constants;
 
 import java.util.List;
+import java.util.Objects;
 
 final class SipConnection extends Connection {
     private static final String PREFIX = "[SipConnection] ";
@@ -61,6 +64,7 @@
             getPhone().registerForPreciseCallStateChanged(mHandler, MSG_PRECISE_CALL_STATE_CHANGED,
                     null);
         }
+        updateHandle();
         setInitialized();
     }
 
@@ -268,6 +272,44 @@
         }
     }
 
+    /**
+     * Updates the handle on this connection based on the original connection.
+     */
+    private void updateHandle() {
+        if (mOriginalConnection != null) {
+            Uri handle = getHandleFromAddress(mOriginalConnection.getAddress());
+            int presentation = mOriginalConnection.getNumberPresentation();
+            if (!Objects.equals(handle, getHandle()) ||
+                    presentation != getHandlePresentation()) {
+                com.android.services.telephony.Log.v(this, "updateHandle, handle changed");
+                setHandle(handle, presentation);
+            }
+
+            String name = mOriginalConnection.getCnapName();
+            int namePresentation = mOriginalConnection.getCnapNamePresentation();
+            if (!Objects.equals(name, getCallerDisplayName()) ||
+                    namePresentation != getCallerDisplayNamePresentation()) {
+                com.android.services.telephony.Log
+                        .v(this, "updateHandle, caller display name changed");
+                setCallerDisplayName(name, namePresentation);
+            }
+        }
+    }
+
+    /**
+     * Determines the handle for an incoming number.
+     *
+     * @param address The incoming number.
+     * @return The Uri representing the number.
+     */
+    private static Uri getHandleFromAddress(String address) {
+        // Address can be null for blocked calls.
+        if (address == null) {
+            address = "";
+        }
+        return Uri.fromParts(Constants.SCHEME_SIP, address, null);
+    }
+
     private void close() {
         if (getPhone() != null) {
             getPhone().unregisterForPreciseCallStateChanged(mHandler);
diff --git a/sip/src/com/android/services/telephony/sip/SipSharedPreferences.java b/sip/src/com/android/services/telephony/sip/SipSharedPreferences.java
index ff7a3c8..b5d1fc2 100644
--- a/sip/src/com/android/services/telephony/sip/SipSharedPreferences.java
+++ b/sip/src/com/android/services/telephony/sip/SipSharedPreferences.java
@@ -18,7 +18,9 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
 import android.content.SharedPreferences;
+import android.net.sip.SipManager;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.text.TextUtils;
@@ -82,6 +84,12 @@
     public void setSipCallOption(String option) {
         Settings.System.putString(mContext.getContentResolver(),
                 Settings.System.SIP_CALL_OPTIONS, option);
+
+        // Notify SipAccountRegistry in the telephony layer that the configuration has changed.
+        // This causes the SIP PhoneAccounts to be re-registered.  This ensures the supported URI
+        // schemes for the SIP PhoneAccounts matches the new SIP_CALL_OPTIONS setting.
+        Intent intent = new Intent(SipManager.ACTION_SIP_CALL_OPTION_CHANGED);
+        mContext.sendBroadcast(intent);
     }
 
     public String getSipCallOption() {
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 05c00fa..1806558 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -124,6 +124,7 @@
         // Assuming that onClick gets called first
         if (!mOkClicked) {
             mButtonDataRoam.setChecked(false);
+            getPreferenceScreen().setEnabled(true);
         }
     }
 
diff --git a/src/com/android/services/telephony/TelecommAccountRegistry.java b/src/com/android/services/telephony/TelecommAccountRegistry.java
index c342e48..095073b 100644
--- a/src/com/android/services/telephony/TelecommAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecommAccountRegistry.java
@@ -104,6 +104,8 @@
                     .withIconResId(getPhoneAccountIcon(slotId))
                     .withLabel(label)
                     .withShortDescription(description)
+                    .withSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                    .withSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
                     .build();
 
             // Register with Telecomm and put into the account entry.
@@ -131,6 +133,7 @@
     };
 
     private static final String TEL_SCHEME = "tel";
+    private static final String VOICEMAIL_SCHEME = "voicemail";
     private static TelecommAccountRegistry sInstance;
     private final Context mContext;
     private final TelecommManager mTelecommManager;
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 4d9709a..9cbf8a6 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -393,11 +393,22 @@
     private void hangup(int disconnectCause) {
         if (mOriginalConnection != null) {
             try {
-                Call call = getCall();
-                if (call != null) {
-                    call.hangup();
+                // Hanging up a ringing call requires that we invoke call.hangup() as opposed to
+                // connection.hangup(). Without this change, the party originating the call will not
+                // get sent to voicemail if the user opts to reject the call.
+                if (isValidRingingCall()) {
+                    Call call = getCall();
+                    if (call != null) {
+                        call.hangup();
+                    } else {
+                        Log.w(this, "Attempting to hangup a connection without backing call.");
+                    }
                 } else {
-                    Log.w(this, "Attempting to hangup a connection without backing call.");
+                    // We still prefer to call connection.hangup() for non-ringing calls in order
+                    // to support hanging-up specific calls within a conference call. If we invoked
+                    // call.hangup() while in a conference, we would end up hanging up the entire
+                    // conference call instead of the specific connection.
+                    mOriginalConnection.hangup();
                 }
             } catch (CallStateException e) {
                 Log.e(this, e, "Call to Connection.hangup failed with exception");