am bc6f59a1: Merge "VolumeZen: Introduce internal vs external ringer mode." into lmp-mr1-dev

* commit 'bc6f59a1ef341231c2b57e0cde691be1a5a32203':
  VolumeZen: Introduce internal vs external ringer mode.
This commit is contained in:
John Spurlock
2014-11-25 18:45:23 +00:00
committed by Android Git Automerger
15 changed files with 582 additions and 237 deletions

View File

@ -469,6 +469,49 @@ public class AudioManager {
*/ */
public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10; 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 * Ringer mode that will be silent and will not vibrate. (This overrides the
* vibrate setting.) * vibrate setting.)
@ -857,7 +900,7 @@ public class AudioManager {
public int getRingerMode() { public int getRingerMode() {
IAudioService service = getService(); IAudioService service = getService();
try { try {
return service.getRingerMode(); return service.getRingerModeExternal();
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Dead object in getRingerMode", e); Log.e(TAG, "Dead object in getRingerMode", e);
return RINGER_MODE_NORMAL; return RINGER_MODE_NORMAL;
@ -977,21 +1020,12 @@ public class AudioManager {
* @see #isVolumeFixed() * @see #isVolumeFixed()
*/ */
public void setRingerMode(int ringerMode) { 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)) { if (!isValidRingerMode(ringerMode)) {
return; return;
} }
IAudioService service = getService(); IAudioService service = getService();
try { try {
service.setRingerMode(ringerMode, checkZen); service.setRingerModeExternal(ringerMode, mContext.getOpPackageName());
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Dead object in setRingerMode", e); Log.e(TAG, "Dead object in setRingerMode", e);
} }
@ -3307,6 +3341,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. * Set Hdmi Cec system audio mode.
* *

View File

@ -38,4 +38,20 @@ public abstract class AudioManagerInternal {
public abstract void adjustMasterVolumeForUid(int steps, int flags, String callingPackage, public abstract void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
int uid); 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);
}
} }

View File

@ -66,7 +66,6 @@ import android.os.SystemProperties;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.Vibrator; import android.os.Vibrator;
import android.provider.Settings; import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.System; import android.provider.Settings.System;
import android.telecom.TelecomManager; import android.telecom.TelecomManager;
import android.text.TextUtils; import android.text.TextUtils;
@ -375,7 +374,8 @@ public class AudioService extends IAudioService.Stub {
* {@link AudioManager#RINGER_MODE_VIBRATE}. * {@link AudioManager#RINGER_MODE_VIBRATE}.
*/ */
// protected by mSettingsLock // 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 */ /** @see System#MODE_RINGER_STREAMS_AFFECTED */
private int mRingerModeAffectedStreams = 0; private int mRingerModeAffectedStreams = 0;
@ -532,6 +532,8 @@ public class AudioService extends IAudioService.Stub {
private static Long mLastDeviceConnectMsgTime = new Long(0); private static Long mLastDeviceConnectMsgTime = new Long(0);
private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Construction // Construction
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -619,7 +621,7 @@ public class AudioService extends IAudioService.Stub {
// Call setRingerModeInt() to apply correct mute // Call setRingerModeInt() to apply correct mute
// state on streams affected by ringer mode. // state on streams affected by ringer mode.
mRingerModeMutedStreams = 0; mRingerModeMutedStreams = 0;
setRingerModeInt(getRingerMode(), false); setRingerModeInt(getRingerModeInternal(), false);
// Register for device connection intent broadcasts. // Register for device connection intent broadcasts.
IntentFilter intentFilter = IntentFilter intentFilter =
@ -829,7 +831,7 @@ public class AudioService extends IAudioService.Stub {
if (updateVolumes) { if (updateVolumes) {
mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]); mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
// apply stream mute states according to new value of mRingerModeAffectedStreams // apply stream mute states according to new value of mRingerModeAffectedStreams
setRingerModeInt(getRingerMode(), false); setRingerModeInt(getRingerModeInternal(), false);
sendMsg(mAudioHandler, sendMsg(mAudioHandler,
MSG_SET_ALL_VOLUMES, MSG_SET_ALL_VOLUMES,
SENDMSG_QUEUE, SENDMSG_QUEUE,
@ -883,6 +885,9 @@ public class AudioService extends IAudioService.Stub {
} }
synchronized(mSettingsLock) { synchronized(mSettingsLock) {
mRingerMode = ringerMode; mRingerMode = ringerMode;
if (mRingerModeExternal == -1) {
mRingerModeExternal = mRingerMode;
}
// System.VIBRATE_ON is not used any more but defaults for mVibrateSetting // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
// are still needed while setVibrateSetting() and getVibrateSetting() are being // 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 // or the stream type is one that is affected by ringer modes
if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
(streamTypeAlias == getMasterStreamType())) { (streamTypeAlias == getMasterStreamType())) {
int ringerMode = getRingerMode(); int ringerMode = getRingerModeInternal();
// do not vibrate if already in vibrate mode // do not vibrate if already in vibrate mode
if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
flags &= ~AudioManager.FLAG_VIBRATE; flags &= ~AudioManager.FLAG_VIBRATE;
@ -1080,6 +1085,10 @@ public class AudioService extends IAudioService.Stub {
if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) { if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
flags |= AudioManager.FLAG_SHOW_SILENT_HINT; 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); int oldIndex = mStreamStates[streamType].getIndex(device);
@ -1206,7 +1215,7 @@ public class AudioService extends IAudioService.Stub {
} else { } else {
newRingerMode = AudioManager.RINGER_MODE_NORMAL; 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); : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
} }
/** @see AudioManager#getRingerMode() */ @Override
public int getRingerMode() { public int getRingerModeExternal() {
synchronized(mSettingsLock) {
return mRingerModeExternal;
}
}
@Override
public int getRingerModeInternal() {
synchronized(mSettingsLock) { synchronized(mSettingsLock) {
return mRingerMode; return mRingerMode;
} }
@ -1787,36 +1803,57 @@ public class AudioService extends IAudioService.Stub {
return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX; return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
} }
/** @see AudioManager#setRingerMode(int) */ public void setRingerModeExternal(int ringerMode, String caller) {
public void setRingerMode(int ringerMode, boolean checkZen) { 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()) { if (mUseFixedVolume || isPlatformTelevision()) {
return; return;
} }
if (caller == null || caller.length() == 0) {
throw new IllegalArgumentException("Bad caller: " + caller);
}
ensureValidRingerMode(ringerMode); ensureValidRingerMode(ringerMode);
if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) { if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
ringerMode = AudioManager.RINGER_MODE_SILENT; ringerMode = AudioManager.RINGER_MODE_SILENT;
} }
if (checkZen) { final int ringerModeInternal = getRingerModeInternal();
checkZen(ringerMode); final int ringerModeExternal = getRingerModeExternal();
} if (external) {
if (ringerMode != getRingerMode()) { setRingerModeExt(ringerMode);
setRingerModeInt(ringerMode, true); if (mRingerModeDelegate != null) {
// Send sticky broadcast ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
broadcastRingerMode(ringerMode); 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) { private void setRingerModeExt(int ringerMode) {
// leave zen when callers set ringer-mode = normal or vibrate synchronized(mSettingsLock) {
final int zen = Global.getInt(mContentResolver, Global.ZEN_MODE, Global.ZEN_MODE_OFF); if (ringerMode == mRingerModeExternal) return;
if (ringerMode != AudioManager.RINGER_MODE_SILENT && zen != Global.ZEN_MODE_OFF) { mRingerModeExternal = ringerMode;
final long ident = Binder.clearCallingIdentity();
try {
Global.putInt(mContentResolver, Global.ZEN_MODE, Global.ZEN_MODE_OFF);
} finally {
Binder.restoreCallingIdentity(ident);
}
} }
// Send sticky broadcast
broadcastRingerMode(ringerMode);
} }
private void setRingerModeInt(int ringerMode, boolean persist) { 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 // Unmute stream if previously muted by ringer mode and ringer mode
// is RINGER_MODE_NORMAL or stream is not affected by ringer mode. // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
int numStreamTypes = AudioSystem.getNumStreamTypes(); 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--) { for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
if (isStreamMutedByRingerMode(streamType)) { final boolean isMuted = isStreamMutedByRingerMode(streamType);
if (!isStreamAffectedByRingerMode(streamType) || final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
ringerMode == AudioManager.RINGER_MODE_NORMAL) { if (isMuted == shouldMute) continue;
// ring and notifications volume should never be 0 when not silenced if (!shouldMute) {
// on voice capable devices or devices that support vibration // unmute
if ((isPlatformVoice() || mHasVibrator) && // ring and notifications volume should never be 0 when not silenced
mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { // on voice capable devices or devices that support vibration
synchronized (VolumeStreamState.class) { if ((isPlatformVoice() || mHasVibrator) &&
Set set = mStreamStates[streamType].mIndex.entrySet(); mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
Iterator i = set.iterator(); synchronized (VolumeStreamState.class) {
while (i.hasNext()) { Set set = mStreamStates[streamType].mIndex.entrySet();
Map.Entry entry = (Map.Entry)i.next(); Iterator i = set.iterator();
if ((Integer)entry.getValue() == 0) { while (i.hasNext()) {
entry.setValue(10); 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 { } else {
if (isStreamAffectedByRingerMode(streamType) && // mute
ringerMode != AudioManager.RINGER_MODE_NORMAL) { mStreamStates[streamType].mute(null, true);
mStreamStates[streamType].mute(null, true); mRingerModeMutedStreams |= (1 << streamType);
mRingerModeMutedStreams |= (1 << streamType);
}
} }
} }
@ -1888,10 +1926,10 @@ public class AudioService extends IAudioService.Stub {
switch (getVibrateSetting(vibrateType)) { switch (getVibrateSetting(vibrateType)) {
case AudioManager.VIBRATE_SETTING_ON: case AudioManager.VIBRATE_SETTING_ON:
return getRingerMode() != AudioManager.RINGER_MODE_SILENT; return getRingerModeInternal() != AudioManager.RINGER_MODE_SILENT;
case AudioManager.VIBRATE_SETTING_ONLY_SILENT: case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE; return getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE;
case AudioManager.VIBRATE_SETTING_OFF: case AudioManager.VIBRATE_SETTING_OFF:
// return false, even for incoming calls // 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 // apply new ringer mode before checking volume for alias streams so that streams
// muted by ringer mode have the correct volume // muted by ringer mode have the correct volume
setRingerModeInt(getRingerMode(), false); setRingerModeInt(getRingerModeInternal(), false);
checkAllFixedVolumeDevices(); checkAllFixedVolumeDevices();
checkAllAliasStreamVolumes(); checkAllAliasStreamVolumes();
@ -3003,7 +3041,7 @@ public class AudioService extends IAudioService.Stub {
*/ */
private int checkForRingerModeChange(int oldIndex, int direction, int step) { private int checkForRingerModeChange(int oldIndex, int direction, int step) {
int result = FLAG_ADJUST_VOLUME; int result = FLAG_ADJUST_VOLUME;
int ringerMode = getRingerMode(); int ringerMode = getRingerModeInternal();
switch (ringerMode) { switch (ringerMode) {
case RINGER_MODE_NORMAL: case RINGER_MODE_NORMAL:
@ -3037,6 +3075,8 @@ public class AudioService extends IAudioService.Stub {
if (VOLUME_SETS_RINGER_MODE_SILENT if (VOLUME_SETS_RINGER_MODE_SILENT
&& mPrevVolDirection != AudioManager.ADJUST_LOWER) { && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
ringerMode = RINGER_MODE_SILENT; ringerMode = RINGER_MODE_SILENT;
} else {
result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
} }
} else if (direction == AudioManager.ADJUST_RAISE) { } else if (direction == AudioManager.ADJUST_RAISE) {
ringerMode = RINGER_MODE_NORMAL; ringerMode = RINGER_MODE_NORMAL;
@ -3062,7 +3102,7 @@ public class AudioService extends IAudioService.Stub {
break; break;
} }
setRingerMode(ringerMode, false /*checkZen*/); setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
mPrevVolDirection = direction; mPrevVolDirection = direction;
@ -4136,7 +4176,7 @@ public class AudioService extends IAudioService.Stub {
case MSG_PERSIST_RINGER_MODE: case MSG_PERSIST_RINGER_MODE:
// note that the value persisted is the current ringer mode, not the // 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 // value of ringer mode as of the time the request was made to persist
persistRingerMode(getRingerMode()); persistRingerMode(getRingerModeInternal());
break; break;
case MSG_MEDIA_SERVER_DIED: case MSG_MEDIA_SERVER_DIED:
@ -4188,7 +4228,7 @@ public class AudioService extends IAudioService.Stub {
} }
// Restore ringer mode // Restore ringer mode
setRingerModeInt(getRingerMode(), false); setRingerModeInt(getRingerModeInternal(), false);
// Restore master volume // Restore master volume
restoreMasterVolume(); restoreMasterVolume();
@ -4358,7 +4398,7 @@ public class AudioService extends IAudioService.Stub {
* Ensure all stream types that should be affected by ringer mode * Ensure all stream types that should be affected by ringer mode
* are in the proper state. * are in the proper state.
*/ */
setRingerModeInt(getRingerMode(), false); setRingerModeInt(getRingerModeInternal(), false);
} }
readDockAudioSettings(mContentResolver); readDockAudioSettings(mContentResolver);
} }
@ -5110,7 +5150,7 @@ public class AudioService extends IAudioService.Stub {
(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
} }
// take new state into account for streams muted by ringer mode // take new state into account for streams muted by ringer mode
setRingerModeInt(getRingerMode(), false); setRingerModeInt(getRingerModeInternal(), false);
} }
sendMsg(mAudioHandler, sendMsg(mAudioHandler,
@ -5451,11 +5491,13 @@ public class AudioService extends IAudioService.Stub {
private void dumpRingerMode(PrintWriter pw) { private void dumpRingerMode(PrintWriter pw) {
pw.println("\nRinger mode: "); 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.print("- ringer mode affected streams = 0x");
pw.println(Integer.toHexString(mRingerModeAffectedStreams)); pw.println(Integer.toHexString(mRingerModeAffectedStreams));
pw.print("- ringer mode muted streams = 0x"); pw.print("- ringer mode muted streams = 0x");
pw.println(Integer.toHexString(mRingerModeMutedStreams)); pw.println(Integer.toHexString(mRingerModeMutedStreams));
pw.print("- delegate = "); pw.println(mRingerModeDelegate);
} }
@Override @Override
@ -5477,6 +5519,7 @@ public class AudioService extends IAudioService.Stub {
pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand); pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs); pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
pw.print(" mMcc="); pw.println(mMcc); pw.print(" mMcc="); pw.println(mMcc);
pw.print(" mHasVibrator="); pw.println(mHasVibrator);
} }
private static String safeMediaVolumeStateToString(Integer state) { private static String safeMediaVolumeStateToString(Integer state) {
@ -5668,6 +5711,16 @@ public class AudioService extends IAudioService.Stub {
Log.w(TAG, "Error calling dismiss", e); 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. * LocalServices.
*/ */
final class AudioServiceInternal extends AudioManagerInternal { final class AudioServiceInternal extends AudioManagerInternal {
@Override
public void setRingerModeDelegate(RingerModeDelegate delegate) {
mRingerModeDelegate = delegate;
if (mRingerModeDelegate != null) {
setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
}
}
@Override @Override
public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags, public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
@ -5701,6 +5761,16 @@ public class AudioService extends IAudioService.Stub {
int uid) { int uid) {
adjustMasterVolume(steps, flags, callingPackage, 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);
}
} }
//========================================================================================== //==========================================================================================

View File

@ -77,9 +77,13 @@ interface IAudioService {
void setMicrophoneMute(boolean on, String callingPackage); 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); boolean isValidRingerMode(int ringerMode);

View File

@ -34,4 +34,6 @@ oneway interface IVolumeController {
void setLayoutDirection(int layoutDirection); void setLayoutDirection(int layoutDirection);
void dismiss(); void dismiss();
void internalRingerModeChanged(int mode);
} }

View File

@ -1028,6 +1028,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
} }
} }
public void onInternalRingerModeChanged() {
if (mIconPolicy != null) {
mIconPolicy.updateVolumeZen();
}
}
private void startKeyguard() { private void startKeyguard() {
KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class); KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,

View File

@ -208,7 +208,7 @@ public class PhoneStatusBarPolicy {
} }
} }
private final void updateVolumeZen() { public final void updateVolumeZen() {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
boolean zenVisible = false; boolean zenVisible = false;
@ -230,7 +230,7 @@ public class PhoneStatusBarPolicy {
} }
if (mZen != Global.ZEN_MODE_NO_INTERRUPTIONS && if (mZen != Global.ZEN_MODE_NO_INTERRUPTIONS &&
audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) { audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
volumeVisible = true; volumeVisible = true;
volumeIconId = R.drawable.stat_sys_ringer_vibrate; volumeIconId = R.drawable.stat_sys_ringer_vibrate;
volumeDescription = mContext.getString(R.string.accessibility_ringer_vibrate); volumeDescription = mContext.getString(R.string.accessibility_ringer_vibrate);

View File

@ -157,8 +157,9 @@ public class ZenModeControllerImpl implements ZenModeController {
if (mRegistered) { if (mRegistered) {
mContext.unregisterReceiver(mReceiver); mContext.unregisterReceiver(mReceiver);
} }
mContext.registerReceiverAsUser(mReceiver, new UserHandle(mUserId), final IntentFilter filter = new IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
new IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED), null, null); filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
mContext.registerReceiverAsUser(mReceiver, new UserHandle(mUserId), filter, null, null);
mRegistered = true; mRegistered = true;
mSetupObserver.register(); mSetupObserver.register();
} }

View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2014 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 com.android.systemui.volume;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
public class IconPulser {
private static final float PULSE_SCALE = 1.1f;
private final Interpolator mFastOutSlowInInterpolator;
public IconPulser(Context context) {
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
android.R.interpolator.fast_out_slow_in);
}
public void start(final View target) {
if (target == null || target.getScaleX() != 1) return; // n/a, or already running
target.animate().cancel();
target.animate().scaleX(PULSE_SCALE).scaleY(PULSE_SCALE)
.setInterpolator(mFastOutSlowInInterpolator)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
target.animate().scaleX(1).scaleY(1).setListener(null);
}
});
}
}

View File

@ -124,6 +124,8 @@ public class VolumePanel extends Handler implements DemoMode {
private static final int MSG_ZEN_MODE_AVAILABLE_CHANGED = 13; private static final int MSG_ZEN_MODE_AVAILABLE_CHANGED = 13;
private static final int MSG_USER_ACTIVITY = 14; private static final int MSG_USER_ACTIVITY = 14;
private static final int MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED = 15; private static final int MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED = 15;
private static final int MSG_ZEN_MODE_CHANGED = 16;
private static final int MSG_INTERNAL_RINGER_MODE_CHANGED = 17;
// Pseudo stream type for master volume // Pseudo stream type for master volume
private static final int STREAM_MASTER = -100; private static final int STREAM_MASTER = -100;
@ -169,6 +171,8 @@ public class VolumePanel extends Handler implements DemoMode {
private final ViewGroup mSliderPanel; private final ViewGroup mSliderPanel;
/** The zen mode configuration panel view */ /** The zen mode configuration panel view */
private ZenModePanel mZenPanel; private ZenModePanel mZenPanel;
/** The component currently suppressing notification stream effects */
private ComponentName mNotificationEffectsSuppressor;
private Callback mCallback; private Callback mCallback;
@ -178,6 +182,7 @@ public class VolumePanel extends Handler implements DemoMode {
private SparseArray<StreamControl> mStreamControls; private SparseArray<StreamControl> mStreamControls;
private final AccessibilityManager mAccessibilityManager; private final AccessibilityManager mAccessibilityManager;
private final SecondaryIconTransition mSecondaryIconTransition; private final SecondaryIconTransition mSecondaryIconTransition;
private final IconPulser mIconPulser;
private enum StreamResources { private enum StreamResources {
BluetoothSCOStream(AudioManager.STREAM_BLUETOOTH_SCO, BluetoothSCOStream(AudioManager.STREAM_BLUETOOTH_SCO,
@ -188,7 +193,7 @@ public class VolumePanel extends Handler implements DemoMode {
RingerStream(AudioManager.STREAM_RING, RingerStream(AudioManager.STREAM_RING,
R.string.volume_icon_description_ringer, R.string.volume_icon_description_ringer,
com.android.systemui.R.drawable.ic_ringer_audible, com.android.systemui.R.drawable.ic_ringer_audible,
com.android.systemui.R.drawable.ic_ringer_vibrate, com.android.systemui.R.drawable.ic_ringer_mute,
false), false),
VoiceStream(AudioManager.STREAM_VOICE_CALL, VoiceStream(AudioManager.STREAM_VOICE_CALL,
R.string.volume_icon_description_incall, R.string.volume_icon_description_incall,
@ -208,7 +213,7 @@ public class VolumePanel extends Handler implements DemoMode {
NotificationStream(AudioManager.STREAM_NOTIFICATION, NotificationStream(AudioManager.STREAM_NOTIFICATION,
R.string.volume_icon_description_notification, R.string.volume_icon_description_notification,
com.android.systemui.R.drawable.ic_ringer_audible, com.android.systemui.R.drawable.ic_ringer_audible,
com.android.systemui.R.drawable.ic_ringer_vibrate, com.android.systemui.R.drawable.ic_ringer_mute,
true), true),
// for now, use media resources for master volume // for now, use media resources for master volume
MasterStream(STREAM_MASTER, MasterStream(STREAM_MASTER,
@ -268,6 +273,7 @@ public class VolumePanel extends Handler implements DemoMode {
// Synchronize when accessing this // Synchronize when accessing this
private ToneGenerator mToneGenerators[]; private ToneGenerator mToneGenerators[];
private Vibrator mVibrator; private Vibrator mVibrator;
private boolean mHasVibrator;
private static AlertDialog sSafetyWarning; private static AlertDialog sSafetyWarning;
private static Object sSafetyWarningLock = new Object(); private static Object sSafetyWarningLock = new Object();
@ -354,6 +360,7 @@ public class VolumePanel extends Handler implements DemoMode {
mAccessibilityManager = (AccessibilityManager) context.getSystemService( mAccessibilityManager = (AccessibilityManager) context.getSystemService(
Context.ACCESSIBILITY_SERVICE); Context.ACCESSIBILITY_SERVICE);
mSecondaryIconTransition = new SecondaryIconTransition(); mSecondaryIconTransition = new SecondaryIconTransition();
mIconPulser = new IconPulser(context);
// For now, only show master volume if master volume is supported // For now, only show master volume if master volume is supported
final Resources res = context.getResources(); final Resources res = context.getResources();
@ -435,10 +442,12 @@ public class VolumePanel extends Handler implements DemoMode {
mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()]; mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable); mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
if (mZenController != null && !useMasterVolume) { if (mZenController != null && !useMasterVolume) {
mZenModeAvailable = mZenController.isZenAvailable(); mZenModeAvailable = mZenController.isZenAvailable();
mNotificationEffectsSuppressor = mZenController.getEffectsSuppressor();
mZenController.addCallback(mZenCallback); mZenController.addCallback(mZenCallback);
} }
@ -470,8 +479,10 @@ public class VolumePanel extends Handler implements DemoMode {
pw.print(" mTag="); pw.println(mTag); pw.print(" mTag="); pw.println(mTag);
pw.print(" mRingIsSilent="); pw.println(mRingIsSilent); pw.print(" mRingIsSilent="); pw.println(mRingIsSilent);
pw.print(" mVoiceCapable="); pw.println(mVoiceCapable); pw.print(" mVoiceCapable="); pw.println(mVoiceCapable);
pw.print(" mHasVibrator="); pw.println(mHasVibrator);
pw.print(" mZenModeAvailable="); pw.println(mZenModeAvailable); pw.print(" mZenModeAvailable="); pw.println(mZenModeAvailable);
pw.print(" mZenPanelExpanded="); pw.println(mZenPanelExpanded); pw.print(" mZenPanelExpanded="); pw.println(mZenPanelExpanded);
pw.print(" mNotificationEffectsSuppressor="); pw.println(mNotificationEffectsSuppressor);
pw.print(" mTimeoutDelay="); pw.println(mTimeoutDelay); pw.print(" mTimeoutDelay="); pw.println(mTimeoutDelay);
pw.print(" mDisabledAlpha="); pw.println(mDisabledAlpha); pw.print(" mDisabledAlpha="); pw.println(mDisabledAlpha);
pw.print(" mLastRingerMode="); pw.println(mLastRingerMode); pw.print(" mLastRingerMode="); pw.println(mLastRingerMode);
@ -639,16 +650,19 @@ public class VolumePanel extends Handler implements DemoMode {
sc.iconRes = streamRes.iconRes; sc.iconRes = streamRes.iconRes;
sc.iconMuteRes = streamRes.iconMuteRes; sc.iconMuteRes = streamRes.iconMuteRes;
sc.icon.setImageResource(sc.iconRes); sc.icon.setImageResource(sc.iconRes);
sc.icon.setClickable(isNotification); sc.icon.setClickable(isNotification && mHasVibrator);
if (isNotification) { if (isNotification) {
sc.icon.setSoundEffectsEnabled(false); if (mHasVibrator) {
sc.icon.setOnClickListener(new OnClickListener() { sc.icon.setSoundEffectsEnabled(false);
@Override sc.iconMuteRes = com.android.systemui.R.drawable.ic_ringer_vibrate;
public void onClick(View v) { sc.icon.setOnClickListener(new OnClickListener() {
resetTimeout(); @Override
toggle(sc); public void onClick(View v) {
} resetTimeout();
}); toggleRinger(sc);
}
});
}
sc.iconSuppressedRes = com.android.systemui.R.drawable.ic_ringer_mute; sc.iconSuppressedRes = com.android.systemui.R.drawable.ic_ringer_mute;
} }
sc.seekbarView = (SeekBar) sc.group.findViewById(com.android.systemui.R.id.seekbar); sc.seekbarView = (SeekBar) sc.group.findViewById(com.android.systemui.R.id.seekbar);
@ -681,12 +695,13 @@ public class VolumePanel extends Handler implements DemoMode {
} }
} }
private void toggle(StreamControl sc) { private void toggleRinger(StreamControl sc) {
if (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL) { if (!mHasVibrator) return;
mAudioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE); if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL) {
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_VIBRATE);
postVolumeChanged(sc.streamType, AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE); postVolumeChanged(sc.streamType, AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE);
} else { } else {
mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL);
postVolumeChanged(sc.streamType, AudioManager.FLAG_PLAY_SOUND); postVolumeChanged(sc.streamType, AudioManager.FLAG_PLAY_SOUND);
} }
} }
@ -710,7 +725,7 @@ public class VolumePanel extends Handler implements DemoMode {
private void updateSliderProgress(StreamControl sc, int progress) { private void updateSliderProgress(StreamControl sc, int progress) {
final boolean isRinger = isNotificationOrRing(sc.streamType); final boolean isRinger = isNotificationOrRing(sc.streamType);
if (isRinger && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) { if (isRinger && mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) {
progress = mLastRingerProgress; progress = mLastRingerProgress;
} }
if (progress < 0) { if (progress < 0) {
@ -723,21 +738,30 @@ public class VolumePanel extends Handler implements DemoMode {
} }
private void updateSliderIcon(StreamControl sc, boolean muted) { private void updateSliderIcon(StreamControl sc, boolean muted) {
ComponentName suppressor = null;
if (isNotificationOrRing(sc.streamType)) { if (isNotificationOrRing(sc.streamType)) {
int ringerMode = mAudioManager.getRingerMode(); suppressor = mNotificationEffectsSuppressor;
int ringerMode = mAudioManager.getRingerModeInternal();
if (ringerMode == AudioManager.RINGER_MODE_SILENT) { if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
ringerMode = mLastRingerMode; ringerMode = mLastRingerMode;
} else { } else {
mLastRingerMode = ringerMode; mLastRingerMode = ringerMode;
} }
muted = ringerMode == AudioManager.RINGER_MODE_VIBRATE; if (mHasVibrator) {
muted = ringerMode == AudioManager.RINGER_MODE_VIBRATE;
} else {
muted = false;
}
} }
sc.icon.setImageResource(mDemoIcon != 0 ? mDemoIcon : muted ? sc.iconMuteRes : sc.iconRes); sc.icon.setImageResource(mDemoIcon != 0 ? mDemoIcon
: suppressor != null ? sc.iconSuppressedRes
: muted ? sc.iconMuteRes
: sc.iconRes);
} }
private void updateSliderSupressor(StreamControl sc) { private void updateSliderSuppressor(StreamControl sc) {
final ComponentName suppressor = isNotificationOrRing(sc.streamType) final ComponentName suppressor = isNotificationOrRing(sc.streamType)
? mZenController.getEffectsSuppressor() : null; ? mNotificationEffectsSuppressor : null;
if (suppressor == null) { if (suppressor == null) {
sc.seekbarView.setVisibility(View.VISIBLE); sc.seekbarView.setVisibility(View.VISIBLE);
sc.suppressorView.setVisibility(View.GONE); sc.suppressorView.setVisibility(View.GONE);
@ -746,7 +770,6 @@ public class VolumePanel extends Handler implements DemoMode {
sc.suppressorView.setVisibility(View.VISIBLE); sc.suppressorView.setVisibility(View.VISIBLE);
sc.suppressorView.setText(mContext.getString(R.string.muted_by, sc.suppressorView.setText(mContext.getString(R.string.muted_by,
getSuppressorCaption(suppressor))); getSuppressorCaption(suppressor)));
sc.icon.setImageResource(sc.iconSuppressedRes);
} }
} }
@ -777,7 +800,7 @@ public class VolumePanel extends Handler implements DemoMode {
sc.icon.setImageDrawable(null); sc.icon.setImageDrawable(null);
updateSliderIcon(sc, muted); updateSliderIcon(sc, muted);
updateSliderEnabled(sc, muted, false); updateSliderEnabled(sc, muted, false);
updateSliderSupressor(sc); updateSliderSuppressor(sc);
} }
private void updateSliderEnabled(final StreamControl sc, boolean muted, boolean fixedVolume) { private void updateSliderEnabled(final StreamControl sc, boolean muted, boolean fixedVolume) {
@ -787,7 +810,12 @@ public class VolumePanel extends Handler implements DemoMode {
// never disable touch interactions for remote playback, the muting is not tied to // never disable touch interactions for remote playback, the muting is not tied to
// the state of the phone. // the state of the phone.
sc.seekbarView.setEnabled(!fixedVolume); sc.seekbarView.setEnabled(!fixedVolume);
} else if (isRinger && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) { } else if (isRinger && mNotificationEffectsSuppressor != null) {
sc.icon.setEnabled(true);
sc.icon.setAlpha(1f);
sc.icon.setClickable(false);
} else if (isRinger
&& mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) {
sc.seekbarView.setEnabled(false); sc.seekbarView.setEnabled(false);
sc.icon.setEnabled(false); sc.icon.setEnabled(false);
sc.icon.setAlpha(mDisabledAlpha); sc.icon.setAlpha(mDisabledAlpha);
@ -805,7 +833,7 @@ public class VolumePanel extends Handler implements DemoMode {
if (isRinger && wasEnabled != sc.seekbarView.isEnabled()) { if (isRinger && wasEnabled != sc.seekbarView.isEnabled()) {
if (sc.seekbarView.isEnabled()) { if (sc.seekbarView.isEnabled()) {
sc.group.setOnTouchListener(null); sc.group.setOnTouchListener(null);
sc.icon.setClickable(true); sc.icon.setClickable(mHasVibrator);
} else { } else {
final View.OnTouchListener showHintOnTouch = new View.OnTouchListener() { final View.OnTouchListener showHintOnTouch = new View.OnTouchListener() {
@Override @Override
@ -826,6 +854,16 @@ public class VolumePanel extends Handler implements DemoMode {
} }
} }
private void showVibrateHint() {
final StreamControl active = mStreamControls.get(mActiveStreamType);
if (active != null) {
mIconPulser.start(active.icon);
if (!hasMessages(MSG_VIBRATE)) {
sendEmptyMessageDelayed(MSG_VIBRATE, VIBRATE_DELAY);
}
}
}
private static boolean isNotificationOrRing(int streamType) { private static boolean isNotificationOrRing(int streamType) {
return streamType == AudioManager.STREAM_RING return streamType == AudioManager.STREAM_RING
|| streamType == AudioManager.STREAM_NOTIFICATION; || streamType == AudioManager.STREAM_NOTIFICATION;
@ -953,6 +991,19 @@ public class VolumePanel extends Handler implements DemoMode {
obtainMessage(MSG_LAYOUT_DIRECTION, layoutDirection, 0).sendToTarget(); obtainMessage(MSG_LAYOUT_DIRECTION, layoutDirection, 0).sendToTarget();
} }
public void postInternalRingerModeChanged(int mode) {
removeMessages(MSG_INTERNAL_RINGER_MODE_CHANGED);
obtainMessage(MSG_INTERNAL_RINGER_MODE_CHANGED, mode, 0).sendToTarget();
}
private static String flagsToString(int flags) {
return flags == 0 ? "0" : (flags + "=" + AudioManager.flagsToString(flags));
}
private static String streamToString(int stream) {
return AudioService.streamToString(stream);
}
/** /**
* Override this if you have other work to do when the volume changes (for * Override this if you have other work to do when the volume changes (for
* example, vibrating, playing a sound, etc.). Make sure to call through to * example, vibrating, playing a sound, etc.). Make sure to call through to
@ -960,7 +1011,8 @@ public class VolumePanel extends Handler implements DemoMode {
*/ */
protected void onVolumeChanged(int streamType, int flags) { protected void onVolumeChanged(int streamType, int flags) {
if (LOGD) Log.d(mTag, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")"); if (LOGD) Log.d(mTag, "onVolumeChanged(streamType: " + streamToString(streamType)
+ ", flags: " + flagsToString(flags) + ")");
if ((flags & AudioManager.FLAG_SHOW_UI) != 0) { if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
synchronized (this) { synchronized (this) {
@ -989,7 +1041,8 @@ public class VolumePanel extends Handler implements DemoMode {
protected void onMuteChanged(int streamType, int flags) { protected void onMuteChanged(int streamType, int flags) {
if (LOGD) Log.d(mTag, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")"); if (LOGD) Log.d(mTag, "onMuteChanged(streamType: " + streamToString(streamType)
+ ", flags: " + flagsToString(flags) + ")");
StreamControl sc = mStreamControls.get(streamType); StreamControl sc = mStreamControls.get(streamType);
if (sc != null) { if (sc != null) {
@ -1005,8 +1058,8 @@ public class VolumePanel extends Handler implements DemoMode {
mRingIsSilent = false; mRingIsSilent = false;
if (LOGD) { if (LOGD) {
Log.d(mTag, "onShowVolumeChanged(streamType: " + streamType Log.d(mTag, "onShowVolumeChanged(streamType: " + streamToString(streamType)
+ ", flags: " + flags + "), index: " + index); + ", flags: " + flagsToString(flags) + "), index: " + index);
} }
// get max volume for progress bar // get max volume for progress bar
@ -1017,7 +1070,6 @@ public class VolumePanel extends Handler implements DemoMode {
switch (streamType) { switch (streamType) {
case AudioManager.STREAM_RING: { case AudioManager.STREAM_RING: {
// setRingerIcon();
Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri( Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
mContext, RingtoneManager.TYPE_RINGTONE); mContext, RingtoneManager.TYPE_RINGTONE);
if (ringuri == null) { if (ringuri == null) {
@ -1110,13 +1162,16 @@ public class VolumePanel extends Handler implements DemoMode {
sc.seekbarView.setMax(max); sc.seekbarView.setMax(max);
} }
updateSliderProgress(sc, index); updateSliderProgress(sc, index);
updateSliderEnabled(sc, isMuted(streamType), final boolean muted = isMuted(streamType);
(flags & AudioManager.FLAG_FIXED_VOLUME) != 0); updateSliderEnabled(sc, muted, (flags & AudioManager.FLAG_FIXED_VOLUME) != 0);
// check for secondary-icon transition completion if (isNotificationOrRing(streamType)) {
if (isNotificationOrRing(streamType) && mSecondaryIconTransition.isRunning()) { // check for secondary-icon transition completion
mSecondaryIconTransition.cancel(); // safe to reset if (mSecondaryIconTransition.isRunning()) {
sc.seekbarView.setAlpha(0); sc.seekbarView.animate().alpha(1); mSecondaryIconTransition.cancel(); // safe to reset
mZenPanel.setAlpha(0); mZenPanel.animate().alpha(1); sc.seekbarView.setAlpha(0); sc.seekbarView.animate().alpha(1);
mZenPanel.setAlpha(0); mZenPanel.animate().alpha(1);
}
updateSliderIcon(sc, muted);
} }
} }
@ -1134,15 +1189,20 @@ public class VolumePanel extends Handler implements DemoMode {
// Do a little vibrate if applicable (only when going into vibrate mode) // Do a little vibrate if applicable (only when going into vibrate mode)
if ((streamType != STREAM_REMOTE_MUSIC) && if ((streamType != STREAM_REMOTE_MUSIC) &&
((flags & AudioManager.FLAG_VIBRATE) != 0) && ((flags & AudioManager.FLAG_VIBRATE) != 0) &&
mAudioManager.isStreamAffectedByRingerMode(streamType) && isNotificationOrRing(streamType) &&
mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) { mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY); sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY);
} }
// Pulse the slider icon if an adjustment was suppressed due to silent mode. // Pulse the zen icon if an adjustment was suppressed due to silent mode.
if ((flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) { if ((flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
showSilentHint(); showSilentHint();
} }
// Pulse the slider icon & vibrate if an adjustment down was suppressed due to vibrate mode.
if ((flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
showVibrateHint();
}
} }
private void announceDialogShown() { private void announceDialogShown() {
@ -1186,16 +1246,17 @@ public class VolumePanel extends Handler implements DemoMode {
protected void onVibrate() { protected void onVibrate() {
// Make sure we ended up in vibrate ringer mode // Make sure we ended up in vibrate ringer mode
if (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_VIBRATE) { if (mAudioManager.getRingerModeInternal() != AudioManager.RINGER_MODE_VIBRATE) {
return; return;
} }
if (mVibrator != null) {
mVibrator.vibrate(VIBRATE_DURATION, VIBRATION_ATTRIBUTES); mVibrator.vibrate(VIBRATE_DURATION, VIBRATION_ATTRIBUTES);
}
} }
protected void onRemoteVolumeChanged(MediaController controller, int flags) { protected void onRemoteVolumeChanged(MediaController controller, int flags) {
if (LOGD) Log.d(mTag, "onRemoteVolumeChanged(controller:" + controller + ", flags: " + flags if (LOGD) Log.d(mTag, "onRemoteVolumeChanged(controller:" + controller + ", flags: "
+ ")"); + flagsToString(flags) + ")");
if (((flags & AudioManager.FLAG_SHOW_UI) != 0) || isShowing()) { if (((flags & AudioManager.FLAG_SHOW_UI) != 0) || isShowing()) {
synchronized (this) { synchronized (this) {
@ -1385,7 +1446,9 @@ public class VolumePanel extends Handler implements DemoMode {
break; break;
} }
case MSG_ZEN_MODE_CHANGED:
case MSG_RINGER_MODE_CHANGED: case MSG_RINGER_MODE_CHANGED:
case MSG_INTERNAL_RINGER_MODE_CHANGED:
case MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED: { case MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED: {
if (isShowing()) { if (isShowing()) {
updateStates(); updateStates();
@ -1491,10 +1554,15 @@ public class VolumePanel extends Handler implements DemoMode {
public void onZenAvailableChanged(boolean available) { public void onZenAvailableChanged(boolean available) {
obtainMessage(MSG_ZEN_MODE_AVAILABLE_CHANGED, available ? 1 : 0, 0).sendToTarget(); obtainMessage(MSG_ZEN_MODE_AVAILABLE_CHANGED, available ? 1 : 0, 0).sendToTarget();
} }
@Override @Override
public void onEffectsSupressorChanged() { public void onEffectsSupressorChanged() {
obtainMessage(MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED, mNotificationEffectsSuppressor = mZenController.getEffectsSuppressor();
mZenController.getEffectsSuppressor()).sendToTarget(); sendEmptyMessage(MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED);
}
public void onZenChanged(int zen) {
sendEmptyMessage(MSG_ZEN_MODE_CHANGED);
} }
}; };

View File

@ -181,6 +181,15 @@ public class VolumeUI extends SystemUI {
dismissNow(); dismissNow();
} }
@Override
public void internalRingerModeChanged(int mode) throws RemoteException {
mPanel.postInternalRingerModeChanged(mode);
final PhoneStatusBar psb = getComponent(PhoneStatusBar.class);
if (psb != null) {
psb.onInternalRingerModeChanged();
}
}
@Override @Override
public ZenModeController getZenController() { public ZenModeController getZenController() {
return mPanel.getZenController(); return mPanel.getZenController();

View File

@ -16,8 +16,6 @@
package com.android.systemui.volume; package com.android.systemui.volume;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -38,8 +36,6 @@ import android.util.Log;
import android.util.MathUtils; import android.util.MathUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView; import android.widget.ImageView;
@ -69,7 +65,6 @@ public class ZenModePanel extends LinearLayout {
private static final int FOREVER_CONDITION_INDEX = 0; private static final int FOREVER_CONDITION_INDEX = 0;
private static final int TIME_CONDITION_INDEX = 1; private static final int TIME_CONDITION_INDEX = 1;
private static final int FIRST_CONDITION_INDEX = 2; private static final int FIRST_CONDITION_INDEX = 2;
private static final float SILENT_HINT_PULSE_SCALE = 1.1f;
private static final long SELECT_DEFAULT_DELAY = 300; private static final long SELECT_DEFAULT_DELAY = 300;
public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS); public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
@ -78,7 +73,7 @@ public class ZenModePanel extends LinearLayout {
private final LayoutInflater mInflater; private final LayoutInflater mInflater;
private final H mHandler = new H(); private final H mHandler = new H();
private final Prefs mPrefs; private final Prefs mPrefs;
private final Interpolator mFastOutSlowInInterpolator; private final IconPulser mIconPulser;
private final int mSubheadWarningColor; private final int mSubheadWarningColor;
private final int mSubheadColor; private final int mSubheadColor;
@ -110,8 +105,7 @@ public class ZenModePanel extends LinearLayout {
mContext = context; mContext = context;
mPrefs = new Prefs(); mPrefs = new Prefs();
mInflater = LayoutInflater.from(mContext.getApplicationContext()); mInflater = LayoutInflater.from(mContext.getApplicationContext());
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(mContext, mIconPulser = new IconPulser(mContext);
android.R.interpolator.fast_out_slow_in);
final Resources res = mContext.getResources(); final Resources res = mContext.getResources();
mSubheadWarningColor = res.getColor(R.color.system_warning_color); mSubheadWarningColor = res.getColor(R.color.system_warning_color);
mSubheadColor = res.getColor(R.color.qs_subhead); mSubheadColor = res.getColor(R.color.qs_subhead);
@ -283,16 +277,7 @@ public class ZenModePanel extends LinearLayout {
if (DEBUG) Log.d(mTag, "showSilentHint"); if (DEBUG) Log.d(mTag, "showSilentHint");
if (mZenButtons == null || mZenButtons.getChildCount() == 0) return; if (mZenButtons == null || mZenButtons.getChildCount() == 0) return;
final View noneButton = mZenButtons.getChildAt(0); final View noneButton = mZenButtons.getChildAt(0);
if (noneButton.getScaleX() != 1) return; // already running mIconPulser.start(noneButton);
noneButton.animate().cancel();
noneButton.animate().scaleX(SILENT_HINT_PULSE_SCALE).scaleY(SILENT_HINT_PULSE_SCALE)
.setInterpolator(mFastOutSlowInInterpolator)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
noneButton.animate().scaleX(1).scaleY(1).setListener(null);
}
});
} }
private void handleUpdateZen(int zen) { private void handleUpdateZen(int zen) {

View File

@ -847,7 +847,7 @@ public class NotificationManagerService extends SystemService {
mRankingHelper = new RankingHelper(getContext(), mRankingHelper = new RankingHelper(getContext(),
new RankingWorkerHandler(mRankingThread.getLooper()), new RankingWorkerHandler(mRankingThread.getLooper()),
extractorNames); extractorNames);
mZenModeHelper = new ZenModeHelper(getContext(), mHandler); mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper());
mZenModeHelper.addCallback(new ZenModeHelper.Callback() { mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
@Override @Override
public void onConfigChanged() { public void onConfigChanged() {
@ -970,7 +970,7 @@ public class NotificationManagerService extends SystemService {
// Grab our optional AudioService // Grab our optional AudioService
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mZenModeHelper.setAudioManager(mAudioManager); mZenModeHelper.onSystemReady();
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
// This observer will force an update when observe is called, causing us to // This observer will force an update when observe is called, causing us to
// bind to listener services. // bind to listener services.
@ -1412,8 +1412,8 @@ public class NotificationManagerService extends SystemService {
final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity();
try { try {
synchronized (mNotificationList) { synchronized (mNotificationList) {
mListeners.checkServiceTokenLocked(token); final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
mZenModeHelper.requestFromListener(interruptionFilter); mZenModeHelper.requestFromListener(info.component, interruptionFilter);
updateInterruptionFilterLocked(); updateInterruptionFilterLocked();
} }
} finally { } finally {
@ -1965,7 +1965,7 @@ public class NotificationManagerService extends SystemService {
final boolean convertSoundToVibration = final boolean convertSoundToVibration =
!hasCustomVibrate !hasCustomVibrate
&& hasValidSound && hasValidSound
&& (mAudioManager.getRingerMode() && (mAudioManager.getRingerModeInternal()
== AudioManager.RINGER_MODE_VIBRATE); == AudioManager.RINGER_MODE_VIBRATE);
// The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback. // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
@ -1973,7 +1973,7 @@ public class NotificationManagerService extends SystemService {
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0; (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate) if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
&& !(mAudioManager.getRingerMode() && !(mAudioManager.getRingerModeInternal()
== AudioManager.RINGER_MODE_SILENT)) { == AudioManager.RINGER_MODE_SILENT)) {
mVibrateNotification = record; mVibrateNotification = record;

View File

@ -46,15 +46,15 @@ public class ZenLog {
private static final int TYPE_INTERCEPTED = 1; private static final int TYPE_INTERCEPTED = 1;
private static final int TYPE_ALLOW_DISABLE = 2; private static final int TYPE_ALLOW_DISABLE = 2;
private static final int TYPE_SET_RINGER_MODE = 3; private static final int TYPE_SET_RINGER_MODE_EXTERNAL = 3;
private static final int TYPE_DOWNTIME = 4; private static final int TYPE_SET_RINGER_MODE_INTERNAL = 4;
private static final int TYPE_SET_ZEN_MODE = 5; private static final int TYPE_DOWNTIME = 5;
private static final int TYPE_UPDATE_ZEN_MODE = 6; private static final int TYPE_SET_ZEN_MODE = 6;
private static final int TYPE_EXIT_CONDITION = 7; private static final int TYPE_UPDATE_ZEN_MODE = 7;
private static final int TYPE_SUBSCRIBE = 8; private static final int TYPE_EXIT_CONDITION = 8;
private static final int TYPE_UNSUBSCRIBE = 9; private static final int TYPE_SUBSCRIBE = 9;
private static final int TYPE_CONFIG = 10; private static final int TYPE_UNSUBSCRIBE = 10;
private static final int TYPE_FOLLOW_RINGER_MODE = 11; private static final int TYPE_CONFIG = 11;
private static final int TYPE_NOT_INTERCEPTED = 12; private static final int TYPE_NOT_INTERCEPTED = 12;
private static final int TYPE_DISABLE_EFFECTS = 13; private static final int TYPE_DISABLE_EFFECTS = 13;
@ -71,8 +71,22 @@ public class ZenLog {
append(TYPE_NOT_INTERCEPTED, record.getKey() + "," + reason); append(TYPE_NOT_INTERCEPTED, record.getKey() + "," + reason);
} }
public static void traceSetRingerMode(int ringerMode) { public static void traceSetRingerModeExternal(int ringerModeOld, int ringerModeNew,
append(TYPE_SET_RINGER_MODE, ringerModeToString(ringerMode)); String caller, int ringerModeInternalIn, int ringerModeInternalOut) {
append(TYPE_SET_RINGER_MODE_EXTERNAL, caller + ",e:" +
ringerModeToString(ringerModeOld) + "->" +
ringerModeToString(ringerModeNew) + ",i:" +
ringerModeToString(ringerModeInternalIn) + "->" +
ringerModeToString(ringerModeInternalOut));
}
public static void traceSetRingerModeInternal(int ringerModeOld, int ringerModeNew,
String caller, int ringerModeExternalIn, int ringerModeExternalOut) {
append(TYPE_SET_RINGER_MODE_INTERNAL, caller + ",i:" +
ringerModeToString(ringerModeOld) + "->" +
ringerModeToString(ringerModeNew) + ",e:" +
ringerModeToString(ringerModeExternalIn) + "->" +
ringerModeToString(ringerModeExternalOut));
} }
public static void traceDowntime(int downtimeMode, int day, ArraySet<Integer> days) { public static void traceDowntime(int downtimeMode, int day, ArraySet<Integer> days) {
@ -103,11 +117,6 @@ public class ZenLog {
append(TYPE_CONFIG, newConfig != null ? newConfig.toString() : null); append(TYPE_CONFIG, newConfig != null ? newConfig.toString() : null);
} }
public static void traceFollowRingerMode(int ringerMode, int oldZen, int newZen) {
append(TYPE_FOLLOW_RINGER_MODE, ringerModeToString(ringerMode) + ", "
+ zenModeToString(oldZen) + " -> " + zenModeToString(newZen));
}
public static void traceDisableEffects(NotificationRecord record, String reason) { public static void traceDisableEffects(NotificationRecord record, String reason) {
append(TYPE_DISABLE_EFFECTS, record.getKey() + "," + reason); append(TYPE_DISABLE_EFFECTS, record.getKey() + "," + reason);
} }
@ -120,7 +129,8 @@ public class ZenLog {
switch (type) { switch (type) {
case TYPE_INTERCEPTED: return "intercepted"; case TYPE_INTERCEPTED: return "intercepted";
case TYPE_ALLOW_DISABLE: return "allow_disable"; case TYPE_ALLOW_DISABLE: return "allow_disable";
case TYPE_SET_RINGER_MODE: return "set_ringer_mode"; case TYPE_SET_RINGER_MODE_EXTERNAL: return "set_ringer_mode_external";
case TYPE_SET_RINGER_MODE_INTERNAL: return "set_ringer_mode_internal";
case TYPE_DOWNTIME: return "downtime"; case TYPE_DOWNTIME: return "downtime";
case TYPE_SET_ZEN_MODE: return "set_zen_mode"; case TYPE_SET_ZEN_MODE: return "set_zen_mode";
case TYPE_UPDATE_ZEN_MODE: return "update_zen_mode"; case TYPE_UPDATE_ZEN_MODE: return "update_zen_mode";
@ -128,7 +138,6 @@ public class ZenLog {
case TYPE_SUBSCRIBE: return "subscribe"; case TYPE_SUBSCRIBE: return "subscribe";
case TYPE_UNSUBSCRIBE: return "unsubscribe"; case TYPE_UNSUBSCRIBE: return "unsubscribe";
case TYPE_CONFIG: return "config"; case TYPE_CONFIG: return "config";
case TYPE_FOLLOW_RINGER_MODE: return "follow_ringer_mode";
case TYPE_NOT_INTERCEPTED: return "not_intercepted"; case TYPE_NOT_INTERCEPTED: return "not_intercepted";
case TYPE_DISABLE_EFFECTS: return "disable_effects"; case TYPE_DISABLE_EFFECTS: return "disable_effects";
default: return "unknown"; default: return "unknown";

View File

@ -21,20 +21,20 @@ import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
import android.app.AppOpsManager; import android.app.AppOpsManager;
import android.app.Notification; import android.app.Notification;
import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.XmlResourceParser; import android.content.res.XmlResourceParser;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.media.AudioAttributes; import android.media.AudioAttributes;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.UserHandle; import android.os.UserHandle;
import android.provider.Settings.Global; import android.provider.Settings.Global;
import android.provider.Settings.Secure; import android.provider.Settings.Secure;
@ -45,6 +45,7 @@ import android.util.Log;
import android.util.Slog; import android.util.Slog;
import com.android.internal.R; import com.android.internal.R;
import com.android.server.LocalServices;
import libcore.io.IoUtils; import libcore.io.IoUtils;
@ -60,12 +61,12 @@ import java.util.Objects;
/** /**
* NotificationManagerService helper for functionality related to zen mode. * NotificationManagerService helper for functionality related to zen mode.
*/ */
public class ZenModeHelper { public class ZenModeHelper implements AudioManagerInternal.RingerModeDelegate {
private static final String TAG = "ZenModeHelper"; private static final String TAG = "ZenModeHelper";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final Context mContext; private final Context mContext;
private final Handler mHandler; private final H mHandler;
private final SettingsObserver mSettingsObserver; private final SettingsObserver mSettingsObserver;
private final AppOpsManager mAppOps; private final AppOpsManager mAppOps;
private final ZenModeConfig mDefaultConfig; private final ZenModeConfig mDefaultConfig;
@ -74,21 +75,17 @@ public class ZenModeHelper {
private ComponentName mDefaultPhoneApp; private ComponentName mDefaultPhoneApp;
private int mZenMode; private int mZenMode;
private ZenModeConfig mConfig; private ZenModeConfig mConfig;
private AudioManager mAudioManager; private AudioManagerInternal mAudioManager;
private int mPreviousRingerMode = -1; private int mPreviousRingerMode = -1;
public ZenModeHelper(Context context, Handler handler) { public ZenModeHelper(Context context, Looper looper) {
mContext = context; mContext = context;
mHandler = handler; mHandler = new H(looper);
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mDefaultConfig = readDefaultConfig(context.getResources()); mDefaultConfig = readDefaultConfig(context.getResources());
mConfig = mDefaultConfig; mConfig = mDefaultConfig;
mSettingsObserver = new SettingsObserver(mHandler); mSettingsObserver = new SettingsObserver(mHandler);
mSettingsObserver.observe(); mSettingsObserver.observe();
final IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
mContext.registerReceiver(mReceiver, filter);
} }
public static ZenModeConfig readDefaultConfig(Resources resources) { public static ZenModeConfig readDefaultConfig(Resources resources) {
@ -111,8 +108,11 @@ public class ZenModeHelper {
mCallbacks.add(callback); mCallbacks.add(callback);
} }
public void setAudioManager(AudioManager audioManager) { public void onSystemReady() {
mAudioManager = audioManager; mAudioManager = LocalServices.getService(AudioManagerInternal.class);
if (mAudioManager != null) {
mAudioManager.setRingerModeDelegate(this);
}
} }
public int getZenModeListenerInterruptionFilter() { public int getZenModeListenerInterruptionFilter() {
@ -142,10 +142,10 @@ public class ZenModeHelper {
} }
} }
public void requestFromListener(int interruptionFilter) { public void requestFromListener(ComponentName name, int interruptionFilter) {
final int newZen = zenModeFromListenerInterruptionFilter(interruptionFilter, -1); final int newZen = zenModeFromListenerInterruptionFilter(interruptionFilter, -1);
if (newZen != -1) { if (newZen != -1) {
setZenMode(newZen, "listener"); setZenMode(newZen, "listener:" + (name != null ? name.flattenToShortString() : null));
} }
} }
@ -214,12 +214,13 @@ public class ZenModeHelper {
} }
public void updateZenMode() { public void updateZenMode() {
final int mode = Global.getInt(mContext.getContentResolver(), final int oldMode = mZenMode;
final int newMode = Global.getInt(mContext.getContentResolver(),
Global.ZEN_MODE, Global.ZEN_MODE_OFF); Global.ZEN_MODE, Global.ZEN_MODE_OFF);
if (mode != mZenMode) { if (oldMode != newMode) {
ZenLog.traceUpdateZenMode(mZenMode, mode); ZenLog.traceUpdateZenMode(oldMode, newMode);
} }
mZenMode = mode; mZenMode = newMode;
final boolean zen = mZenMode != Global.ZEN_MODE_OFF; final boolean zen = mZenMode != Global.ZEN_MODE_OFF;
final String[] exceptionPackages = null; // none (for now) final String[] exceptionPackages = null; // none (for now)
@ -241,29 +242,7 @@ public class ZenModeHelper {
muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
exceptionPackages); exceptionPackages);
// force ringer mode into compliance onZenUpdated(oldMode, newMode);
if (mAudioManager != null) {
int ringerMode = mAudioManager.getRingerMode();
int forcedRingerMode = -1;
if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
if (ringerMode != AudioManager.RINGER_MODE_SILENT) {
mPreviousRingerMode = ringerMode;
if (DEBUG) Slog.d(TAG, "Silencing ringer");
forcedRingerMode = AudioManager.RINGER_MODE_SILENT;
}
} else {
if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
if (DEBUG) Slog.d(TAG, "Unsilencing ringer");
forcedRingerMode = mPreviousRingerMode != -1 ? mPreviousRingerMode
: AudioManager.RINGER_MODE_NORMAL;
mPreviousRingerMode = -1;
}
}
if (forcedRingerMode != -1) {
mAudioManager.setRingerMode(forcedRingerMode, false /*checkZen*/);
ZenLog.traceSetRingerMode(forcedRingerMode);
}
}
dispatchOnZenModeChanged(); dispatchOnZenModeChanged();
} }
@ -303,25 +282,102 @@ public class ZenModeHelper {
return true; return true;
} }
private void handleRingerModeChanged() { private void onZenUpdated(int oldZen, int newZen) {
if (mAudioManager != null) { if (mAudioManager == null) return;
// follow ringer mode if necessary if (oldZen == newZen) return;
final int ringerMode = mAudioManager.getRingerMode();
int newZen = -1; // force the ringer mode into compliance
if (ringerMode == AudioManager.RINGER_MODE_SILENT) { final int ringerModeInternal = mAudioManager.getRingerModeInternal();
if (mZenMode == Global.ZEN_MODE_OFF) { int newRingerModeInternal = ringerModeInternal;
newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; switch (newZen) {
case Global.ZEN_MODE_NO_INTERRUPTIONS:
if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) {
mPreviousRingerMode = ringerModeInternal;
newRingerModeInternal = AudioManager.RINGER_MODE_SILENT;
} }
} else if ((ringerMode == AudioManager.RINGER_MODE_NORMAL break;
|| ringerMode == AudioManager.RINGER_MODE_VIBRATE) case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
&& mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) { case Global.ZEN_MODE_OFF:
newZen = Global.ZEN_MODE_OFF; if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) {
} newRingerModeInternal = mPreviousRingerMode != -1 ? mPreviousRingerMode
if (newZen != -1) { : AudioManager.RINGER_MODE_NORMAL;
ZenLog.traceFollowRingerMode(ringerMode, mZenMode, newZen); mPreviousRingerMode = -1;
setZenMode(newZen, "ringerMode"); }
} break;
} }
if (newRingerModeInternal != -1) {
mAudioManager.setRingerModeInternal(newRingerModeInternal, TAG);
}
}
@Override // RingerModeDelegate
public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
int ringerModeExternal) {
final boolean isChange = ringerModeOld != ringerModeNew;
int ringerModeExternalOut = ringerModeNew;
int newZen = -1;
switch(ringerModeNew) {
case AudioManager.RINGER_MODE_SILENT:
if (isChange) {
if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS) {
newZen = Global.ZEN_MODE_NO_INTERRUPTIONS;
}
}
break;
case AudioManager.RINGER_MODE_VIBRATE:
case AudioManager.RINGER_MODE_NORMAL:
if (mZenMode != Global.ZEN_MODE_OFF) {
ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT;
}
break;
}
if (newZen != -1) {
mHandler.postSetZenMode(newZen, "ringerModeInternal");
}
if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) {
ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller,
ringerModeExternal, ringerModeExternalOut);
}
return ringerModeExternalOut;
}
@Override // RingerModeDelegate
public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
int ringerModeInternal) {
int ringerModeInternalOut = ringerModeNew;
final boolean isChange = ringerModeOld != ringerModeNew;
final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
int newZen = -1;
switch(ringerModeNew) {
case AudioManager.RINGER_MODE_SILENT:
if (isChange) {
if (mZenMode == Global.ZEN_MODE_OFF) {
newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
}
ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
: AudioManager.RINGER_MODE_NORMAL;
} else {
ringerModeInternalOut = ringerModeInternal;
}
break;
case AudioManager.RINGER_MODE_VIBRATE:
case AudioManager.RINGER_MODE_NORMAL:
if (mZenMode != Global.ZEN_MODE_OFF) {
newZen = Global.ZEN_MODE_OFF;
}
break;
}
if (newZen != -1) {
mHandler.postSetZenMode(newZen, "ringerModeExternal");
}
ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller, ringerModeInternal,
ringerModeInternalOut);
return ringerModeInternalOut;
} }
private void dispatchOnConfigChanged() { private void dispatchOnConfigChanged() {
@ -399,6 +455,11 @@ public class ZenModeHelper {
return true; return true;
} }
@Override
public String toString() {
return TAG;
}
private boolean audienceMatches(float contactAffinity) { private boolean audienceMatches(float contactAffinity) {
switch (mConfig.allowFrom) { switch (mConfig.allowFrom) {
case ZenModeConfig.SOURCE_ANYONE: case ZenModeConfig.SOURCE_ANYONE:
@ -413,13 +474,6 @@ public class ZenModeHelper {
} }
} }
private final Runnable mRingerModeChanged = new Runnable() {
@Override
public void run() {
handleRingerModeChanged();
}
};
private class SettingsObserver extends ContentObserver { private class SettingsObserver extends ContentObserver {
private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE); private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE);
@ -445,12 +499,26 @@ public class ZenModeHelper {
} }
} }
private final BroadcastReceiver mReceiver = new BroadcastReceiver() { private class H extends Handler {
@Override private static final int MSG_SET_ZEN = 1;
public void onReceive(Context context, Intent intent) {
mHandler.post(mRingerModeChanged); private H(Looper looper) {
super(looper);
} }
};
private void postSetZenMode(int zen, String reason) {
obtainMessage(MSG_SET_ZEN, zen, 0, reason).sendToTarget();
}
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case MSG_SET_ZEN:
setZenMode(msg.arg1, (String) msg.obj);
break;
}
}
}
public static class Callback { public static class Callback {
void onConfigChanged() {} void onConfigChanged() {}