Merge "Protect against INCALL->RINGING transition in AudioManager" into lmp-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3877edf..5d11fb3 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -36,6 +36,7 @@
     <uses-permission android:name="android.permission.BIND_CONNECTION_SERVICE" />
     <uses-permission android:name="android.permission.BIND_INCALL_SERVICE" />
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+    <uses-permission android:name="android.permission.BROADCAST_CALLLOG_INFO" />
 
     <!-- Protects the ability to register any PhoneAccount with a capability flags of either
          PhoneAccount#CAPABILITY_CALL_PROVIDER or PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION. -->
@@ -44,6 +45,16 @@
             android:label="Register CALL_PROVIDER or SIM_SUBSCRIPTION PhoneAccount"
             android:protectionLevel="signature"/>
 
+    <permission
+            android:name="android.permission.BROADCAST_CALLLOG_INFO"
+            android:label="Broadcast the call type/duration information"
+            android:protectionLevel="signature|system"/>
+
+    <permission
+            android:name="android.permission.PROCESS_CALLLOG_INFO"
+            android:label="Register to handle the broadcasted call type/duration information"
+            android:protectionLevel="signature|system"/>
+
     <!-- Declare which SDK level this application was built against. This is needed so that IDEs
          can check for incompatible APIs. -->
     <uses-sdk android:minSdkVersion="19" />
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index debd49b..f49074f 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -30,15 +30,15 @@
     <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"मैं आपको वापस कॉल करूंगा/करूंगी."</string>
     <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"मैं आपको बाद में कॉल करूंगा/करूंगी."</string>
     <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"अभी बात नहीं हो सकती. बाद में कॉल करें?"</string>
-    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"त्वरित प्रतिसाद"</string>
-    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"त्वरित प्रतिसाद संपादित करें"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"झटपट उत्तर"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"झटपट उत्तर संपादित करें"</string>
     <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
-    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"त्वरित प्रतिसाद"</string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"झटपट उत्तर"</string>
     <string name="respond_via_sms_menu_reset_default_activity" msgid="1461742052902053466">"डिफ़ॉल्ट ऐप्स  रीसेट करें"</string>
     <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> को संदेश भेजा गया."</string>
     <string name="outgoing_call_not_allowed" msgid="1434784869685645427">"इस उपयोगकर्ता को गैर-आपातकालीन फ़ोन कॉल करने की अनुमति नहीं है"</string>
     <string name="outgoing_call_error_no_phone_number_supplied" msgid="4987143284589568716">"कॉल नहीं भेजा गया, कोई मान्य नंबर नहीं डाला गया था."</string>
-    <string name="no_vm_number" msgid="4164780423805688336">"गुम ध्वनिमेल नंबर"</string>
-    <string name="no_vm_number_msg" msgid="1300729501030053828">"सिम कार्ड पर कोई ध्वनिमेल नंबर संग्रहीत नहीं है."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"गुम वॉयस मेल नंबर"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"सिम कार्ड पर कोई वॉयस मेल नंबर संग्रहीत नहीं है."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"नंबर जोड़ें"</string>
 </resources>
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index edb3a38..a0a8a62 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -557,8 +557,12 @@
     }
 
     void setCallCapabilities(int callCapabilities) {
+        setCallCapabilities(callCapabilities, false /* forceUpdate */);
+    }
+
+    void setCallCapabilities(int callCapabilities, boolean forceUpdate) {
         Log.v(this, "setCallCapabilities: %s", PhoneCapabilities.toString(callCapabilities));
-        if (mCallCapabilities != callCapabilities) {
+        if (forceUpdate || mCallCapabilities != callCapabilities) {
            mCallCapabilities = callCapabilities;
             for (Listener l : mListeners) {
                 l.onCallCapabilitiesChanged(this);
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 719e525..a89dcea 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -330,7 +330,7 @@
     }
 
     private void updateAudioStreamAndMode() {
-        Log.v(this, "updateAudioStreamAndMode, mIsRinging: %b, mIsTonePlaying: %b", mIsRinging,
+        Log.i(this, "updateAudioStreamAndMode, mIsRinging: %b, mIsTonePlaying: %b", mIsRinging,
                 mIsTonePlaying);
         if (mIsRinging) {
             requestAudioFocusAndSetMode(AudioManager.STREAM_RING, AudioManager.MODE_RINGTONE);
@@ -359,7 +359,7 @@
     }
 
     private void requestAudioFocusAndSetMode(int stream, int mode) {
-        Log.v(this, "requestAudioFocusAndSetMode, stream: %d -> %d", mAudioFocusStreamType, stream);
+        Log.i(this, "requestAudioFocusAndSetMode, stream: %d -> %d", mAudioFocusStreamType, stream);
         Preconditions.checkState(stream != STREAM_NONE);
 
         // Even if we already have focus, if the stream is different we update audio manager to give
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
old mode 100644
new mode 100755
index 89d9316..658af10
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -17,6 +17,8 @@
 package com.android.server.telecom;
 
 import android.content.Context;
+import android.content.Intent;
+import android.Manifest.permission;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.provider.CallLog.Calls;
@@ -83,6 +85,12 @@
     private static final String TAG = CallLogManager.class.getSimpleName();
 
     private final Context mContext;
+    private static final String ACTION_CALLS_TABLE_ADD_ENTRY =
+                "com.android.server.telecom.intent.action.CALLS_ADD_ENTRY";
+    private static final String PERMISSION_PROCESS_CALLLOG_INFO =
+                "android.permission.PROCESS_CALLLOG_INFO";
+    private static final String CALL_TYPE = "callType";
+    private static final String CALL_DURATION = "duration";
 
     public CallLogManager(Context context) {
         mContext = context;
@@ -174,6 +182,8 @@
         // Don't log emergency numbers if the device doesn't allow it.
         final boolean isOkToLogThisCall = !isEmergencyNumber || okToLogEmergencyNumber;
 
+        sendAddCallBroadcast(callType, duration);
+
         if (isOkToLogThisCall) {
             Log.d(TAG, "Logging Calllog entry: " + callerInfo + ", "
                     + Log.pii(number) + "," + presentation + ", " + callType
@@ -293,4 +303,11 @@
             }
         }
     }
+
+    private void sendAddCallBroadcast(int callType, long duration) {
+        Intent callAddIntent = new Intent(ACTION_CALLS_TABLE_ADD_ENTRY);
+        callAddIntent.putExtra(CALL_TYPE, callType);
+        callAddIntent.putExtra(CALL_DURATION, duration);
+        mContext.sendBroadcast(callAddIntent, PERMISSION_PROCESS_CALLLOG_INFO);
+    }
 }
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 932084b..d714a6b 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -447,12 +447,7 @@
         call.setExtras(extras);
 
         // Do not add the call if it is a potential MMI code.
-        // We also want to skip adding the call if there is a broadcast receiver which could
-        // intercept the outgoing call and cancel it.  We do this to ensure that we do not show the
-        // InCall UI for the cancelled call.  If the call is not intercepted, it will be added in
-        // {@link CallsManager#onSuccessfulOutgoingCall}.
-        if (isPotentialMMICode(handle) || isPotentialInCallMMICode ||
-                (!isEmergencyCall && canOutgoingCallBroadcastsBeIntercepted())) {
+        if (isPotentialMMICode(handle) || isPotentialInCallMMICode) {
             call.addListener(this);
         } else {
             addCall(call);
@@ -1001,6 +996,14 @@
             }
             updateForegroundCall();
         }
+
+        // Now that a call has been removed, other calls may gain new call capabilities (for
+        // example, if only one call is left, it is now add-call capable again). Trigger the
+        // recalculation of the call's current capabilities by forcing an update. (See
+        // InCallController.toParcelableCall()).
+        for (Call otherCall : mCalls) {
+            otherCall.setCallCapabilities(call.getCallCapabilities(), true /* forceUpdate */);
+        }
     }
 
     /**
@@ -1203,28 +1206,6 @@
     }
 
     /**
-     * Determines if the {@link Intent#ACTION_NEW_OUTGOING_CALL} intent can be received by another
-     * package with priority 0, potentially providing the ability to cancel the intent before it
-     * is received.
-     *
-     * @return {@code true} if the intent can be intercepted by another
-     */
-    private boolean canOutgoingCallBroadcastsBeIntercepted() {
-        PackageManager packageManager = mContext.getPackageManager();
-        Intent intent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
-        List<ResolveInfo> receivers = packageManager.queryBroadcastReceivers(intent, 0);
-
-        for (ResolveInfo info : receivers) {
-            // Check for an interceptor with priority 0; this would potentially receive the
-            // broadcast before Telecom and cancel it.
-            if (info.priority == 0) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
      * Dumps the state of the {@link CallsManager}.
      *
      * @param pw The {@code IndentingPrintWriter} to write the state to.
diff --git a/src/com/android/server/telecom/CreateConnectionProcessor.java b/src/com/android/server/telecom/CreateConnectionProcessor.java
index 0c6e25d..fab2679 100644
--- a/src/com/android/server/telecom/CreateConnectionProcessor.java
+++ b/src/com/android/server/telecom/CreateConnectionProcessor.java
@@ -238,6 +238,18 @@
             Log.i(this, "Emergency number detected");
             mAttemptRecords.clear();
             List<PhoneAccount> allAccounts = mPhoneAccountRegistrar.getAllPhoneAccounts();
+
+            if (allAccounts.isEmpty()) {
+                // If the list of phone accounts is empty at this point, it means Telephony hasn't
+                // registered any phone accounts yet. Add a fallback emergency phone account so
+                // that emergency calls can still go through. We create a new ArrayLists here just
+                // in case the implementation of PhoneAccountRegistrar ever returns an unmodifiable
+                // list.
+                allAccounts = new ArrayList<PhoneAccount>();
+                allAccounts.add(TelephonyUtil.getDefaultEmergencyPhoneAccount());
+            }
+
+
             // First, add SIM phone accounts which can place emergency calls.
             for (PhoneAccount phoneAccount : allAccounts) {
                 if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) &&
diff --git a/src/com/android/server/telecom/MissedCallNotifier.java b/src/com/android/server/telecom/MissedCallNotifier.java
index 8abd5b7..76d0ae8 100644
--- a/src/com/android/server/telecom/MissedCallNotifier.java
+++ b/src/com/android/server/telecom/MissedCallNotifier.java
@@ -29,6 +29,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.UserHandle;
 import android.provider.CallLog;
 import android.provider.CallLog.Calls;
 import android.telecom.CallState;
@@ -166,7 +167,8 @@
         configureLedOnNotification(notification);
 
         Log.i(this, "Adding missed call notification for %s.", call);
-        mNotificationManager.notify(MISSED_CALL_NOTIFICATION_ID, notification);
+        mNotificationManager.notifyAsUser(
+                null /* tag */ , MISSED_CALL_NOTIFICATION_ID, notification, UserHandle.CURRENT);
     }
 
     /** Cancels the "missed call" notification. */
diff --git a/src/com/android/server/telecom/TelephonyUtil.java b/src/com/android/server/telecom/TelephonyUtil.java
index 29b6f89..a130522 100644
--- a/src/com/android/server/telecom/TelephonyUtil.java
+++ b/src/com/android/server/telecom/TelephonyUtil.java
@@ -19,6 +19,8 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.net.Uri;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
 import android.telephony.PhoneNumberUtils;
 
 /**
@@ -33,8 +35,25 @@
     private static final String PSTN_CALL_SERVICE_CLASS_NAME =
             "com.android.services.telephony.TelephonyConnectionService";
 
+    private static final PhoneAccountHandle DEFAULT_EMERGENCY_PHONE_ACCOUNT_HANDLE =
+            new PhoneAccountHandle(
+                    new ComponentName(TELEPHONY_PACKAGE_NAME, PSTN_CALL_SERVICE_CLASS_NAME), "E");
+
     private TelephonyUtil() {}
 
+    /**
+     * @return fallback {@link PhoneAccount} to be used by Telecom for emergency calls in the
+     * rare case that Telephony has not registered any phone accounts yet. Details about this
+     * account are not expected to be displayed in the UI, so the description, etc are not
+     * populated.
+     */
+    static PhoneAccount getDefaultEmergencyPhoneAccount() {
+        return PhoneAccount.builder(DEFAULT_EMERGENCY_PHONE_ACCOUNT_HANDLE, "E")
+                .setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
+                        PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                        PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS).build();
+    }
+
     static boolean isPstnComponentName(ComponentName componentName) {
         final ComponentName pstnComponentName = new ComponentName(
                 TELEPHONY_PACKAGE_NAME, PSTN_CALL_SERVICE_CLASS_NAME);