Merge "Missed call notification creates PendingIntent using TaskStackBuilder" into klp-dev
diff --git a/common/src/com/android/services/telephony/common/Call.java b/common/src/com/android/services/telephony/common/Call.java
index f397f62..debad61 100644
--- a/common/src/com/android/services/telephony/common/Call.java
+++ b/common/src/com/android/services/telephony/common/Call.java
@@ -372,7 +372,7 @@
     public String toString() {
         return Objects.toStringHelper(this)
                 .add("mCallId", mCallId)
-                .add("mState", mState)
+                .add("mState", STATE_MAP.get(mState))
                 .add("mDisconnectCause", mDisconnectCause)
                 .add("mCapabilities", mCapabilities)
                 .add("mConnectTime", mConnectTime)
diff --git a/common/src/com/android/services/telephony/common/ICallHandlerService.aidl b/common/src/com/android/services/telephony/common/ICallHandlerService.aidl
index ccf30b0..5eddb0e 100644
--- a/common/src/com/android/services/telephony/common/ICallHandlerService.aidl
+++ b/common/src/com/android/services/telephony/common/ICallHandlerService.aidl
@@ -55,7 +55,7 @@
      * Called when the audio mode changes.
      * {@see AudioMode}
      */
-    void onAudioModeChange(in int mode);
+    void onAudioModeChange(in int mode, in boolean muted);
 
     /**
      * Called when the supported audio modes change.
diff --git a/src/com/android/phone/AudioRouter.java b/src/com/android/phone/AudioRouter.java
index 517f777..00fc131 100644
--- a/src/com/android/phone/AudioRouter.java
+++ b/src/com/android/phone/AudioRouter.java
@@ -75,6 +75,13 @@
     }
 
     /**
+     * Returns the current mute state.
+     */
+    public boolean getMute() {
+        return PhoneUtils.getMute();
+    }
+
+    /**
      * Add a listener to audio mode changes.
      */
     public void addAudioModeListener(AudioModeListener listener) {
@@ -82,7 +89,7 @@
             mListeners.add(listener);
 
             // For first notification, mPreviousAudioMode doesn't make sense.
-            listener.onAudioModeChange(mAudioMode, mAudioMode);
+            listener.onAudioModeChange(mAudioMode, getMute());
             listener.onSupportedAudioModeChange(mSupportedModes);
         }
     }
@@ -187,6 +194,11 @@
         }
     }
 
+    public void onMuteChange(boolean muted) {
+        logD("onMuteChange: " + muted);
+        notifyListeners();
+    }
+
     /**
      * Called when the bluetooth connection changes.
      * We adjust the audio mode according to the state we receive.
@@ -323,13 +335,13 @@
         logD("Supported AudioMode: " + AudioMode.toString(mSupportedModes));
 
         for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onAudioModeChange(mPreviousMode, mAudioMode);
+            mListeners.get(i).onAudioModeChange(mAudioMode, getMute());
             mListeners.get(i).onSupportedAudioModeChange(mSupportedModes);
         }
     }
 
     public interface AudioModeListener {
-        void onAudioModeChange(int previousMode, int newMode);
+        void onAudioModeChange(int newMode, boolean muted);
         void onSupportedAudioModeChange(int modeMask);
     }
 
diff --git a/src/com/android/phone/CallHandlerServiceProxy.java b/src/com/android/phone/CallHandlerServiceProxy.java
index 624a086..6fdf80a 100644
--- a/src/com/android/phone/CallHandlerServiceProxy.java
+++ b/src/com/android/phone/CallHandlerServiceProxy.java
@@ -53,10 +53,11 @@
     private CallCommandService mCallCommandService;
     private CallModeler mCallModeler;
     private Context mContext;
+
     private ICallHandlerService mCallHandlerServiceGuarded;  // Guarded by mServiceAndQueueLock
-    private List<Call> mIncomingCallQueueGuarded;            // Guarded by mServiceAndQueueLock
-    private List<List<Call>> mUpdateCallQueueGuarded;        // Guarded by mServiceAndQueueLock
-    private List<Call> mDisconnectCallQueueGuarded;        // Guarded by mServiceAndQueueLock
+    // Single queue to guarantee ordering
+    private List<QueueParams> mQueue;                        // Guarded by mServiceAndQueueLock
+
     private final Object mServiceAndQueueLock = new Object();
     private int mBindRetryCount = 0;
 
@@ -157,7 +158,7 @@
     }
 
     @Override
-    public void onAudioModeChange(int previousMode, int newMode) {
+    public void onAudioModeChange(int newMode, boolean muted) {
         try {
             synchronized (mServiceAndQueueLock) {
                 // TODO(klp): does this need to be enqueued?
@@ -172,13 +173,13 @@
 
             // Just do a simple log for now.
             Log.i(TAG, "Updating with new audio mode: " + AudioMode.toString(newMode) +
-                    " from " + AudioMode.toString(previousMode));
+                    " with mute " + muted);
 
             if (DBG) {
                 Log.d(TAG, "onSupportAudioModeChange");
             }
 
-            mCallHandlerServiceGuarded.onAudioModeChange(newMode);
+            mCallHandlerServiceGuarded.onAudioModeChange(newMode, muted);
         } catch (Exception e) {
             Log.e(TAG, "Remote exception handling onAudioModeChange", e);
         }
@@ -283,16 +284,14 @@
      * Called when the in-call UI service is connected.  Send command interface to in-call.
      */
     private void onCallHandlerServiceConnected(ICallHandlerService callHandlerService) {
+
         synchronized (mServiceAndQueueLock) {
             mCallHandlerServiceGuarded = callHandlerService;
 
             // Before we send any updates, we need to set up the initial service calls.
             makeInitialServiceCalls();
 
-            // TODO(klp): combine queues into a single ordered queue.
-            processIncomingCallQueue();
-            processUpdateCallQueue();
-            processDisconnectQueue();
+            processQueue();
         }
     }
 
@@ -304,66 +303,71 @@
             mCallHandlerServiceGuarded.setCallCommandService(mCallCommandService);
 
             onSupportedAudioModeChange(mAudioRouter.getSupportedAudioModes());
-            final int mode = mAudioRouter.getAudioMode();
-            onAudioModeChange(mode, mode);
+            onAudioModeChange(mAudioRouter.getAudioMode(), mAudioRouter.getMute());
         } catch (RemoteException e) {
             Log.e(TAG, "Remote exception calling CallHandlerService::setCallCommandService", e);
         }
     }
 
+    private List<QueueParams> getQueue() {
+        if (mQueue == null) {
+            mQueue = Lists.newArrayList();
+        }
+        return mQueue;
+    }
 
     private void enqueueDisconnect(Call call) {
-        if (mDisconnectCallQueueGuarded == null) {
-            mDisconnectCallQueueGuarded = Lists.newArrayList();
-        }
-        mDisconnectCallQueueGuarded.add(new Call(call));
+        getQueue().add(new QueueParams(QueueParams.METHOD_DISCONNECT, new Call(call)));
     }
 
     private void enqueueIncoming(Call call) {
-        if (mIncomingCallQueueGuarded == null) {
-            mIncomingCallQueueGuarded = Lists.newArrayList();
-        }
-        mIncomingCallQueueGuarded.add(new Call(call));
+        getQueue().add(new QueueParams(QueueParams.METHOD_INCOMING, new Call(call)));
     }
 
     private void enqueueUpdate(List<Call> calls) {
-        if (mUpdateCallQueueGuarded == null) {
-            mUpdateCallQueueGuarded = Lists.newArrayList();
-        }
         final List<Call> copy = Lists.newArrayList();
         for (Call call : calls) {
             copy.add(new Call(call));
         }
-        mUpdateCallQueueGuarded.add(copy);
+        getQueue().add(new QueueParams(QueueParams.METHOD_INCOMING, copy));
     }
 
-    private void processDisconnectQueue() {
-        if (mDisconnectCallQueueGuarded != null) {
-            for (Call call : mDisconnectCallQueueGuarded) {
-                onDisconnect(call);
+    private void processQueue() {
+        List<QueueParams> queue = getQueue();
+        for (QueueParams params : queue) {
+            switch (params.mMethod) {
+                case QueueParams.METHOD_INCOMING:
+                    onIncoming((Call) params.mArg);
+                    break;
+                case QueueParams.METHOD_UPDATE:
+                    onUpdate((List<Call>) params.mArg);
+                    break;
+                case QueueParams.METHOD_DISCONNECT:
+                    onDisconnect((Call) params.mArg);
+                    break;
+                default:
+                    throw new IllegalArgumentException("Method type " + params.mMethod +
+                            " not recognized.");
             }
-            mDisconnectCallQueueGuarded.clear();
-            mDisconnectCallQueueGuarded = null;
         }
+        mQueue.clear();
+        mQueue = null;
     }
 
-    private void processIncomingCallQueue() {
-        if (mIncomingCallQueueGuarded != null) {
-            for (Call call : mIncomingCallQueueGuarded) {
-                onIncoming(call);
-            }
-            mIncomingCallQueueGuarded.clear();
-            mIncomingCallQueueGuarded = null;
-        }
-    }
+    /**
+     * Holds method parameters.
+     */
+    private static class QueueParams {
+        private static final int METHOD_INCOMING = 1;
+        private static final int METHOD_UPDATE = 2;
+        private static final int METHOD_DISCONNECT = 3;
 
-    private void processUpdateCallQueue() {
-        if (mUpdateCallQueueGuarded != null) {
-            for (List<Call> calls : mUpdateCallQueueGuarded) {
-                onUpdate(calls);
-            }
-            mUpdateCallQueueGuarded.clear();
-            mUpdateCallQueueGuarded = null;
+        private final int mMethod;
+        private final Object mArg;
+
+        private QueueParams(int method, Object arg) {
+            mMethod = method;
+            this.mArg = arg;
         }
     }
 }
diff --git a/src/com/android/phone/CallModeler.java b/src/com/android/phone/CallModeler.java
index 6b7a137..393e054 100644
--- a/src/com/android/phone/CallModeler.java
+++ b/src/com/android/phone/CallModeler.java
@@ -199,7 +199,6 @@
         final Call call = getCallFromMap(mCallMap, conn, true);
 
         updateCallFromConnection(call, conn, false);
-        call.setState(Call.State.INCOMING);
 
         for (int i = 0; i < mListeners.size(); ++i) {
             if (call != null) {
@@ -217,7 +216,6 @@
             final boolean wasConferenced = call.getState() == State.CONFERENCED;
 
             updateCallFromConnection(call, conn, false);
-            call.setState(Call.State.DISCONNECTED);
 
             for (int i = 0; i < mListeners.size(); ++i) {
                 mListeners.get(i).onDisconnect(call);
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index 6b96737..586cf88 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -1971,6 +1971,7 @@
             phone.setMute(muted);
         }
         app.notificationMgr.updateMuteNotification();
+        app.getAudioRouter().onMuteChange(muted);
     }
 
     /**