CSD: Fixed volume not lowering to RS1

Fixed AppOps blocking the volume lowering and calling lower volume when
the SysUI lower volume button is clicked by the user.

Flag: NONE
Test: trigger CSD warnings and check that volume is lowered
Bug: 309861467
Change-Id: Ic91db26c87c5daed88b1d2a896713b3dbf1a443d
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 8584dbc..12ddf9b 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -303,7 +303,7 @@
 
     void disableSafeMediaVolume(String callingPackage);
 
-    void lowerVolumeToRs1(String callingPackage);
+    oneway void lowerVolumeToRs1(String callingPackage);
 
     @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
     float getOutputRs2UpperBound();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java b/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java
index eb0bf46..d6e6f3f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java
@@ -35,8 +35,8 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.messages.nano.SystemMessageProto;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.util.NotificationChannels;
 import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -46,7 +46,8 @@
 import dagger.assisted.AssistedInject;
 
 /**
- * A class that implements the four Computed Sound Dose-related warnings defined in {@link AudioManager}:
+ * A class that implements the three Computed Sound Dose-related warnings defined in
+ * {@link AudioManager}:
  * <ul>
  *     <li>{@link AudioManager#CSD_WARNING_DOSE_REACHED_1X}</li>
  *     <li>{@link AudioManager#CSD_WARNING_DOSE_REPEATED_5X}</li>
@@ -188,8 +189,8 @@
     public void onClick(DialogInterface dialog, int which) {
         if (which == DialogInterface.BUTTON_NEGATIVE) {
             Log.d(TAG, "Lower volume pressed for CSD warning " + mCsdWarning);
+            mAudioManager.lowerVolumeToRs1();
             dismiss();
-
         }
         if (D.BUG) Log.d(TAG, "on click " + which);
     }
@@ -216,10 +217,6 @@
 
     @Override
     public void onDismiss(DialogInterface unused) {
-        if (mCsdWarning == AudioManager.CSD_WARNING_DOSE_REPEATED_5X) {
-            // level is always reduced to RS1 beyond the 5x dose
-            mAudioManager.lowerVolumeToRs1();
-        }
         try {
             mContext.unregisterReceiver(mReceiver);
         } catch (IllegalArgumentException e) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index b209fb0..41655e2 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -16,8 +16,8 @@
 
 package com.android.server.audio;
 
-import static android.app.BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT;
 import static android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED;
+import static android.app.BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT;
 import static android.media.AudioDeviceInfo.TYPE_BLE_HEADSET;
 import static android.media.AudioDeviceInfo.TYPE_BLE_SPEAKER;
 import static android.media.AudioDeviceInfo.TYPE_BLUETOOTH_A2DP;
@@ -29,7 +29,6 @@
 import static android.media.AudioManager.RINGER_MODE_NORMAL;
 import static android.media.AudioManager.RINGER_MODE_SILENT;
 import static android.media.AudioManager.RINGER_MODE_VIBRATE;
-import static android.media.AudioManager.STREAM_MUSIC;
 import static android.media.AudioManager.STREAM_SYSTEM;
 import static android.os.Process.FIRST_APPLICATION_UID;
 import static android.os.Process.INVALID_UID;
@@ -409,7 +408,6 @@
     private static final int MSG_RESET_SPATIALIZER = 50;
     private static final int MSG_NO_LOG_FOR_PLAYER_I = 51;
     private static final int MSG_DISPATCH_PREFERRED_MIXER_ATTRIBUTES = 52;
-    private static final int MSG_LOWER_VOLUME_TO_RS1 = 53;
     private static final int MSG_CONFIGURATION_CHANGED = 54;
     private static final int MSG_BROADCAST_MASTER_MUTE = 55;
 
@@ -3534,7 +3532,7 @@
             return;
         }
 
-        mSoundDoseHelper.invalidatPendingVolumeCommand();
+        mSoundDoseHelper.invalidatePendingVolumeCommand();
 
         flags &= ~AudioManager.FLAG_FIXED_VOLUME;
         if (streamTypeAlias == AudioSystem.STREAM_MUSIC && isFixedVolumeDevice(device)) {
@@ -4605,7 +4603,7 @@
             return;
         }
 
-        mSoundDoseHelper.invalidatPendingVolumeCommand();
+        mSoundDoseHelper.invalidatePendingVolumeCommand();
 
         oldIndex = streamState.getIndex(device);
 
@@ -9542,10 +9540,6 @@
                     onDispatchPreferredMixerAttributesChanged(msg.getData(), msg.arg1);
                     break;
 
-                case MSG_LOWER_VOLUME_TO_RS1:
-                    onLowerVolumeToRs1();
-                    break;
-
                 case MSG_CONFIGURATION_CHANGED:
                     onConfigurationChanged();
                     break;
@@ -9560,6 +9554,7 @@
                 case SoundDoseHelper.MSG_PERSIST_MUSIC_ACTIVE_MS:
                 case SoundDoseHelper.MSG_PERSIST_CSD_VALUES:
                 case SoundDoseHelper.MSG_CSD_UPDATE_ATTENUATION:
+                case SoundDoseHelper.MSG_LOWER_VOLUME_TO_RS1:
                     mSoundDoseHelper.handleMessage(msg);
                     break;
 
@@ -10944,31 +10939,11 @@
     }
 
     /*package*/ void postLowerVolumeToRs1() {
-        sendMsg(mAudioHandler, MSG_LOWER_VOLUME_TO_RS1, SENDMSG_QUEUE,
+        sendMsg(mAudioHandler, SoundDoseHelper.MSG_LOWER_VOLUME_TO_RS1, SENDMSG_QUEUE,
                 // no params, no delay
                 0, 0, null, 0);
     }
 
-    /**
-     * Called when handling MSG_LOWER_VOLUME_TO_RS1
-     */
-    private void onLowerVolumeToRs1() {
-        final ArrayList<AudioDeviceAttributes> devices = getDevicesForAttributesInt(
-                new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(), true);
-        final int nativeDeviceType;
-        final AudioDeviceAttributes ada;
-        if (!devices.isEmpty()) {
-            ada = devices.get(0);
-            nativeDeviceType = ada.getInternalType();
-        } else {
-            nativeDeviceType = AudioSystem.DEVICE_OUT_USB_HEADSET;
-            ada = new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_USB_HEADSET, "");
-        }
-        final int index = mSoundDoseHelper.safeMediaVolumeIndex(nativeDeviceType);
-        setStreamVolumeWithAttributionInt(STREAM_MUSIC, index, /*flags*/ 0, ada,
-                "com.android.server.audio", "AudioService");
-    }
-
     @Override
     @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED)
     public float getOutputRs2UpperBound() {
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index aac868f..21a7d31 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -539,6 +539,8 @@
         static final int DOSE_UPDATE = 1;
         static final int DOSE_REPEAT_5X = 2;
         static final int DOSE_ACCUMULATION_START = 3;
+        static final int LOWER_VOLUME_TO_RS1 = 4;
+
         final int mEventType;
         final float mFloatValue;
         final long mLongValue;
@@ -565,6 +567,10 @@
             return new SoundDoseEvent(DOSE_ACCUMULATION_START, 0 /*ignored*/, 0 /*ignored*/);
         }
 
+        static SoundDoseEvent getLowerVolumeToRs1Event() {
+            return new SoundDoseEvent(LOWER_VOLUME_TO_RS1, 0 /*ignored*/, 0 /*ignored*/);
+        }
+
         @Override
         public String eventToString() {
             switch (mEventType) {
@@ -578,6 +584,8 @@
                     return "CSD reached 500%";
                 case DOSE_ACCUMULATION_START:
                     return "CSD accumulating: RS2 entered";
+                case LOWER_VOLUME_TO_RS1:
+                    return "CSD lowering volume to RS1";
             }
             return new StringBuilder("FIXME invalid event type:").append(mEventType).toString();
         }
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index d65c7c2c..793752f 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -18,6 +18,7 @@
 
 import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES;
 import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_UNKNOWN;
+import static android.media.AudioManager.STREAM_MUSIC;
 
 import static com.android.server.audio.AudioService.MAX_STREAM_VOLUME;
 import static com.android.server.audio.AudioService.MIN_STREAM_VOLUME;
@@ -31,6 +32,8 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.media.AudioAttributes;
+import android.media.AudioDeviceAttributes;
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.ISoundDose;
@@ -115,6 +118,9 @@
     /*package*/ static final int MSG_PERSIST_CSD_VALUES = SAFE_MEDIA_VOLUME_MSG_START + 5;
     /*package*/ static final int MSG_CSD_UPDATE_ATTENUATION = SAFE_MEDIA_VOLUME_MSG_START + 6;
 
+    /*package*/ static final int MSG_LOWER_VOLUME_TO_RS1 = SAFE_MEDIA_VOLUME_MSG_START + 7;
+
+
     private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
 
     private static final int MOMENTARY_EXPOSURE_TIMEOUT_MS = (20 * 3600 * 1000); // 20 hours
@@ -774,7 +780,7 @@
         return mSafeMediaVolumeDevices.get(device, SAFE_MEDIA_VOLUME_UNINITIALIZED) >= 0;
     }
 
-    /*package*/ void invalidatPendingVolumeCommand() {
+    /*package*/ void invalidatePendingVolumeCommand() {
         synchronized (mSafeMediaVolumeStateLock) {
             mPendingVolumeCommand = null;
         }
@@ -808,6 +814,9 @@
                 updateDoseAttenuation(streamState.getIndex(device), device,
                         streamState.getStreamType(), isAbsoluteVolume);
                 break;
+            case MSG_LOWER_VOLUME_TO_RS1:
+                onLowerVolumeToRs1();
+                break;
             default:
                 Log.e(TAG, "Unexpected msg to handle: " + msg.what);
                 break;
@@ -1272,6 +1281,25 @@
         return value;
     }
 
+    /** Called when handling MSG_LOWER_VOLUME_TO_RS1 */
+    private void onLowerVolumeToRs1() {
+        mLogger.enqueue(SoundDoseEvent.getLowerVolumeToRs1Event());
+        final ArrayList<AudioDeviceAttributes> devices = mAudioService.getDevicesForAttributesInt(
+                new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(), true);
+        final int nativeDeviceType;
+        final AudioDeviceAttributes ada;
+        if (!devices.isEmpty()) {
+            ada = devices.get(0);
+            nativeDeviceType = ada.getInternalType();
+        } else {
+            nativeDeviceType = AudioSystem.DEVICE_OUT_USB_HEADSET;
+            ada = new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_USB_HEADSET, "");
+        }
+        final int index = safeMediaVolumeIndex(nativeDeviceType);
+        mAudioService.setStreamVolumeWithAttributionInt(STREAM_MUSIC, index / 10, /*flags*/ 0, ada,
+                mContext.getOpPackageName(), /*attributionTag=*/null);
+    }
+
     // StreamVolumeCommand contains the information needed to defer the process of
     // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
     private static class StreamVolumeCommand {