OSDN Git Service

Volume policy updates.
authorJohn Spurlock <jspurlock@google.com>
Tue, 3 Mar 2015 22:35:57 +0000 (17:35 -0500)
committerJohn Spurlock <jspurlock@google.com>
Thu, 12 Mar 2015 17:57:08 +0000 (13:57 -0400)
 - Make volume policy settable by the volume UI instead
   of hardcoded in AudioService.
 - Add status bar icon for silent mode.
 - Limit unmute-on-volume-adjust behavior to tvs.
 - Ensure all changes to device volume are sent through
   setIndex so no change events are missed.

Bug: 19260237
Change-Id: Iea070a7a6f90ff620e39629f2da3f33f87223d72

media/java/android/media/AudioManager.java
media/java/android/media/AudioManagerInternal.java
media/java/android/media/IAudioService.aidl
media/java/android/media/VolumePolicy.aidl [new file with mode: 0644]
media/java/android/media/VolumePolicy.java [new file with mode: 0644]
packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
services/core/java/com/android/server/audio/AudioService.java
services/core/java/com/android/server/notification/ZenModeHelper.java

index db67fbf..3fc3646 100644 (file)
@@ -3214,6 +3214,18 @@ public class AudioManager {
     }
 
     /**
+     * Only useful for volume controllers.
+     * @hide
+     */
+    public void setVolumePolicy(VolumePolicy policy) {
+        try {
+            getService().setVolumePolicy(policy);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Error calling setVolumePolicy", e);
+        }
+    }
+
+    /**
      * Set Hdmi Cec system audio mode.
      *
      * @param on whether to be on system audio mode
index d456b7e..abb4257 100644 (file)
@@ -46,10 +46,10 @@ public abstract class AudioManagerInternal {
     public interface RingerModeDelegate {
         /** Called when external ringer mode is evaluated, returns the new internal ringer mode */
         int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
-                int ringerModeInternal);
+                int ringerModeInternal, VolumePolicy policy);
 
         /** Called when internal ringer mode is evaluated, returns the new external ringer mode */
         int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
-                int ringerModeExternal);
+                int ringerModeExternal, VolumePolicy policy);
     }
 }
index 2e8e017..827cb13 100644 (file)
@@ -29,6 +29,7 @@ import android.media.IRemoteVolumeObserver;
 import android.media.IRingtonePlayer;
 import android.media.IVolumeController;
 import android.media.Rating;
+import android.media.VolumePolicy;
 import android.media.audiopolicy.AudioPolicyConfig;
 import android.media.audiopolicy.IAudioPolicyCallback;
 import android.net.Uri;
@@ -204,9 +205,12 @@ interface IAudioService {
 
     boolean isHdmiSystemAudioSupported();
 
-           String registerAudioPolicy(in AudioPolicyConfig policyConfig,
-                    in IAudioPolicyCallback pcb, boolean hasFocusListener);
+    String registerAudioPolicy(in AudioPolicyConfig policyConfig,
+            in IAudioPolicyCallback pcb, boolean hasFocusListener);
+
     oneway void unregisterAudioPolicyAsync(in IAudioPolicyCallback pcb);
 
-           int setFocusPropertiesForPolicy(int duckingBehavior, in IAudioPolicyCallback pcb);
+    int setFocusPropertiesForPolicy(int duckingBehavior, in IAudioPolicyCallback pcb);
+
+    void setVolumePolicy(in VolumePolicy policy);
 }
diff --git a/media/java/android/media/VolumePolicy.aidl b/media/java/android/media/VolumePolicy.aidl
new file mode 100644 (file)
index 0000000..371f798
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+parcelable VolumePolicy;
diff --git a/media/java/android/media/VolumePolicy.java b/media/java/android/media/VolumePolicy.java
new file mode 100644 (file)
index 0000000..677a0ef
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public final class VolumePolicy implements Parcelable {
+    public static final VolumePolicy DEFAULT = new VolumePolicy(false, false, true);
+
+    public final boolean volumeDownToEnterSilent;
+    public final boolean volumeUpToExitSilent;
+    public final boolean doNotDisturbWhenSilent;
+
+    public VolumePolicy(boolean volumeDownToEnterSilent, boolean volumeUpToExitSilent,
+            boolean doNotDisturbWhenSilent) {
+        this.volumeDownToEnterSilent = volumeDownToEnterSilent;
+        this.volumeUpToExitSilent = volumeUpToExitSilent;
+        this.doNotDisturbWhenSilent = doNotDisturbWhenSilent;
+    }
+
+    @Override
+    public String toString() {
+        return "VolumePolicy[volumeDownToEnterSilent=" + volumeDownToEnterSilent
+                + ",volumeUpToExitSilent=" + volumeUpToExitSilent
+                + ",doNotDisturbWhenSilent=" + doNotDisturbWhenSilent + "]";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(volumeDownToEnterSilent ? 1 : 0);
+        dest.writeInt(volumeUpToExitSilent ? 1 : 0);
+        dest.writeInt(doNotDisturbWhenSilent ? 1 : 0);
+    }
+
+    public static final Parcelable.Creator<VolumePolicy> CREATOR
+            = new Parcelable.Creator<VolumePolicy>() {
+        @Override
+        public VolumePolicy createFromParcel(Parcel p) {
+            return new VolumePolicy(p.readInt() != 0, p.readInt() != 0, p.readInt() != 0);
+        }
+
+        @Override
+        public VolumePolicy[] newArray(int size) {
+            return new VolumePolicy[size];
+        }
+    };
+}
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
new file mode 100644 (file)
index 0000000..36e6cef
--- /dev/null
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+        android:insetLeft="3dp"
+        android:insetRight="3dp">
+    <vector android:width="18dp"
+            android:height="18dp"
+            android:viewportWidth="48.0"
+            android:viewportHeight="48.0">
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M23.000000,44.000000c2.200000,0.000000 4.000000,-1.800000 4.000000,-4.000000l-8.000000,0.000000C19.000000,42.200001 20.799999,44.000000 23.000000,44.000000zM36.000000,21.000000c0.000000,-6.100000 -4.300000,-11.300000 -10.000000,-12.600000L26.000000,7.000000c0.000000,-1.700000 -1.300000,-3.000000 -3.000000,-3.000000c-1.700000,0.000000 -3.000000,1.300000 -3.000000,3.000000l0.000000,1.400000c-1.000000,0.200000 -2.000000,0.600000 -2.900000,1.100000L36.000000,28.400000L36.000000,21.000000zM35.500000,38.000000l4.000000,4.000000l2.500000,-2.500000L8.500000,6.000000L6.000000,8.500000l5.800000,5.800000C10.700000,16.299999 10.000000,18.600000 10.000000,21.000000l0.000000,11.000000l-4.000000,4.000000l0.000000,2.000000L35.500000,38.000000z"/>
+    </vector>
+</inset>
index 5da8457..2236aae 100644 (file)
@@ -213,7 +213,12 @@ public class PhoneStatusBarPolicy {
             zenDescription = mContext.getString(R.string.zen_important_interruptions);
         }
 
-        if (mZen != Global.ZEN_MODE_NO_INTERRUPTIONS &&
+        if (DndTile.isVisible(mContext)
+                && audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) {
+            volumeVisible = true;
+            volumeIconId = R.drawable.stat_sys_ringer_silent;
+            volumeDescription = mContext.getString(R.string.accessibility_ringer_silent);
+        } else if (mZen != Global.ZEN_MODE_NO_INTERRUPTIONS &&
                 audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
             volumeVisible = true;
             volumeIconId = R.drawable.stat_sys_ringer_vibrate;
index 7603c7d..687452d 100644 (file)
@@ -31,6 +31,7 @@ import android.content.res.Configuration;
 import android.media.AudioManager;
 import android.media.IRemoteVolumeController;
 import android.media.IVolumeController;
+import android.media.VolumePolicy;
 import android.media.session.ISessionController;
 import android.media.session.MediaController;
 import android.media.session.MediaSessionManager;
@@ -114,6 +115,7 @@ public class VolumeUI extends SystemUI {
         if (register) {
             if (LOGD) Log.d(TAG, "Registering default volume controller");
             mAudioManager.setVolumeController(mVolumeController);
+            mAudioManager.setVolumePolicy(VolumePolicy.DEFAULT);
             mMediaSessionManager.setRemoteVolumeController(mRemoteVolumeController);
             DndTile.setVisible(mContext, false);
         } else {
index 1208c04..bd3175f 100644 (file)
@@ -62,6 +62,7 @@ import android.media.IRingtonePlayer;
 import android.media.IVolumeController;
 import android.media.MediaPlayer;
 import android.media.SoundPool;
+import android.media.VolumePolicy;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
 import android.media.audiopolicy.AudioPolicy;
@@ -145,12 +146,6 @@ public class AudioService extends IAudioService.Stub {
     /** debug calls to devices APIs */
     protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
 
-    /** Allow volume changes to set ringer mode to silent? */
-    private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
-
-    /** In silent mode, are volume adjustments (raises) prevented? */
-    private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
-
     /** How long to delay before persisting a change in volume/ringer mode. */
     private static final int PERSIST_DELAY = 500;
 
@@ -534,6 +529,7 @@ public class AudioService extends IAudioService.Stub {
     private static Long mLastDeviceConnectMsgTime = new Long(0);
 
     private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
+    private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
 
     // Intent "extra" data keys.
     public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
@@ -1133,8 +1129,10 @@ public class AudioService extends IAudioService.Stub {
                         // unmute immediately for volume up
                         streamState.mute(false);
                     } else if (direction == AudioManager.ADJUST_LOWER) {
-                        sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
-                                streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
+                        if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
+                            sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
+                                    streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
+                        }
                     }
                 }
                 sendMsg(mAudioHandler,
@@ -1234,7 +1232,7 @@ public class AudioService extends IAudioService.Stub {
             int newRingerMode;
             if (index == 0) {
                 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
-                        : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
+                        : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
                         : AudioManager.RINGER_MODE_NORMAL;
             } else {
                 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
@@ -1730,7 +1728,7 @@ public class AudioService extends IAudioService.Stub {
                     setRingerModeExt(ringerMode);
                     if (mRingerModeDelegate != null) {
                         ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
-                                ringerMode, caller, ringerModeInternal);
+                                ringerMode, caller, ringerModeInternal, mVolumePolicy);
                     }
                     if (ringerMode != ringerModeInternal) {
                         setRingerModeInt(ringerMode, true /*persist*/);
@@ -1741,7 +1739,7 @@ public class AudioService extends IAudioService.Stub {
                     }
                     if (mRingerModeDelegate != null) {
                         ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
-                                ringerMode, caller, ringerModeExternal);
+                                ringerMode, caller, ringerModeExternal, mVolumePolicy);
                     }
                     setRingerModeExt(ringerMode);
                 }
@@ -1785,12 +1783,12 @@ public class AudioService extends IAudioService.Stub {
                 if ((isPlatformVoice() || mHasVibrator) &&
                         mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
                     synchronized (VolumeStreamState.class) {
-                        SparseIntArray indexMap = mStreamStates[streamType].mIndexMap;
-                        for (int i = 0; i < indexMap.size(); i++) {
-                            int device = indexMap.keyAt(i);
-                            int value = indexMap.valueAt(i);
+                        final VolumeStreamState vss = mStreamStates[streamType];
+                        for (int i = 0; i < vss.mIndexMap.size(); i++) {
+                            int device = vss.mIndexMap.keyAt(i);
+                            int value = vss.mIndexMap.valueAt(i);
                             if (value == 0) {
-                                indexMap.put(device, 10);
+                                vss.setIndex(10, device, TAG);
                             }
                         }
                         // Persist volume for stream ring when it is changed here
@@ -2933,7 +2931,8 @@ public class AudioService extends IAudioService.Stub {
      * adjusting volume. If so, this will set the proper ringer mode and volume
      * indices on the stream states.
      */
-    private int checkForRingerModeChange(int oldIndex, int direction,  int step, boolean isMuted) {
+    private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
+        final boolean isTv = mPlatformType == AudioSystem.PLATFORM_TELEVISION;
         int result = FLAG_ADJUST_VOLUME;
         int ringerMode = getRingerModeInternal();
 
@@ -2952,13 +2951,13 @@ public class AudioService extends IAudioService.Stub {
                 } else {
                     // (oldIndex < step) is equivalent to (old UI index == 0)
                     if ((oldIndex < step)
-                            && VOLUME_SETS_RINGER_MODE_SILENT
+                            && mVolumePolicy.volumeDownToEnterSilent
                             && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
                         ringerMode = RINGER_MODE_SILENT;
                     }
                 }
-            } else if (direction == AudioManager.ADJUST_TOGGLE_MUTE
-                    || direction == AudioManager.ADJUST_MUTE) {
+            } else if (isTv && (direction == AudioManager.ADJUST_TOGGLE_MUTE
+                    || direction == AudioManager.ADJUST_MUTE)) {
                 if (mHasVibrator) {
                     ringerMode = RINGER_MODE_VIBRATE;
                 } else {
@@ -2976,10 +2975,10 @@ public class AudioService extends IAudioService.Stub {
             }
             if ((direction == AudioManager.ADJUST_LOWER)) {
                 // This is the case we were muted with the volume turned up
-                if (oldIndex >= 2 * step && isMuted) {
+                if (isTv && oldIndex >= 2 * step && isMuted) {
                     ringerMode = RINGER_MODE_NORMAL;
                 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
-                    if (VOLUME_SETS_RINGER_MODE_SILENT) {
+                    if (mVolumePolicy.volumeDownToEnterSilent) {
                         ringerMode = RINGER_MODE_SILENT;
                     } else {
                         result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
@@ -2993,13 +2992,13 @@ public class AudioService extends IAudioService.Stub {
             result &= ~FLAG_ADJUST_VOLUME;
             break;
         case RINGER_MODE_SILENT:
-            if (direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
+            if (isTv && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
                 // This is the case we were muted with the volume turned up
                 ringerMode = RINGER_MODE_NORMAL;
             } else if (direction == AudioManager.ADJUST_RAISE
                     || direction == AudioManager.ADJUST_TOGGLE_MUTE
                     || direction == AudioManager.ADJUST_UNMUTE) {
-                if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
+                if (!mVolumePolicy.volumeUpToExitSilent) {
                     result |= AudioManager.FLAG_SHOW_SILENT_HINT;
                 } else {
                   if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
@@ -5418,6 +5417,7 @@ public class AudioService extends IAudioService.Stub {
         pw.print("  mCameraSoundForced="); pw.println(mCameraSoundForced);
         pw.print("  mHasVibrator="); pw.println(mHasVibrator);
         pw.print("  mControllerService="); pw.println(mControllerService);
+        pw.print("  mVolumePolicy="); pw.println(mVolumePolicy);
 
         dumpAudioPolicies(pw);
     }
@@ -5493,6 +5493,14 @@ public class AudioService extends IAudioService.Stub {
         if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
     }
 
+    @Override
+    public void setVolumePolicy(VolumePolicy policy) {
+        enforceVolumeController("set volume policy");
+        if (policy != null) {
+            mVolumePolicy = policy;
+        }
+    }
+
     public static class VolumeController {
         private static final String TAG = "VolumeController";
 
index 841fc21..a985b01 100644 (file)
@@ -31,6 +31,7 @@ import android.database.ContentObserver;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
+import android.media.VolumePolicy;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -334,7 +335,7 @@ public class ZenModeHelper implements AudioManagerInternal.RingerModeDelegate {
 
     @Override  // RingerModeDelegate
     public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
-            int ringerModeExternal) {
+            int ringerModeExternal, VolumePolicy policy) {
         final boolean isChange = ringerModeOld != ringerModeNew;
 
         int ringerModeExternalOut = ringerModeNew;
@@ -342,7 +343,7 @@ public class ZenModeHelper implements AudioManagerInternal.RingerModeDelegate {
         int newZen = -1;
         switch (ringerModeNew) {
             case AudioManager.RINGER_MODE_SILENT:
-                if (isChange) {
+                if (isChange && policy.doNotDisturbWhenSilent) {
                     if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS) {
                         newZen = Global.ZEN_MODE_NO_INTERRUPTIONS;
                     }
@@ -371,7 +372,7 @@ public class ZenModeHelper implements AudioManagerInternal.RingerModeDelegate {
 
     @Override  // RingerModeDelegate
     public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
-            int ringerModeInternal) {
+            int ringerModeInternal, VolumePolicy policy) {
         int ringerModeInternalOut = ringerModeNew;
         final boolean isChange = ringerModeOld != ringerModeNew;
         final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;