Merge "Correctly send the original address in BluetoothPhoneService if using gateway" into lmp-dev
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
index 9dca6a2..9d1390f 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn-rIN/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="telecommAppLabel" product="default" msgid="3477737022166975496">"ಫೋನ್"</string>
     <string name="unknown" msgid="6878797917991465859">"ಅಜ್ಞಾತ"</string>
-    <string name="notification_missedCallTitle" msgid="7554385905572364535">"ತಪ್ಪಿ ಹೋದ ಕರೆ"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"ಮಿಸ್ಡ್‌ ಕಾಲ್‌"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"ತಪ್ಪಿದ ಕರೆಗಳು"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> ತಪ್ಪಿದ ಕರೆಗಳು"</string>
-    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> ಅವರಿಂದ ತಪ್ಪಿದ ಕರೆ"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> ಅವರಿಂದ ಮಿಸ್ಡ್‌ ಕಾಲ್‌"</string>
     <string name="notification_missedCall_call_back" msgid="2684890353590890187">"ಮರಳಿ ಕರೆ ಮಾಡಿ"</string>
     <string name="notification_missedCall_message" msgid="3049928912736917988">"ಸಂದೇಶ"</string>
     <string name="accessibility_call_muted" msgid="2776111226185342220">"ಕರೆಯನ್ನು ಮ್ಯೂಟ್ ಮಾಡಲಾಗಿದೆ."</string>
diff --git a/src/com/android/server/telecom/BluetoothPhoneService.java b/src/com/android/server/telecom/BluetoothPhoneService.java
index 7d0dab1..4356558 100644
--- a/src/com/android/server/telecom/BluetoothPhoneService.java
+++ b/src/com/android/server/telecom/BluetoothPhoneService.java
@@ -97,6 +97,12 @@
     // Add all held calls to a conference
     private static final int CHLD_TYPE_ADDHELDTOCONF = 3;
 
+    private int mNumActiveCalls = 0;
+    private int mNumHeldCalls = 0;
+    private int mBluetoothCallState = CALL_STATE_IDLE;
+    private String mRingingAddress = null;
+    private int mRingingAddressType = 0;
+
     /**
      * Binder implementation of IBluetoothHeadsetPhone. Implements the command interface that the
      * bluetooth headset code uses to control call.
@@ -517,8 +523,8 @@
         String address = addressUri == null ? null : addressUri.getSchemeSpecificPart();
         int addressType = address == null ? -1 : PhoneNumberUtils.toaFromString(address);
 
-        Log.d(this, "sending clcc for call %d, %d, %d, %b, %s, %d",
-                index, direction, state, isPartOfConference, address, addressType);
+        Log.i(this, "sending clcc for call %d, %d, %d, %b, %s, %d",
+                index, direction, state, isPartOfConference, Log.piiHandle(address), addressType);
         mBluetoothHeadset.clccResponse(
                 index, direction, state, 0, isPartOfConference, address, addressType);
     }
@@ -567,26 +573,56 @@
             ringingAddress = "";
         }
 
-        Log.d(TAG, "updateHeadsetWithCallState " +
-                "numActive %s, " +
-                "numHeld %s, " +
-                "callState %s, " +
-                "ringing number %s, " +
-                "ringing type %s",
-                activeCall,
-                heldCall,
-                bluetoothCallState,
-                ringingAddress,
-                ringingAddressType);
+        int numActiveCalls = activeCall == null ? 0 : 1;
+        int numHeldCalls = heldCall == null ? 0 : 1;
 
+        if (mBluetoothHeadset != null &&
+                (numActiveCalls != mNumActiveCalls ||
+                 numHeldCalls != mNumHeldCalls ||
+                 bluetoothCallState != mBluetoothCallState ||
+                 !TextUtils.equals(ringingAddress, mRingingAddress) ||
+                 ringingAddressType != mRingingAddressType)) {
 
-        if (mBluetoothHeadset != null) {
+            // If the call is transitioning into the alerting state, send DIALING first.
+            // Some devices expect to see a DIALING state prior to seeing an ALERTING state
+            // so we need to send it first.
+            boolean sendDialingFirst = mBluetoothCallState != bluetoothCallState &&
+                    bluetoothCallState == CALL_STATE_ALERTING;
+
+            mNumActiveCalls = numActiveCalls;
+            mNumHeldCalls = numHeldCalls;
+            mBluetoothCallState = bluetoothCallState;
+            mRingingAddress = ringingAddress;
+            mRingingAddressType = ringingAddressType;
+
+            if (sendDialingFirst) {
+                Log.i(TAG, "Sending dialing state");
+                mBluetoothHeadset.phoneStateChanged(
+                        mNumActiveCalls,
+                        mNumHeldCalls,
+                        CALL_STATE_DIALING,
+                        mRingingAddress,
+                        mRingingAddressType);
+            }
+
+            Log.i(TAG, "updateHeadsetWithCallState " +
+                    "numActive %s, " +
+                    "numHeld %s, " +
+                    "callState %s, " +
+                    "ringing number %s, " +
+                    "ringing type %s",
+                    mNumActiveCalls,
+                    mNumHeldCalls,
+                    mBluetoothCallState,
+                    Log.pii(mRingingAddress),
+                    mRingingAddressType);
+
             mBluetoothHeadset.phoneStateChanged(
-                    activeCall == null ? 0 : 1,
-                    heldCall == null ? 0 : 1,
-                    bluetoothCallState,
-                    ringingAddress,
-                    ringingAddressType);
+                    mNumActiveCalls,
+                    mNumHeldCalls,
+                    mBluetoothCallState,
+                    mRingingAddress,
+                    mRingingAddressType);
         }
     }
 
@@ -620,10 +656,6 @@
             case CallState.DISCONNECTED:
             case CallState.CONNECTING:
             case CallState.PRE_DIAL_WAIT:
-                if (callState == CallState.CONNECTING || callState == CallState.PRE_DIAL_WAIT) {
-                    Log.w(this, "convertCallState: unexpected state %s",
-                            CallState.toString(callState));
-                }
                 return CALL_STATE_IDLE;
 
             case CallState.ACTIVE:
diff --git a/src/com/android/server/telecom/CreateConnectionProcessor.java b/src/com/android/server/telecom/CreateConnectionProcessor.java
index 6adb72c..6aae49b 100644
--- a/src/com/android/server/telecom/CreateConnectionProcessor.java
+++ b/src/com/android/server/telecom/CreateConnectionProcessor.java
@@ -176,7 +176,8 @@
         } else {
             Log.v(this, "attemptNextPhoneAccount, no more accounts, failing");
             if (mResponse != null) {
-                mResponse.handleCreateConnectionFailure(mLastErrorDisconnectCause);
+                mResponse.handleCreateConnectionFailure(mLastErrorDisconnectCause != null ?
+                        mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR));
                 mResponse = null;
                 mCall.clearConnectionService();
             }
diff --git a/src/com/android/server/telecom/InCallToneMonitor.java b/src/com/android/server/telecom/InCallToneMonitor.java
index b71a102..32d0924 100644
--- a/src/com/android/server/telecom/InCallToneMonitor.java
+++ b/src/com/android/server/telecom/InCallToneMonitor.java
@@ -42,7 +42,7 @@
             return;
         }
 
-        if (newState == CallState.DISCONNECTED) {
+        if (newState == CallState.DISCONNECTED && call.getDisconnectCause() != null) {
             int toneToPlay = InCallTonePlayer.TONE_INVALID;
 
             Log.v(this, "Disconnect cause: %s.", call.getDisconnectCause());
diff --git a/src/com/android/server/telecom/PhoneAccountBroadcastReceiver.java b/src/com/android/server/telecom/PhoneAccountBroadcastReceiver.java
index 1104518..74f63cd 100644
--- a/src/com/android/server/telecom/PhoneAccountBroadcastReceiver.java
+++ b/src/com/android/server/telecom/PhoneAccountBroadcastReceiver.java
@@ -61,6 +61,9 @@
      * @param packageName The name of the removed package.
      */
     private void handlePackageRemoved(Context context, String packageName) {
-        CallsManager.getInstance().getPhoneAccountRegistrar().clearAccounts(packageName);
+        final CallsManager callsManager = CallsManager.getInstance();
+        if (callsManager != null) {
+            callsManager.getPhoneAccountRegistrar().clearAccounts(packageName);
+        }
     }
 }
diff --git a/src/com/android/server/telecom/PhoneStateBroadcaster.java b/src/com/android/server/telecom/PhoneStateBroadcaster.java
index 0c16689..b96eb02 100644
--- a/src/com/android/server/telecom/PhoneStateBroadcaster.java
+++ b/src/com/android/server/telecom/PhoneStateBroadcaster.java
@@ -61,9 +61,17 @@
 
     @Override
     public void onCallRemoved(Call call) {
-        if (!CallsManager.getInstance().hasAnyCalls()) {
-            sendPhoneStateChangedBroadcast(call, TelephonyManager.CALL_STATE_IDLE);
+        // Recalculate the current phone state based on the consolidated state of the remaining
+        // calls in the call list.
+        final CallsManager callsManager = CallsManager.getInstance();
+        int callState = TelephonyManager.CALL_STATE_IDLE;
+        if (callsManager.hasRingingCall()) {
+            callState = TelephonyManager.CALL_STATE_RINGING;
+        } else if (callsManager.getFirstCallWithState(CallState.DIALING, CallState.ACTIVE,
+                    CallState.ON_HOLD) != null) {
+            callState = TelephonyManager.CALL_STATE_OFFHOOK;
         }
+        sendPhoneStateChangedBroadcast(call, callState);
     }
 
     int getCallState() {