diff options
author | John Spurlock <jspurlock@google.com> | 2014-11-17 10:29:10 -0500 |
---|---|---|
committer | John Spurlock <jspurlock@google.com> | 2014-11-25 13:20:46 -0500 |
commit | 661f2cf45860d2e10924e6b69966a9afe255f28b (patch) | |
tree | e7ad0a86244468b8df5efe81736e43c74b9126a9 /media/java | |
parent | fb6121e069f25dd43e15b1377fe4d5f60c3d0dbe (diff) | |
download | frameworks_base-661f2cf45860d2e10924e6b69966a9afe255f28b.zip frameworks_base-661f2cf45860d2e10924e6b69966a9afe255f28b.tar.gz frameworks_base-661f2cf45860d2e10924e6b69966a9afe255f28b.tar.bz2 |
VolumeZen: Introduce internal vs external ringer mode.
Stabilize mapping between ringer-mode=silent and zen=priority
by keeping track of two ringer modes:
- Internal ringer mode: Used for underlying stream muting
- External ringer mode: Reported to clients
The mapping between external ringer mode + zen is:
- normal = all
- vibrate = all
- silent = priority (read-write) or none (read)
Changes include:
- Remove "zen check" from audio service, back to audio
service having no knowledge of zen.
- Maintain a new external ringer mode in audio service,
this is the ringer mode reported through AudioManager
to callers, also mapped to the change intent.
- Introduce a "ringer mode delegate" to the local
audio manager interface, responsible for observing
external / internal mode changes, and making changes
if necessary.
- Internal ringer mode changes are still interesting
to the volume dialog, wire up a callback through
the existing IVolumeController interface.
- On devices without vibration, the mapping is the same
but since no ringer mode change is possible, disable
the icon toggle and remove the mute icon when volume=0.
- On devices with vibration, volume down presses should
pulse the vibrate icon (and vibrate) as a hint that this
is as low as the device can go using the keys. Since
the mechanics are similar to the existing zen=none hint,
pull into shared helper.
- Log ringer mode changes to the zen log, include calling
package information for issue diagnosis.
- Include whether vibration is supported in the audio service
dump.
- Update the status bar icon policy to use the internal ringer
mode, not the external mode (for vibrate icon).
- Update the "Muted by <x>" logic, include current suppressor
in dumpsys, ensure suppression icon is enabled & !clickable,
regardless of zen mode.
Bug: 17884168
Bug: 15471679
Bug: 16824970
Change-Id: Ia7d3bb23ce6d1e37b24fb6521d1c1ab9bb8f60c0
Diffstat (limited to 'media/java')
-rw-r--r-- | media/java/android/media/AudioManager.java | 81 | ||||
-rw-r--r-- | media/java/android/media/AudioManagerInternal.java | 16 | ||||
-rw-r--r-- | media/java/android/media/AudioService.java | 188 | ||||
-rw-r--r-- | media/java/android/media/IAudioService.aidl | 8 | ||||
-rw-r--r-- | media/java/android/media/IVolumeController.aidl | 2 |
5 files changed, 223 insertions, 72 deletions
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 3f08305..0642bcd 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -470,6 +470,49 @@ public class AudioManager { public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10; /** + * Adjusting the volume down from vibrated was prevented, display a hint in the UI. + * @hide + */ + public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11; + + private static final String[] FLAG_NAMES = { + "FLAG_SHOW_UI", + "FLAG_ALLOW_RINGER_MODES", + "FLAG_PLAY_SOUND", + "FLAG_REMOVE_SOUND_AND_VIBRATE", + "FLAG_VIBRATE", + "FLAG_FIXED_VOLUME", + "FLAG_BLUETOOTH_ABS_VOLUME", + "FLAG_SHOW_SILENT_HINT", + "FLAG_HDMI_SYSTEM_AUDIO_VOLUME", + "FLAG_ACTIVE_MEDIA_ONLY", + "FLAG_SHOW_UI_WARNINGS", + "FLAG_SHOW_VIBRATE_HINT", + }; + + /** @hide */ + public static String flagsToString(int flags) { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < FLAG_NAMES.length; i++) { + final int flag = 1 << i; + if ((flags & flag) != 0) { + if (sb.length() > 0) { + sb.append(','); + } + sb.append(FLAG_NAMES[i]); + flags &= ~flag; + } + } + if (flags != 0) { + if (sb.length() > 0) { + sb.append(','); + } + sb.append(flags); + } + return sb.toString(); + } + + /** * Ringer mode that will be silent and will not vibrate. (This overrides the * vibrate setting.) * @@ -857,7 +900,7 @@ public class AudioManager { public int getRingerMode() { IAudioService service = getService(); try { - return service.getRingerMode(); + return service.getRingerModeExternal(); } catch (RemoteException e) { Log.e(TAG, "Dead object in getRingerMode", e); return RINGER_MODE_NORMAL; @@ -977,21 +1020,12 @@ public class AudioManager { * @see #isVolumeFixed() */ public void setRingerMode(int ringerMode) { - setRingerMode(ringerMode, true /*checkZen*/); - } - - /** - * @see #setRingerMode(int) - * @param checkZen Update zen mode if necessary to compensate. - * @hide - */ - public void setRingerMode(int ringerMode, boolean checkZen) { if (!isValidRingerMode(ringerMode)) { return; } IAudioService service = getService(); try { - service.setRingerMode(ringerMode, checkZen); + service.setRingerModeExternal(ringerMode, mContext.getOpPackageName()); } catch (RemoteException e) { Log.e(TAG, "Dead object in setRingerMode", e); } @@ -3308,6 +3342,31 @@ public class AudioManager { } /** + * Only useful for volume controllers. + * @hide + */ + public void setRingerModeInternal(int ringerMode) { + try { + getService().setRingerModeInternal(ringerMode, mContext.getOpPackageName()); + } catch (RemoteException e) { + Log.w(TAG, "Error calling setRingerModeInternal", e); + } + } + + /** + * Only useful for volume controllers. + * @hide + */ + public int getRingerModeInternal() { + try { + return getService().getRingerModeInternal(); + } catch (RemoteException e) { + Log.w(TAG, "Error calling getRingerModeInternal", e); + return RINGER_MODE_NORMAL; + } + } + + /** * Set Hdmi Cec system audio mode. * * @param on whether to be on system audio mode diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java index a6cc493..d9586bc 100644 --- a/media/java/android/media/AudioManagerInternal.java +++ b/media/java/android/media/AudioManagerInternal.java @@ -38,4 +38,20 @@ public abstract class AudioManagerInternal { public abstract void adjustMasterVolumeForUid(int steps, int flags, String callingPackage, int uid); + + public abstract void setRingerModeDelegate(RingerModeDelegate delegate); + + public abstract int getRingerModeInternal(); + + public abstract void setRingerModeInternal(int ringerMode, String caller); + + 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); + + /** Called when internal ringer mode is evaluated, returns the new external ringer mode */ + int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller, + int ringerModeExternal); + } } diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index b6b24a4..0175fd4 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -66,7 +66,6 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.Vibrator; import android.provider.Settings; -import android.provider.Settings.Global; import android.provider.Settings.System; import android.telecom.TelecomManager; import android.text.TextUtils; @@ -375,7 +374,8 @@ public class AudioService extends IAudioService.Stub { * {@link AudioManager#RINGER_MODE_VIBRATE}. */ // protected by mSettingsLock - private int mRingerMode; + private int mRingerMode; // internal ringer mode, affects muting of underlying streams + private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager) /** @see System#MODE_RINGER_STREAMS_AFFECTED */ private int mRingerModeAffectedStreams = 0; @@ -532,6 +532,8 @@ public class AudioService extends IAudioService.Stub { private static Long mLastDeviceConnectMsgTime = new Long(0); + private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate; + /////////////////////////////////////////////////////////////////////////// // Construction /////////////////////////////////////////////////////////////////////////// @@ -619,7 +621,7 @@ public class AudioService extends IAudioService.Stub { // Call setRingerModeInt() to apply correct mute // state on streams affected by ringer mode. mRingerModeMutedStreams = 0; - setRingerModeInt(getRingerMode(), false); + setRingerModeInt(getRingerModeInternal(), false); // Register for device connection intent broadcasts. IntentFilter intentFilter = @@ -829,7 +831,7 @@ public class AudioService extends IAudioService.Stub { if (updateVolumes) { mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]); // apply stream mute states according to new value of mRingerModeAffectedStreams - setRingerModeInt(getRingerMode(), false); + setRingerModeInt(getRingerModeInternal(), false); sendMsg(mAudioHandler, MSG_SET_ALL_VOLUMES, SENDMSG_QUEUE, @@ -883,6 +885,9 @@ public class AudioService extends IAudioService.Stub { } synchronized(mSettingsLock) { mRingerMode = ringerMode; + if (mRingerModeExternal == -1) { + mRingerModeExternal = mRingerMode; + } // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting // are still needed while setVibrateSetting() and getVibrateSetting() are being @@ -1067,7 +1072,7 @@ public class AudioService extends IAudioService.Stub { // 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(); + int ringerMode = getRingerModeInternal(); // do not vibrate if already in vibrate mode if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { flags &= ~AudioManager.FLAG_VIBRATE; @@ -1080,6 +1085,10 @@ public class AudioService extends IAudioService.Stub { if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) { flags |= AudioManager.FLAG_SHOW_SILENT_HINT; } + // If suppressing a volume down adjustment in vibrate mode, display the UI hint + if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) { + flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT; + } } int oldIndex = mStreamStates[streamType].getIndex(device); @@ -1206,7 +1215,7 @@ public class AudioService extends IAudioService.Stub { } else { newRingerMode = AudioManager.RINGER_MODE_NORMAL; } - setRingerMode(newRingerMode, false /*checkZen*/); + setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/); } } @@ -1769,8 +1778,15 @@ public class AudioService extends IAudioService.Stub { : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY); } - /** @see AudioManager#getRingerMode() */ - public int getRingerMode() { + @Override + public int getRingerModeExternal() { + synchronized(mSettingsLock) { + return mRingerModeExternal; + } + } + + @Override + public int getRingerModeInternal() { synchronized(mSettingsLock) { return mRingerMode; } @@ -1787,36 +1803,57 @@ public class AudioService extends IAudioService.Stub { return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX; } - /** @see AudioManager#setRingerMode(int) */ - public void setRingerMode(int ringerMode, boolean checkZen) { + public void setRingerModeExternal(int ringerMode, String caller) { + setRingerMode(ringerMode, caller, true /*external*/); + } + + public void setRingerModeInternal(int ringerMode, String caller) { + enforceSelfOrSystemUI("setRingerModeInternal"); + setRingerMode(ringerMode, caller, false /*external*/); + } + + private void setRingerMode(int ringerMode, String caller, boolean external) { if (mUseFixedVolume || isPlatformTelevision()) { return; } + if (caller == null || caller.length() == 0) { + throw new IllegalArgumentException("Bad caller: " + caller); + } ensureValidRingerMode(ringerMode); if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) { ringerMode = AudioManager.RINGER_MODE_SILENT; } - if (checkZen) { - checkZen(ringerMode); - } - if (ringerMode != getRingerMode()) { - setRingerModeInt(ringerMode, true); - // Send sticky broadcast - broadcastRingerMode(ringerMode); + final int ringerModeInternal = getRingerModeInternal(); + final int ringerModeExternal = getRingerModeExternal(); + if (external) { + setRingerModeExt(ringerMode); + if (mRingerModeDelegate != null) { + ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal, + ringerMode, caller, ringerModeInternal); + } + if (ringerMode != ringerModeInternal) { + setRingerModeInt(ringerMode, true /*persist*/); + } + } else /*internal*/ { + if (ringerMode != ringerModeInternal) { + setRingerModeInt(ringerMode, true /*persist*/); + mVolumeController.postInternalRingerModeChanged(ringerMode); + } + if (mRingerModeDelegate != null) { + ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal, + ringerMode, caller, ringerModeExternal); + } + setRingerModeExt(ringerMode); } } - private void checkZen(int ringerMode) { - // leave zen when callers set ringer-mode = normal or vibrate - final int zen = Global.getInt(mContentResolver, Global.ZEN_MODE, Global.ZEN_MODE_OFF); - if (ringerMode != AudioManager.RINGER_MODE_SILENT && zen != Global.ZEN_MODE_OFF) { - final long ident = Binder.clearCallingIdentity(); - try { - Global.putInt(mContentResolver, Global.ZEN_MODE, Global.ZEN_MODE_OFF); - } finally { - Binder.restoreCallingIdentity(ident); - } + private void setRingerModeExt(int ringerMode) { + synchronized(mSettingsLock) { + if (ringerMode == mRingerModeExternal) return; + mRingerModeExternal = ringerMode; } + // Send sticky broadcast + broadcastRingerMode(ringerMode); } private void setRingerModeInt(int ringerMode, boolean persist) { @@ -1829,34 +1866,35 @@ public class AudioService extends IAudioService.Stub { // 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(); + final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE + || ringerMode == AudioManager.RINGER_MODE_SILENT; for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { - if (isStreamMutedByRingerMode(streamType)) { - if (!isStreamAffectedByRingerMode(streamType) || - ringerMode == AudioManager.RINGER_MODE_NORMAL) { - // ring and notifications volume should never be 0 when not silenced - // on voice capable devices or devices that support vibration - if ((isPlatformVoice() || mHasVibrator) && - mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { - synchronized (VolumeStreamState.class) { - Set set = mStreamStates[streamType].mIndex.entrySet(); - Iterator i = set.iterator(); - while (i.hasNext()) { - Map.Entry entry = (Map.Entry)i.next(); - if ((Integer)entry.getValue() == 0) { - entry.setValue(10); - } + final boolean isMuted = isStreamMutedByRingerMode(streamType); + final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType); + if (isMuted == shouldMute) continue; + if (!shouldMute) { + // unmute + // ring and notifications volume should never be 0 when not silenced + // on voice capable devices or devices that support vibration + if ((isPlatformVoice() || mHasVibrator) && + mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { + synchronized (VolumeStreamState.class) { + Set set = mStreamStates[streamType].mIndex.entrySet(); + Iterator i = set.iterator(); + while (i.hasNext()) { + Map.Entry entry = (Map.Entry)i.next(); + if ((Integer)entry.getValue() == 0) { + entry.setValue(10); } } } - mStreamStates[streamType].mute(null, false); - mRingerModeMutedStreams &= ~(1 << streamType); } + mStreamStates[streamType].mute(null, false); + mRingerModeMutedStreams &= ~(1 << streamType); } else { - if (isStreamAffectedByRingerMode(streamType) && - ringerMode != AudioManager.RINGER_MODE_NORMAL) { - mStreamStates[streamType].mute(null, true); - mRingerModeMutedStreams |= (1 << streamType); - } + // mute + mStreamStates[streamType].mute(null, true); + mRingerModeMutedStreams |= (1 << streamType); } } @@ -1888,10 +1926,10 @@ public class AudioService extends IAudioService.Stub { switch (getVibrateSetting(vibrateType)) { case AudioManager.VIBRATE_SETTING_ON: - return getRingerMode() != AudioManager.RINGER_MODE_SILENT; + return getRingerModeInternal() != AudioManager.RINGER_MODE_SILENT; case AudioManager.VIBRATE_SETTING_ONLY_SILENT: - return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE; + return getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE; case AudioManager.VIBRATE_SETTING_OFF: // return false, even for incoming calls @@ -2352,7 +2390,7 @@ public class AudioService extends IAudioService.Stub { // apply new ringer mode before checking volume for alias streams so that streams // muted by ringer mode have the correct volume - setRingerModeInt(getRingerMode(), false); + setRingerModeInt(getRingerModeInternal(), false); checkAllFixedVolumeDevices(); checkAllAliasStreamVolumes(); @@ -3003,7 +3041,7 @@ public class AudioService extends IAudioService.Stub { */ private int checkForRingerModeChange(int oldIndex, int direction, int step) { int result = FLAG_ADJUST_VOLUME; - int ringerMode = getRingerMode(); + int ringerMode = getRingerModeInternal(); switch (ringerMode) { case RINGER_MODE_NORMAL: @@ -3037,6 +3075,8 @@ public class AudioService extends IAudioService.Stub { if (VOLUME_SETS_RINGER_MODE_SILENT && mPrevVolDirection != AudioManager.ADJUST_LOWER) { ringerMode = RINGER_MODE_SILENT; + } else { + result |= AudioManager.FLAG_SHOW_VIBRATE_HINT; } } else if (direction == AudioManager.ADJUST_RAISE) { ringerMode = RINGER_MODE_NORMAL; @@ -3062,7 +3102,7 @@ public class AudioService extends IAudioService.Stub { break; } - setRingerMode(ringerMode, false /*checkZen*/); + setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/); mPrevVolDirection = direction; @@ -4136,7 +4176,7 @@ public class AudioService extends IAudioService.Stub { case MSG_PERSIST_RINGER_MODE: // note that the value persisted is the current ringer mode, not the // value of ringer mode as of the time the request was made to persist - persistRingerMode(getRingerMode()); + persistRingerMode(getRingerModeInternal()); break; case MSG_MEDIA_SERVER_DIED: @@ -4188,7 +4228,7 @@ public class AudioService extends IAudioService.Stub { } // Restore ringer mode - setRingerModeInt(getRingerMode(), false); + setRingerModeInt(getRingerModeInternal(), false); // Restore master volume restoreMasterVolume(); @@ -4358,7 +4398,7 @@ public class AudioService extends IAudioService.Stub { * Ensure all stream types that should be affected by ringer mode * are in the proper state. */ - setRingerModeInt(getRingerMode(), false); + setRingerModeInt(getRingerModeInternal(), false); } readDockAudioSettings(mContentResolver); } @@ -5110,7 +5150,7 @@ public class AudioService extends IAudioService.Stub { (1 << AudioSystem.STREAM_SYSTEM_ENFORCED); } // take new state into account for streams muted by ringer mode - setRingerModeInt(getRingerMode(), false); + setRingerModeInt(getRingerModeInternal(), false); } sendMsg(mAudioHandler, @@ -5451,11 +5491,13 @@ public class AudioService extends IAudioService.Stub { private void dumpRingerMode(PrintWriter pw) { pw.println("\nRinger mode: "); - pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]); + pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]); + pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]); pw.print("- ringer mode affected streams = 0x"); pw.println(Integer.toHexString(mRingerModeAffectedStreams)); pw.print("- ringer mode muted streams = 0x"); pw.println(Integer.toHexString(mRingerModeMutedStreams)); + pw.print("- delegate = "); pw.println(mRingerModeDelegate); } @Override @@ -5477,6 +5519,7 @@ public class AudioService extends IAudioService.Stub { pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand); pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs); pw.print(" mMcc="); pw.println(mMcc); + pw.print(" mHasVibrator="); pw.println(mHasVibrator); } private static String safeMediaVolumeStateToString(Integer state) { @@ -5668,6 +5711,16 @@ public class AudioService extends IAudioService.Stub { Log.w(TAG, "Error calling dismiss", e); } } + + public void postInternalRingerModeChanged(int mode) { + if (mController == null) + return; + try { + mController.internalRingerModeChanged(mode); + } catch (RemoteException e) { + Log.w(TAG, "Error calling internalRingerModeChanged", e); + } + } } /** @@ -5675,6 +5728,13 @@ public class AudioService extends IAudioService.Stub { * LocalServices. */ final class AudioServiceInternal extends AudioManagerInternal { + @Override + public void setRingerModeDelegate(RingerModeDelegate delegate) { + mRingerModeDelegate = delegate; + if (mRingerModeDelegate != null) { + setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate"); + } + } @Override public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags, @@ -5701,6 +5761,16 @@ public class AudioService extends IAudioService.Stub { int uid) { adjustMasterVolume(steps, flags, callingPackage, uid); } + + @Override + public int getRingerModeInternal() { + return AudioService.this.getRingerModeInternal(); + } + + @Override + public void setRingerModeInternal(int ringerMode, String caller) { + AudioService.this.setRingerModeInternal(ringerMode, caller); + } } //========================================================================================== diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index b691447..4d8aa76 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -77,9 +77,13 @@ interface IAudioService { void setMicrophoneMute(boolean on, String callingPackage); - void setRingerMode(int ringerMode, boolean checkZen); + void setRingerModeExternal(int ringerMode, String caller); - int getRingerMode(); + void setRingerModeInternal(int ringerMode, String caller); + + int getRingerModeExternal(); + + int getRingerModeInternal(); boolean isValidRingerMode(int ringerMode); diff --git a/media/java/android/media/IVolumeController.aidl b/media/java/android/media/IVolumeController.aidl index e3593a6..c31d80c 100644 --- a/media/java/android/media/IVolumeController.aidl +++ b/media/java/android/media/IVolumeController.aidl @@ -34,4 +34,6 @@ oneway interface IVolumeController { void setLayoutDirection(int layoutDirection); void dismiss(); + + void internalRingerModeChanged(int mode); } |