Merge "Add more logging for analytics dumps"
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index de22352..cda6054 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -2444,6 +2444,7 @@
     public Call getHeldCallByConnectionService(ConnectionServiceWrapper connSvr) {
         Optional<Call> heldCall = mCalls.stream()
                 .filter(call -> call.getConnectionService() == connSvr
+                        && call.getParentCall() == null
                         && call.getState() == CallState.ON_HOLD)
                 .findFirst();
         return heldCall.isPresent() ? heldCall.get() : null;
diff --git a/src/com/android/server/telecom/InCallTonePlayer.java b/src/com/android/server/telecom/InCallTonePlayer.java
index d0afe28..5864ce0 100644
--- a/src/com/android/server/telecom/InCallTonePlayer.java
+++ b/src/com/android/server/telecom/InCallTonePlayer.java
@@ -16,10 +16,13 @@
 
 package com.android.server.telecom;
 
+import android.annotation.Nullable;
+import android.content.Context;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.MediaPlayer;
 import android.media.ToneGenerator;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
 import android.telecom.Log;
@@ -87,33 +90,51 @@
     public static class MediaPlayerAdapterImpl implements MediaPlayerAdapter {
         private MediaPlayer mMediaPlayer;
 
-        public MediaPlayerAdapterImpl(MediaPlayer mediaPlayer) {
+        /**
+         * Create new media player adapter backed by a real mediaplayer.
+         * Note: Its possible for the mediaplayer to be null if
+         * {@link MediaPlayer#create(Context, Uri)} fails for some reason; in this case we can
+         * continue but not bother playing the audio.
+         * @param mediaPlayer The media player.
+         */
+        public MediaPlayerAdapterImpl(@Nullable MediaPlayer mediaPlayer) {
             mMediaPlayer = mediaPlayer;
         }
 
         @Override
         public void setLooping(boolean isLooping) {
-            mMediaPlayer.setLooping(isLooping);
+            if (mMediaPlayer != null) {
+                mMediaPlayer.setLooping(isLooping);
+            }
         }
 
         @Override
         public void setOnCompletionListener(MediaPlayer.OnCompletionListener listener) {
-            mMediaPlayer.setOnCompletionListener(listener);
+            if (mMediaPlayer != null) {
+                mMediaPlayer.setOnCompletionListener(listener);
+            }
         }
 
         @Override
         public void start() {
-            mMediaPlayer.start();
+            if (mMediaPlayer != null) {
+                mMediaPlayer.start();
+            }
         }
 
         @Override
         public void release() {
-            mMediaPlayer.release();
+            if (mMediaPlayer != null) {
+                mMediaPlayer.release();
+            }
         }
 
         @Override
         public int getDuration() {
-            return mMediaPlayer.getDuration();
+            if (mMediaPlayer != null) {
+                return mMediaPlayer.getDuration();
+            }
+            return 0;
         }
     }
 
diff --git a/src/com/android/server/telecom/ServiceBinder.java b/src/com/android/server/telecom/ServiceBinder.java
index cf5407d..a322a5e 100644
--- a/src/com/android/server/telecom/ServiceBinder.java
+++ b/src/com/android/server/telecom/ServiceBinder.java
@@ -73,13 +73,15 @@
             // Reset any abort request if we're asked to bind again.
             clearAbort();
 
-            if (!mCallbacks.isEmpty()) {
-                // Binding already in progress, append to the list of callbacks and bail out.
+            synchronized (mCallbacks) {
+                if (!mCallbacks.isEmpty()) {
+                    // Binding already in progress, append to the list of callbacks and bail out.
+                    mCallbacks.add(callback);
+                    return;
+                }
                 mCallbacks.add(callback);
-                return;
             }
 
-            mCallbacks.add(callback);
             if (mServiceConnection == null) {
                 Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
                 ServiceConnection connection = new ServiceBinderConnection(call);
@@ -351,10 +353,16 @@
      * outstanding callbacks is cleared afterwards.
      */
     private void handleSuccessfulConnection() {
-        for (BindCallback callback : mCallbacks) {
+        // Make a copy so that we don't have a deadlock inside one of the callbacks.
+        Set<BindCallback> callbacksCopy = new ArraySet<>();
+        synchronized (mCallbacks) {
+            callbacksCopy.addAll(mCallbacks);
+            mCallbacks.clear();
+        }
+
+        for (BindCallback callback : callbacksCopy) {
             callback.onSuccess();
         }
-        mCallbacks.clear();
     }
 
     /**
@@ -362,10 +370,16 @@
      * outstanding callbacks is cleared afterwards.
      */
     private void handleFailedConnection() {
-        for (BindCallback callback : mCallbacks) {
+        // Make a copy so that we don't have a deadlock inside one of the callbacks.
+        Set<BindCallback> callbacksCopy = new ArraySet<>();
+        synchronized (mCallbacks) {
+            callbacksCopy.addAll(mCallbacks);
+            mCallbacks.clear();
+        }
+
+        for (BindCallback callback : callbacksCopy) {
             callback.onFailure();
         }
-        mCallbacks.clear();
     }
 
     /**