AudioService: improve initial safe volume delay

AudioService relies on a valid mmc in order to enforce the headset
volume limitation or not. There is a timeout to enforce the limitation
if no mcc is configured after boot.
Until this timeout is reached or a valid SIM is detected the headset
volume is not limited.

This change makes that the last known volume limitation state (enforced or
not) is persisted so that next time we boot, last known state is applied until
a new mcc is configured if any. In most cases, the mcc does not change from one
boot to the next and we do the right thing. If teh mcc does change, the correct
policy will be enforced when the mcc is detected or after the timeout.

Also fix a bug where the volume panel was not displayed if the limitation mechanism
is triggered at the first press on VOL+ key.

Bug 7455275.

Change-Id: Id0f2996d893d38c6a14f4f9e4a0e9e3be17ef127
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b94f0b9..ad68428 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5315,6 +5315,12 @@
         public static final String DOCK_AUDIO_MEDIA_ENABLED = "dock_audio_media_enabled";
 
         /**
+         * Persisted safe headphone volume management state by AudioService
+         * @hide
+         */
+        public static final String AUDIO_SAFE_VOLUME_STATE = "audio_safe_volume_state";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 22f699f..96c955f 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -157,6 +157,7 @@
     private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 25;
     private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 26;
     private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 27;
+    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 28;
 
     // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be
     // persisted
@@ -481,6 +482,14 @@
                 null,
                 0);
 
+        mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
+                                                        Settings.Global.AUDIO_SAFE_VOLUME_STATE,
+                                                        SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
+        // The default safe volume index read here will be replaced by the actual value when
+        // the mcc is read by onConfigureSafeVolume()
+        mSafeMediaVolumeIndex = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_safe_media_volume_index) * 10;
+
         readPersistedSettings();
         mSettingsObserver = new SettingsObserver();
         updateStreamVolumeAlias(false /*updateVolumes*/);
@@ -488,8 +497,6 @@
 
         mMediaServerOk = true;
 
-        mSafeMediaVolumeState = new Integer(SAFE_MEDIA_VOLUME_NOT_CONFIGURED);
-
         // Call setRingerModeInt() to apply correct mute
         // state on streams affected by ringer mode.
         mRingerModeMutedStreams = 0;
@@ -822,70 +829,72 @@
         // convert one UI step (+/-1) into a number of internal units on the stream alias
         int step = rescaleIndex(10, streamType, streamTypeAlias);
 
-        if ((direction == AudioManager.ADJUST_RAISE) &&
-                !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
-            return;
-        }
-
         int index;
         int oldIndex;
 
-        flags &= ~AudioManager.FLAG_FIXED_VOLUME;
-        if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
-               ((device & mFixedVolumeDevices) != 0)) {
-            flags |= AudioManager.FLAG_FIXED_VOLUME;
-            index = mStreamStates[streamType].getMaxIndex();
+        if ((direction == AudioManager.ADJUST_RAISE) &&
+                !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
+            index = mStreamStates[streamType].getIndex(device,
+                                                 (streamState.muteCount() != 0)  /* lastAudible */);
             oldIndex = index;
         } else {
-            // If either the client forces allowing ringer modes for this adjustment,
-            // or the stream type is one that is affected by ringer modes
-            if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
-                    (streamTypeAlias == getMasterStreamType())) {
-                int ringerMode = getRingerMode();
-                // do not vibrate if already in vibrate mode
-                if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
-                    flags &= ~AudioManager.FLAG_VIBRATE;
-                }
-                // Check if the ringer mode changes with this volume adjustment. If
-                // it does, it will handle adjusting the volume, so we won't below
-                adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
-                if ((streamTypeAlias == getMasterStreamType()) &&
-                        (mRingerMode == AudioManager.RINGER_MODE_SILENT)) {
-                    streamState.setLastAudibleIndex(0, device);
-                }
-            }
-
-            // If stream is muted, adjust last audible index only
-            oldIndex = mStreamStates[streamType].getIndex(device,
-                    (mStreamStates[streamType].muteCount() != 0) /* lastAudible */);
-
-            if (streamState.muteCount() != 0) {
-                if (adjustVolume) {
-                    // Post a persist volume msg
-                    // no need to persist volume on all streams sharing the same alias
-                    streamState.adjustLastAudibleIndex(direction * step, device);
-                    sendMsg(mAudioHandler,
-                            MSG_PERSIST_VOLUME,
-                            SENDMSG_QUEUE,
-                            PERSIST_LAST_AUDIBLE,
-                            device,
-                            streamState,
-                            PERSIST_DELAY);
-                }
-                index = mStreamStates[streamType].getIndex(device, true  /* lastAudible */);
+            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
+            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
+                   ((device & mFixedVolumeDevices) != 0)) {
+                flags |= AudioManager.FLAG_FIXED_VOLUME;
+                index = mStreamStates[streamType].getMaxIndex();
+                oldIndex = index;
             } else {
-                if (adjustVolume && streamState.adjustIndex(direction * step, device)) {
-                    // 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_DEVICE_VOLUME,
-                            SENDMSG_QUEUE,
-                            device,
-                            0,
-                            streamState,
-                            0);
+                // If either the client forces allowing ringer modes for this adjustment,
+                // or the stream type is one that is affected by ringer modes
+                if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
+                        (streamTypeAlias == getMasterStreamType())) {
+                    int ringerMode = getRingerMode();
+                    // do not vibrate if already in vibrate mode
+                    if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
+                        flags &= ~AudioManager.FLAG_VIBRATE;
+                    }
+                    // Check if the ringer mode changes with this volume adjustment. If
+                    // it does, it will handle adjusting the volume, so we won't below
+                    adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
+                    if ((streamTypeAlias == getMasterStreamType()) &&
+                            (mRingerMode == AudioManager.RINGER_MODE_SILENT)) {
+                        streamState.setLastAudibleIndex(0, device);
+                    }
                 }
-                index = mStreamStates[streamType].getIndex(device, false  /* lastAudible */);
+
+                // If stream is muted, adjust last audible index only
+                oldIndex = mStreamStates[streamType].getIndex(device,
+                        (mStreamStates[streamType].muteCount() != 0) /* lastAudible */);
+
+                if (streamState.muteCount() != 0) {
+                    if (adjustVolume) {
+                        // Post a persist volume msg
+                        // no need to persist volume on all streams sharing the same alias
+                        streamState.adjustLastAudibleIndex(direction * step, device);
+                        sendMsg(mAudioHandler,
+                                MSG_PERSIST_VOLUME,
+                                SENDMSG_QUEUE,
+                                PERSIST_LAST_AUDIBLE,
+                                device,
+                                streamState,
+                                PERSIST_DELAY);
+                    }
+                    index = mStreamStates[streamType].getIndex(device, true  /* lastAudible */);
+                } else {
+                    if (adjustVolume && streamState.adjustIndex(direction * step, device)) {
+                        // 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_DEVICE_VOLUME,
+                                SENDMSG_QUEUE,
+                                device,
+                                0,
+                                streamState,
+                                0);
+                    }
+                    index = mStreamStates[streamType].getIndex(device, false  /* lastAudible */);
+                }
             }
         }
         sendVolumeUpdate(streamType, oldIndex, index, flags);
@@ -2306,13 +2315,31 @@
                         com.android.internal.R.integer.config_safe_media_volume_index) * 10;
                 boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean(
                         com.android.internal.R.bool.config_safe_media_volume_enabled);
+
+                // The persisted state is either "disabled" or "active": this is the state applied
+                // next time we boot and cannot be "inactive"
+                int persistedState;
                 if (safeMediaVolumeEnabled) {
-                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
-                    enforceSafeMediaVolume();
+                    persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
+                    // The state can already be "inactive" here if the user has forced it before
+                    // the 30 seconds timeout for forced configuration. In this case we don't reset
+                    // it to "active".
+                    if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
+                        mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
+                        enforceSafeMediaVolume();
+                    }
                 } else {
+                    persistedState = SAFE_MEDIA_VOLUME_DISABLED;
                     mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
                 }
                 mMcc = mcc;
+                sendMsg(mAudioHandler,
+                        MSG_PERSIST_SAFE_VOLUME_STATE,
+                        SENDMSG_QUEUE,
+                        persistedState,
+                        0,
+                        null,
+                        0);
             }
         }
     }
@@ -3224,6 +3251,12 @@
             AudioSystem.setForceUse(usage, config);
         }
 
+        private void onPersistSafeVolumeState(int state) {
+            Settings.Global.putInt(mContentResolver,
+                    Settings.Global.AUDIO_SAFE_VOLUME_STATE,
+                    state);
+        }
+
         @Override
         public void handleMessage(Message msg) {
 
@@ -3433,6 +3466,9 @@
                 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
                     onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
                     break;
+                case MSG_PERSIST_SAFE_VOLUME_STATE:
+                    onPersistSafeVolumeState(msg.arg1);
+                    break;
             }
         }
     }