Merge "Fix issue 2472495: Phone cannot be set to silent mode via volume keys while Driveabout is taking."
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index ae0eccb..74e6157 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -208,6 +208,9 @@
     /** @see System#MODE_RINGER_STREAMS_AFFECTED */
     private int mRingerModeAffectedStreams;
 
+    // Streams currently muted by ringer mode
+    private int mRingerModeMutedStreams;
+
     /** @see System#MUTE_STREAMS_AFFECTED */
     private int mMuteAffectedStreams;
 
@@ -404,7 +407,7 @@
 
 
         VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]];
-        final int oldIndex = streamState.mIndex;
+        final int oldIndex = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex;
         boolean adjustVolume = true;
 
         // If either the client forces allowing ringer modes for this adjustment,
@@ -416,30 +419,43 @@
             adjustVolume = checkForRingerModeChange(oldIndex, direction);
         }
 
-        if (adjustVolume && streamState.adjustIndex(direction)) {
-            // Post message to set system volume (it in turn will post a message
-            // to persist). Do not change volume if stream is muted.
-            if (streamState.muteCount() == 0) {
+        // If stream is muted, adjust last audible index only
+        int index;
+        if (streamState.muteCount() != 0) {
+            if (adjustVolume) {
+                streamState.adjustLastAudibleIndex(direction);
+                // Post a persist volume msg
+                sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType,
+                        SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY);
+            }
+            index = streamState.mLastAudibleIndex;
+        } else {
+            if (adjustVolume && streamState.adjustIndex(direction)) {
+                // Post message to set system volume (it in turn will post a message
+                // to persist). Do not change volume if stream is muted.
                 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, STREAM_VOLUME_ALIAS[streamType], SENDMSG_NOOP, 0, 0,
                         streamState, 0);
             }
+            index = streamState.mIndex;
         }
-
         // UI
         mVolumePanel.postVolumeChanged(streamType, flags);
         // Broadcast Intent
-        sendVolumeUpdate(streamType, oldIndex, streamState.mIndex);
+        sendVolumeUpdate(streamType, oldIndex, index);
     }
 
     /** @see AudioManager#setStreamVolume(int, int, int) */
     public void setStreamVolume(int streamType, int index, int flags) {
         ensureValidStreamType(streamType);
+        VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]];
 
-        final int oldIndex = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex;
+        final int oldIndex = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex;
 
         index = rescaleIndex(index * 10, streamType, STREAM_VOLUME_ALIAS[streamType]);
         setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, false, true);
 
+        index = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex;
+
         // UI, etc.
         mVolumePanel.postVolumeChanged(streamType, flags);
         // Broadcast Intent
@@ -470,22 +486,30 @@
      */
     private void setStreamVolumeInt(int streamType, int index, boolean force, boolean lastAudible) {
         VolumeStreamState streamState = mStreamStates[streamType];
-        if (streamState.setIndex(index, lastAudible) || force) {
-            // Post message to set system volume (it in turn will post a message
-            // to persist).
-            // If stream is muted or we are in silent mode and stream is affected by ringer mode
-            // and the new volume is not 0, just persist the new volume but do not change
-            // current value
-            if (streamState.muteCount() == 0 &&
-                (mRingerMode == AudioManager.RINGER_MODE_NORMAL ||
-                !isStreamAffectedByRingerMode(streamType) ||
-                index == 0)) {
-                sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0,
-                        streamState, 0);
-            } else {
-                // Post a persist volume msg
-                sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType,
-                        SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY);
+
+        // If stream is muted, set last audible index only
+        if (streamState.muteCount() != 0) {
+            streamState.setLastAudibleIndex(index);
+            // Post a persist volume msg
+            sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType,
+                    SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY);
+        } else {
+            if (streamState.setIndex(index, lastAudible) || force) {
+                // Post message to set system volume (it in turn will post a message
+                // to persist).
+                // If we are in silent mode and stream is affected by ringer mode
+                // and the new volume is not 0, just persist the new volume but do not change
+                // current value
+                if (mRingerMode == AudioManager.RINGER_MODE_NORMAL ||
+                    !isStreamAffectedByRingerMode(streamType) ||
+                    index == 0) {
+                    sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0,
+                            streamState, 0);
+                } else {
+                    // Post a persist volume msg
+                    sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType,
+                            SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY);
+                }
             }
         }
     }
@@ -537,27 +561,24 @@
     private void setRingerModeInt(int ringerMode, boolean persist) {
         mRingerMode = ringerMode;
 
-        // Adjust volumes via posting message
+        // Mute stream if not previously muted by ringer mode and ringer mode
+        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
+        // Unmute stream if previously muted by ringer mode and ringer mode
+        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
         int numStreamTypes = AudioSystem.getNumStreamTypes();
-        if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
-            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
-                if (!isStreamAffectedByRingerMode(streamType)) continue;
-                // Bring back last audible volume
-                setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex,
-                                   true, false);
-            }
-        } else {
-            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
-                if (isStreamAffectedByRingerMode(streamType)) {
-                    // Either silent or vibrate, either way volume is 0
-                    setStreamVolumeInt(streamType, 0, false, false);
-                } else {
-                    // restore stream volume in the case the stream changed from affected
-                    // to non affected by ringer mode. Does not arm to do it for streams that
-                    // are not affected as well.
-                    setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex,
-                            true, false);
+        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+            if (isStreamMutedByRingerMode(streamType)) {
+                if (!isStreamAffectedByRingerMode(streamType) ||
+                    mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
+                    mStreamStates[streamType].mute(null, false);
+                    mRingerModeMutedStreams &= ~(1 << streamType);
                 }
+            } else {
+                if (isStreamAffectedByRingerMode(streamType) &&
+                    mRingerMode != AudioManager.RINGER_MODE_NORMAL) {
+                   mStreamStates[streamType].mute(null, true);
+                   mRingerModeMutedStreams |= (1 << streamType);
+               }
             }
         }
 
@@ -728,7 +749,7 @@
             }
             int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
             int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex;
-            setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, true);
+            setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, false);
         }
     }
 
@@ -862,7 +883,7 @@
             }
             streamState.mLastAudibleIndex = streamState.getValidIndex(index);
 
-            // unmute stream that whas muted but is not affect by mute anymore
+            // unmute stream that was muted but is not affect by mute anymore
             if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
                 int size = streamState.mDeathHandlers.size();
                 for (int i = 0; i < size; i++) {
@@ -1127,6 +1148,10 @@
         return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
     }
 
+    private boolean isStreamMutedByRingerMode(int streamType) {
+        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
+    }
+
     public boolean isStreamAffectedByMute(int streamType) {
         return (mMuteAffectedStreams & (1 << streamType)) != 0;
     }
@@ -1293,6 +1318,14 @@
             }
         }
 
+        public void setLastAudibleIndex(int index) {
+            mLastAudibleIndex = getValidIndex(index);
+        }
+
+        public void adjustLastAudibleIndex(int deltaIndex) {
+            setLastAudibleIndex(mLastAudibleIndex + deltaIndex * 10);
+        }
+
         public int getMaxIndex() {
             return mIndexMax;
         }
@@ -1330,7 +1363,10 @@
                         if (mMuteCount == 0) {
                             // Register for client death notification
                             try {
-                                mICallback.linkToDeath(this, 0);
+                                // mICallback can be 0 if muted by AudioService
+                                if (mICallback != null) {
+                                    mICallback.linkToDeath(this, 0);
+                                }
                                 mDeathHandlers.add(this);
                                 // If the stream is not yet muted by any client, set lvel to 0
                                 if (muteCount() == 0) {
@@ -1356,9 +1392,12 @@
                             if (mMuteCount == 0) {
                                 // Unregistr from client death notification
                                 mDeathHandlers.remove(this);
-                                mICallback.unlinkToDeath(this, 0);
+                                // mICallback can be 0 if muted by AudioService
+                                if (mICallback != null) {
+                                    mICallback.unlinkToDeath(this, 0);
+                                }
                                 if (muteCount() == 0) {
-                                    // If the stream is not mut any more, restore it's volume if
+                                    // If the stream is not muted any more, restore it's volume if
                                     // ringer mode allows it
                                     if (!isStreamAffectedByRingerMode(mStreamType) || mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
                                         setIndex(mLastAudibleIndex, false);
@@ -1398,7 +1437,7 @@
                 int size = mDeathHandlers.size();
                 for (int i = 0; i < size; i++) {
                     handler = mDeathHandlers.get(i);
-                    if (cb.equals(handler.mICallback)) {
+                    if (cb == handler.mICallback) {
                         return handler;
                     }
                 }