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;
/**
* 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);
}
@ -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.
*

View File

@ -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);
}
}

View File

@ -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);
}
}
//==========================================================================================

View File

@ -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);

View File

@ -34,4 +34,6 @@ oneway interface IVolumeController {
void setLayoutDirection(int layoutDirection);
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() {
KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
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);
boolean zenVisible = false;
@ -230,7 +230,7 @@ public class PhoneStatusBarPolicy {
}
if (mZen != Global.ZEN_MODE_NO_INTERRUPTIONS &&
audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
volumeVisible = true;
volumeIconId = R.drawable.stat_sys_ringer_vibrate;
volumeDescription = mContext.getString(R.string.accessibility_ringer_vibrate);

View File

@ -157,8 +157,9 @@ public class ZenModeControllerImpl implements ZenModeController {
if (mRegistered) {
mContext.unregisterReceiver(mReceiver);
}
mContext.registerReceiverAsUser(mReceiver, new UserHandle(mUserId),
new IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED), null, null);
final IntentFilter filter = new IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
mContext.registerReceiverAsUser(mReceiver, new UserHandle(mUserId), filter, null, null);
mRegistered = true;
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_USER_ACTIVITY = 14;
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
private static final int STREAM_MASTER = -100;
@ -169,6 +171,8 @@ public class VolumePanel extends Handler implements DemoMode {
private final ViewGroup mSliderPanel;
/** The zen mode configuration panel view */
private ZenModePanel mZenPanel;
/** The component currently suppressing notification stream effects */
private ComponentName mNotificationEffectsSuppressor;
private Callback mCallback;
@ -178,6 +182,7 @@ public class VolumePanel extends Handler implements DemoMode {
private SparseArray<StreamControl> mStreamControls;
private final AccessibilityManager mAccessibilityManager;
private final SecondaryIconTransition mSecondaryIconTransition;
private final IconPulser mIconPulser;
private enum StreamResources {
BluetoothSCOStream(AudioManager.STREAM_BLUETOOTH_SCO,
@ -188,7 +193,7 @@ public class VolumePanel extends Handler implements DemoMode {
RingerStream(AudioManager.STREAM_RING,
R.string.volume_icon_description_ringer,
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),
VoiceStream(AudioManager.STREAM_VOICE_CALL,
R.string.volume_icon_description_incall,
@ -208,7 +213,7 @@ public class VolumePanel extends Handler implements DemoMode {
NotificationStream(AudioManager.STREAM_NOTIFICATION,
R.string.volume_icon_description_notification,
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),
// for now, use media resources for master volume
MasterStream(STREAM_MASTER,
@ -268,6 +273,7 @@ public class VolumePanel extends Handler implements DemoMode {
// Synchronize when accessing this
private ToneGenerator mToneGenerators[];
private Vibrator mVibrator;
private boolean mHasVibrator;
private static AlertDialog sSafetyWarning;
private static Object sSafetyWarningLock = new Object();
@ -354,6 +360,7 @@ public class VolumePanel extends Handler implements DemoMode {
mAccessibilityManager = (AccessibilityManager) context.getSystemService(
Context.ACCESSIBILITY_SERVICE);
mSecondaryIconTransition = new SecondaryIconTransition();
mIconPulser = new IconPulser(context);
// For now, only show master volume if master volume is supported
final Resources res = context.getResources();
@ -435,10 +442,12 @@ public class VolumePanel extends Handler implements DemoMode {
mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
if (mZenController != null && !useMasterVolume) {
mZenModeAvailable = mZenController.isZenAvailable();
mNotificationEffectsSuppressor = mZenController.getEffectsSuppressor();
mZenController.addCallback(mZenCallback);
}
@ -470,8 +479,10 @@ public class VolumePanel extends Handler implements DemoMode {
pw.print(" mTag="); pw.println(mTag);
pw.print(" mRingIsSilent="); pw.println(mRingIsSilent);
pw.print(" mVoiceCapable="); pw.println(mVoiceCapable);
pw.print(" mHasVibrator="); pw.println(mHasVibrator);
pw.print(" mZenModeAvailable="); pw.println(mZenModeAvailable);
pw.print(" mZenPanelExpanded="); pw.println(mZenPanelExpanded);
pw.print(" mNotificationEffectsSuppressor="); pw.println(mNotificationEffectsSuppressor);
pw.print(" mTimeoutDelay="); pw.println(mTimeoutDelay);
pw.print(" mDisabledAlpha="); pw.println(mDisabledAlpha);
pw.print(" mLastRingerMode="); pw.println(mLastRingerMode);
@ -639,16 +650,19 @@ public class VolumePanel extends Handler implements DemoMode {
sc.iconRes = streamRes.iconRes;
sc.iconMuteRes = streamRes.iconMuteRes;
sc.icon.setImageResource(sc.iconRes);
sc.icon.setClickable(isNotification);
sc.icon.setClickable(isNotification && mHasVibrator);
if (isNotification) {
sc.icon.setSoundEffectsEnabled(false);
sc.icon.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
resetTimeout();
toggle(sc);
}
});
if (mHasVibrator) {
sc.icon.setSoundEffectsEnabled(false);
sc.iconMuteRes = com.android.systemui.R.drawable.ic_ringer_vibrate;
sc.icon.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
resetTimeout();
toggleRinger(sc);
}
});
}
sc.iconSuppressedRes = com.android.systemui.R.drawable.ic_ringer_mute;
}
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) {
if (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL) {
mAudioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
private void toggleRinger(StreamControl sc) {
if (!mHasVibrator) return;
if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL) {
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_VIBRATE);
postVolumeChanged(sc.streamType, AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE);
} else {
mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL);
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) {
final boolean isRinger = isNotificationOrRing(sc.streamType);
if (isRinger && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
if (isRinger && mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) {
progress = mLastRingerProgress;
}
if (progress < 0) {
@ -723,21 +738,30 @@ public class VolumePanel extends Handler implements DemoMode {
}
private void updateSliderIcon(StreamControl sc, boolean muted) {
ComponentName suppressor = null;
if (isNotificationOrRing(sc.streamType)) {
int ringerMode = mAudioManager.getRingerMode();
suppressor = mNotificationEffectsSuppressor;
int ringerMode = mAudioManager.getRingerModeInternal();
if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
ringerMode = mLastRingerMode;
} else {
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)
? mZenController.getEffectsSuppressor() : null;
? mNotificationEffectsSuppressor : null;
if (suppressor == null) {
sc.seekbarView.setVisibility(View.VISIBLE);
sc.suppressorView.setVisibility(View.GONE);
@ -746,7 +770,6 @@ public class VolumePanel extends Handler implements DemoMode {
sc.suppressorView.setVisibility(View.VISIBLE);
sc.suppressorView.setText(mContext.getString(R.string.muted_by,
getSuppressorCaption(suppressor)));
sc.icon.setImageResource(sc.iconSuppressedRes);
}
}
@ -777,7 +800,7 @@ public class VolumePanel extends Handler implements DemoMode {
sc.icon.setImageDrawable(null);
updateSliderIcon(sc, muted);
updateSliderEnabled(sc, muted, false);
updateSliderSupressor(sc);
updateSliderSuppressor(sc);
}
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
// the state of the phone.
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.icon.setEnabled(false);
sc.icon.setAlpha(mDisabledAlpha);
@ -805,7 +833,7 @@ public class VolumePanel extends Handler implements DemoMode {
if (isRinger && wasEnabled != sc.seekbarView.isEnabled()) {
if (sc.seekbarView.isEnabled()) {
sc.group.setOnTouchListener(null);
sc.icon.setClickable(true);
sc.icon.setClickable(mHasVibrator);
} else {
final View.OnTouchListener showHintOnTouch = new View.OnTouchListener() {
@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) {
return streamType == AudioManager.STREAM_RING
|| streamType == AudioManager.STREAM_NOTIFICATION;
@ -953,6 +991,19 @@ public class VolumePanel extends Handler implements DemoMode {
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
* 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) {
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) {
synchronized (this) {
@ -989,7 +1041,8 @@ public class VolumePanel extends Handler implements DemoMode {
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);
if (sc != null) {
@ -1005,8 +1058,8 @@ public class VolumePanel extends Handler implements DemoMode {
mRingIsSilent = false;
if (LOGD) {
Log.d(mTag, "onShowVolumeChanged(streamType: " + streamType
+ ", flags: " + flags + "), index: " + index);
Log.d(mTag, "onShowVolumeChanged(streamType: " + streamToString(streamType)
+ ", flags: " + flagsToString(flags) + "), index: " + index);
}
// get max volume for progress bar
@ -1017,7 +1070,6 @@ public class VolumePanel extends Handler implements DemoMode {
switch (streamType) {
case AudioManager.STREAM_RING: {
// setRingerIcon();
Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
mContext, RingtoneManager.TYPE_RINGTONE);
if (ringuri == null) {
@ -1110,13 +1162,16 @@ public class VolumePanel extends Handler implements DemoMode {
sc.seekbarView.setMax(max);
}
updateSliderProgress(sc, index);
updateSliderEnabled(sc, isMuted(streamType),
(flags & AudioManager.FLAG_FIXED_VOLUME) != 0);
// check for secondary-icon transition completion
if (isNotificationOrRing(streamType) && mSecondaryIconTransition.isRunning()) {
mSecondaryIconTransition.cancel(); // safe to reset
sc.seekbarView.setAlpha(0); sc.seekbarView.animate().alpha(1);
mZenPanel.setAlpha(0); mZenPanel.animate().alpha(1);
final boolean muted = isMuted(streamType);
updateSliderEnabled(sc, muted, (flags & AudioManager.FLAG_FIXED_VOLUME) != 0);
if (isNotificationOrRing(streamType)) {
// check for secondary-icon transition completion
if (mSecondaryIconTransition.isRunning()) {
mSecondaryIconTransition.cancel(); // safe to reset
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)
if ((streamType != STREAM_REMOTE_MUSIC) &&
((flags & AudioManager.FLAG_VIBRATE) != 0) &&
mAudioManager.isStreamAffectedByRingerMode(streamType) &&
mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
isNotificationOrRing(streamType) &&
mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
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) {
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() {
@ -1186,16 +1246,17 @@ public class VolumePanel extends Handler implements DemoMode {
protected void onVibrate() {
// Make sure we ended up in vibrate ringer mode
if (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_VIBRATE) {
if (mAudioManager.getRingerModeInternal() != AudioManager.RINGER_MODE_VIBRATE) {
return;
}
mVibrator.vibrate(VIBRATE_DURATION, VIBRATION_ATTRIBUTES);
if (mVibrator != null) {
mVibrator.vibrate(VIBRATE_DURATION, VIBRATION_ATTRIBUTES);
}
}
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()) {
synchronized (this) {
@ -1385,7 +1446,9 @@ public class VolumePanel extends Handler implements DemoMode {
break;
}
case MSG_ZEN_MODE_CHANGED:
case MSG_RINGER_MODE_CHANGED:
case MSG_INTERNAL_RINGER_MODE_CHANGED:
case MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED: {
if (isShowing()) {
updateStates();
@ -1491,10 +1554,15 @@ public class VolumePanel extends Handler implements DemoMode {
public void onZenAvailableChanged(boolean available) {
obtainMessage(MSG_ZEN_MODE_AVAILABLE_CHANGED, available ? 1 : 0, 0).sendToTarget();
}
@Override
public void onEffectsSupressorChanged() {
obtainMessage(MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED,
mZenController.getEffectsSuppressor()).sendToTarget();
mNotificationEffectsSuppressor = mZenController.getEffectsSuppressor();
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();
}
@Override
public void internalRingerModeChanged(int mode) throws RemoteException {
mPanel.postInternalRingerModeChanged(mode);
final PhoneStatusBar psb = getComponent(PhoneStatusBar.class);
if (psb != null) {
psb.onInternalRingerModeChanged();
}
}
@Override
public ZenModeController getZenController() {
return mPanel.getZenController();

View File

@ -16,8 +16,6 @@
package com.android.systemui.volume;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
@ -38,8 +36,6 @@ import android.util.Log;
import android.util.MathUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
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 TIME_CONDITION_INDEX = 1;
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;
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 H mHandler = new H();
private final Prefs mPrefs;
private final Interpolator mFastOutSlowInInterpolator;
private final IconPulser mIconPulser;
private final int mSubheadWarningColor;
private final int mSubheadColor;
@ -110,8 +105,7 @@ public class ZenModePanel extends LinearLayout {
mContext = context;
mPrefs = new Prefs();
mInflater = LayoutInflater.from(mContext.getApplicationContext());
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(mContext,
android.R.interpolator.fast_out_slow_in);
mIconPulser = new IconPulser(mContext);
final Resources res = mContext.getResources();
mSubheadWarningColor = res.getColor(R.color.system_warning_color);
mSubheadColor = res.getColor(R.color.qs_subhead);
@ -283,16 +277,7 @@ public class ZenModePanel extends LinearLayout {
if (DEBUG) Log.d(mTag, "showSilentHint");
if (mZenButtons == null || mZenButtons.getChildCount() == 0) return;
final View noneButton = mZenButtons.getChildAt(0);
if (noneButton.getScaleX() != 1) return; // already running
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);
}
});
mIconPulser.start(noneButton);
}
private void handleUpdateZen(int zen) {

View File

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

View File

@ -46,15 +46,15 @@ public class ZenLog {
private static final int TYPE_INTERCEPTED = 1;
private static final int TYPE_ALLOW_DISABLE = 2;
private static final int TYPE_SET_RINGER_MODE = 3;
private static final int TYPE_DOWNTIME = 4;
private static final int TYPE_SET_ZEN_MODE = 5;
private static final int TYPE_UPDATE_ZEN_MODE = 6;
private static final int TYPE_EXIT_CONDITION = 7;
private static final int TYPE_SUBSCRIBE = 8;
private static final int TYPE_UNSUBSCRIBE = 9;
private static final int TYPE_CONFIG = 10;
private static final int TYPE_FOLLOW_RINGER_MODE = 11;
private static final int TYPE_SET_RINGER_MODE_EXTERNAL = 3;
private static final int TYPE_SET_RINGER_MODE_INTERNAL = 4;
private static final int TYPE_DOWNTIME = 5;
private static final int TYPE_SET_ZEN_MODE = 6;
private static final int TYPE_UPDATE_ZEN_MODE = 7;
private static final int TYPE_EXIT_CONDITION = 8;
private static final int TYPE_SUBSCRIBE = 9;
private static final int TYPE_UNSUBSCRIBE = 10;
private static final int TYPE_CONFIG = 11;
private static final int TYPE_NOT_INTERCEPTED = 12;
private static final int TYPE_DISABLE_EFFECTS = 13;
@ -71,8 +71,22 @@ public class ZenLog {
append(TYPE_NOT_INTERCEPTED, record.getKey() + "," + reason);
}
public static void traceSetRingerMode(int ringerMode) {
append(TYPE_SET_RINGER_MODE, ringerModeToString(ringerMode));
public static void traceSetRingerModeExternal(int ringerModeOld, int ringerModeNew,
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) {
@ -103,11 +117,6 @@ public class ZenLog {
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) {
append(TYPE_DISABLE_EFFECTS, record.getKey() + "," + reason);
}
@ -120,7 +129,8 @@ public class ZenLog {
switch (type) {
case TYPE_INTERCEPTED: return "intercepted";
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_SET_ZEN_MODE: return "set_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_UNSUBSCRIBE: return "unsubscribe";
case TYPE_CONFIG: return "config";
case TYPE_FOLLOW_RINGER_MODE: return "follow_ringer_mode";
case TYPE_NOT_INTERCEPTED: return "not_intercepted";
case TYPE_DISABLE_EFFECTS: return "disable_effects";
default: return "unknown";

View File

@ -21,20 +21,20 @@ import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
import android.app.AppOpsManager;
import android.app.Notification;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.database.ContentObserver;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.UserHandle;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
@ -45,6 +45,7 @@ import android.util.Log;
import android.util.Slog;
import com.android.internal.R;
import com.android.server.LocalServices;
import libcore.io.IoUtils;
@ -60,12 +61,12 @@ import java.util.Objects;
/**
* 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 boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final Context mContext;
private final Handler mHandler;
private final H mHandler;
private final SettingsObserver mSettingsObserver;
private final AppOpsManager mAppOps;
private final ZenModeConfig mDefaultConfig;
@ -74,21 +75,17 @@ public class ZenModeHelper {
private ComponentName mDefaultPhoneApp;
private int mZenMode;
private ZenModeConfig mConfig;
private AudioManager mAudioManager;
private AudioManagerInternal mAudioManager;
private int mPreviousRingerMode = -1;
public ZenModeHelper(Context context, Handler handler) {
public ZenModeHelper(Context context, Looper looper) {
mContext = context;
mHandler = handler;
mHandler = new H(looper);
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mDefaultConfig = readDefaultConfig(context.getResources());
mConfig = mDefaultConfig;
mSettingsObserver = new SettingsObserver(mHandler);
mSettingsObserver.observe();
final IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
mContext.registerReceiver(mReceiver, filter);
}
public static ZenModeConfig readDefaultConfig(Resources resources) {
@ -111,8 +108,11 @@ public class ZenModeHelper {
mCallbacks.add(callback);
}
public void setAudioManager(AudioManager audioManager) {
mAudioManager = audioManager;
public void onSystemReady() {
mAudioManager = LocalServices.getService(AudioManagerInternal.class);
if (mAudioManager != null) {
mAudioManager.setRingerModeDelegate(this);
}
}
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);
if (newZen != -1) {
setZenMode(newZen, "listener");
setZenMode(newZen, "listener:" + (name != null ? name.flattenToShortString() : null));
}
}
@ -214,12 +214,13 @@ public class ZenModeHelper {
}
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);
if (mode != mZenMode) {
ZenLog.traceUpdateZenMode(mZenMode, mode);
if (oldMode != newMode) {
ZenLog.traceUpdateZenMode(oldMode, newMode);
}
mZenMode = mode;
mZenMode = newMode;
final boolean zen = mZenMode != Global.ZEN_MODE_OFF;
final String[] exceptionPackages = null; // none (for now)
@ -241,29 +242,7 @@ public class ZenModeHelper {
muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
exceptionPackages);
// force ringer mode into compliance
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);
}
}
onZenUpdated(oldMode, newMode);
dispatchOnZenModeChanged();
}
@ -303,25 +282,102 @@ public class ZenModeHelper {
return true;
}
private void handleRingerModeChanged() {
if (mAudioManager != null) {
// follow ringer mode if necessary
final int ringerMode = mAudioManager.getRingerMode();
int newZen = -1;
if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
if (mZenMode == Global.ZEN_MODE_OFF) {
newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
private void onZenUpdated(int oldZen, int newZen) {
if (mAudioManager == null) return;
if (oldZen == newZen) return;
// force the ringer mode into compliance
final int ringerModeInternal = mAudioManager.getRingerModeInternal();
int newRingerModeInternal = ringerModeInternal;
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
|| ringerMode == AudioManager.RINGER_MODE_VIBRATE)
&& mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
newZen = Global.ZEN_MODE_OFF;
}
if (newZen != -1) {
ZenLog.traceFollowRingerMode(ringerMode, mZenMode, newZen);
setZenMode(newZen, "ringerMode");
}
break;
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
case Global.ZEN_MODE_OFF:
if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) {
newRingerModeInternal = mPreviousRingerMode != -1 ? mPreviousRingerMode
: AudioManager.RINGER_MODE_NORMAL;
mPreviousRingerMode = -1;
}
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() {
@ -399,6 +455,11 @@ public class ZenModeHelper {
return true;
}
@Override
public String toString() {
return TAG;
}
private boolean audienceMatches(float contactAffinity) {
switch (mConfig.allowFrom) {
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 final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE);
@ -445,12 +499,26 @@ public class ZenModeHelper {
}
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mHandler.post(mRingerModeChanged);
private class H extends Handler {
private static final int MSG_SET_ZEN = 1;
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 {
void onConfigChanged() {}