这里添加的模式可能涉及的地方不全面,目前把已知的地方都加上。可以搜索ZEN_MODE_ALARMS来看看哪里还需要加代码。目前就改了这些地方,有些地方不知道有什么用,可能只是log信息,有些是显示的图标,根据不同模式显示不同icon。
1.在QS中添加选项
打开关闭DND是在quick settings中的,当然也可以按音量下。我们这要在QS中添加,可以按照其他dnd模式来添加代码。
先加数据库。
frameworks/base/core/java/android/provider/Settings.java
/**
* Defines global zen mode. ZEN_MODE_OFF, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
* or ZEN_MODE_NO_INTERRUPTIONS.
*
* @hide
*/
public static final String ZEN_MODE = "zen_mode";
/** @hide */ public static final int ZEN_MODE_OFF = 0;
/** @hide */ public static final int ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1;
/** @hide */ public static final int ZEN_MODE_NO_INTERRUPTIONS = 2;
/** @hide */ public static final int ZEN_MODE_ALARMS = 3;
/** @hide */ public static final int ZEN_MODE_GAME = 4;
/** @hide */ public static String zenModeToString(int mode) {
if (mode == ZEN_MODE_IMPORTANT_INTERRUPTIONS) return "ZEN_MODE_IMPORTANT_INTERRUPTIONS";
if (mode == ZEN_MODE_ALARMS) return "ZEN_MODE_ALARMS";
if (mode == ZEN_MODE_NO_INTERRUPTIONS) return "ZEN_MODE_NO_INTERRUPTIONS";
if (mode == ZEN_MODE_GAME) return "ZEN_MODE_GAME";
return "ZEN_MODE_OFF";
}
/** @hide */ public static boolean isValidZenMode(int value) {
switch (value) {
case Global.ZEN_MODE_OFF:
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
case Global.ZEN_MODE_ALARMS:
case Global.ZEN_MODE_NO_INTERRUPTIONS:
case Global.ZEN_MODE_GAME:
return true;
default:
return false;
}
}
然后添加QS
frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
final boolean newValue = zen != ZEN_MODE_OFF;
final boolean valueChanged = state.value != newValue;
state.dualTarget = true;
state.value = newValue;
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
switch (zen) {
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
state.label = mContext.getString(R.string.quick_settings_dnd_priority_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_dnd_priority_on);
break;
case Global.ZEN_MODE_NO_INTERRUPTIONS:
state.icon = TOTAL_SILENCE;
state.label = mContext.getString(R.string.quick_settings_dnd_none_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_dnd_none_on);
break;
case ZEN_MODE_ALARMS:
state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
state.label = mContext.getString(R.string.quick_settings_dnd_alarms_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_dnd_alarms_on);
break;
case Global.ZEN_MODE_GAME:
state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
state.label = mContext.getString(R.string.quick_settings_dnd_game_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_dnd_game_on);
break;
default:
state.icon = TOTAL_SILENCE.equals(state.icon) ? mDisableTotalSilence : mDisable;
state.label = mContext.getString(R.string.quick_settings_dnd_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_dnd);
break;
}
if (valueChanged) {
fireToggleStateChanged(state.value);
}
state.dualLabelContentDescription = mContext.getResources().getString(
R.string.accessibility_quick_settings_open_settings, getTileLabel());
state.expandedAccessibilityClassName = Switch.class.getName();
}
这里添加的是QS中显示的,也就是dnd没有展开时的。
当你点击dnd下面的那个箭头就会展开,和蓝牙类似。下面就是展开的画面。最上面的按钮就是mZenButtons,下面是第一次使用会有个介绍mZenIntroduction,就是绿色的框边上有个x关闭。
代码位置在
frameworks/base/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
这里只需要模仿其他dnd模式来添加代码。
public class ZenModePanel extends FrameLayout {
private static final String TAG = "ZenModePanel";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final int STATE_MODIFY = 0;
public static final int STATE_AUTO_RULE = 1;
public static final int STATE_OFF = 2;
private static final int SECONDS_MS = 1000;
private static final int MINUTES_MS = 60 * SECONDS_MS;
private static final int[] MINUTE_BUCKETS = ZenModeConfig.MINUTE_BUCKETS;
private static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0];
private static final int MAX_BUCKET_MINUTES = MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
private static final int FOREVER_CONDITION_INDEX = 0;
private static final int COUNTDOWN_CONDITION_INDEX = 1;
private static final int COUNTDOWN_ALARM_CONDITION_INDEX = 2;
private static final int COUNTDOWN_CONDITION_COUNT = 2;
public static final Intent ZEN_SETTINGS
= new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
public static final Intent ZEN_PRIORITY_SETTINGS
= new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS);
private static final long TRANSITION_DURATION = 300;
private final Context mContext;
protected final LayoutInflater mInflater;
private final H mHandler = new H();
private final ZenPrefs mPrefs;
private final TransitionHelper mTransitionHelper = new TransitionHelper();
private final Uri mForeverId;
private final ConfigurableTexts mConfigurableTexts;
private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
protected SegmentedButtons mZenButtons;
private View mZenIntroduction;
private TextView mZenIntroductionMessage;
private View mZenIntroductionConfirm;
private TextView mZenIntroductionCustomize;
protected LinearLayout mZenConditions;
private TextView mZenAlarmWarning;
private RadioGroup mZenRadioGroup;
private LinearLayout mZenRadioGroupContent;
private Callback mCallback;
private ZenModeController mController;
private boolean mCountdownConditionSupported;
private boolean mRequestingConditions;
private Condition mExitCondition;
private int mBucketIndex = -1;
private boolean mExpanded;
private boolean mHidden;
private int mSessionZen;
private int mAttachedZen;
private boolean mAttached;
private Condition mSessionExitCondition;
private Condition[] mConditions;
private Condition mTimeCondition;
private boolean mVoiceCapable;
protected int mZenModeConditionLayoutId;
protected int mZenModeButtonLayoutId;
private View mEmpty;
private TextView mEmptyText;
private ImageView mEmptyIcon;
private View mAutoRule;
private TextView mAutoTitle;
private int mState = STATE_MODIFY;
private ViewGroup mEdit;
public ZenModePanel(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
mPrefs = new ZenPrefs();
mInflater = LayoutInflater.from(mContext.getApplicationContext());
mForeverId = Condition.newId(mContext).appendPath("forever").build();
mConfigurableTexts = new ConfigurableTexts(mContext);
mVoiceCapable = Util.isVoiceCapable(mContext);
mZenModeConditionLayoutId = R.layout.zen_mode_condition;
mZenModeButtonLayoutId = R.layout.zen_mode_button;
if (DEBUG) Log.d(mTag, "new ZenModePanel");
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("ZenModePanel state:");
pw.print(" mCountdownConditionSupported="); pw.println(mCountdownConditionSupported);
pw.print(" mRequestingConditions="); pw.println(mRequestingConditions);
pw.print(" mAttached="); pw.println(mAttached);
pw.print(" mHidden="); pw.println(mHidden);
pw.print(" mExpanded="); pw.println(mExpanded);
pw.print(" mSessionZen="); pw.println(mSessionZen);
pw.print(" mAttachedZen="); pw.println(mAttachedZen);
pw.print(" mConfirmedPriorityIntroduction=");
pw.println(mPrefs.mConfirmedPriorityIntroduction);
pw.print(" mConfirmedSilenceIntroduction=");
pw.println(mPrefs.mConfirmedSilenceIntroduction);
pw.print(" mVoiceCapable="); pw.println(mVoiceCapable);
mTransitionHelper.dump(fd, pw, args);
}
protected void createZenButtons() {
mZenButtons = findViewById(R.id.zen_buttons);
mZenButtons.addButton(R.string.interruption_level_none_twoline,
R.string.interruption_level_none_with_warning,
Global.ZEN_MODE_NO_INTERRUPTIONS);
mZenButtons.addButton(R.string.interruption_level_game_twoline,
R.string.interruption_level_game,
Global.ZEN_MODE_GAME);
mZenButtons.addButton(R.string.interruption_level_alarms_twoline,
R.string.interruption_level_alarms,
Global.ZEN_MODE_ALARMS);
mZenButtons.addButton(R.string.interruption_level_priority_twoline,
R.string.interruption_level_priority,
Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
mZenButtons.setCallback(mZenButtonsCallback);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
createZenButtons();
mZenIntroduction = findViewById(R.id.zen_introduction);
mZenIntroductionMessage = findViewById(R.id.zen_introduction_message);
mZenIntroductionConfirm = findViewById(R.id.zen_introduction_confirm);
mZenIntroductionConfirm.setOnClickListener(v -> confirmZenIntroduction());
mZenIntroductionCustomize = findViewById(R.id.zen_introduction_customize);
mZenIntroductionCustomize.setOnClickListener(v -> {
confirmZenIntroduction();
if (mCallback != null) {
mCallback.onPrioritySettings();
}
});
mConfigurableTexts.add(mZenIntroductionCustomize, R.string.zen_priority_customize_button);
mZenConditions = findViewById(R.id.zen_conditions);
mZenAlarmWarning = findViewById(R.id.zen_alarm_warning);
mZenRadioGroup = findViewById(R.id.zen_radio_buttons);
mZenRadioGroupContent = findViewById(R.id.zen_radio_buttons_content);
mEdit = findViewById(R.id.edit_container);
mEmpty = findViewById(android.R.id.empty);
mEmpty.setVisibility(INVISIBLE);
mEmptyText = mEmpty.findViewById(android.R.id.title);
mEmptyIcon = mEmpty.findViewById(android.R.id.icon);
mAutoRule = findViewById(R.id.auto_rule);
mAutoTitle = mAutoRule.findViewById(android.R.id.title);
mAutoRule.setVisibility(INVISIBLE);
}
private View getView(int state) {
switch (state) {
case STATE_AUTO_RULE:
return mAutoRule;
case STATE_OFF:
return mEmpty;
default:
return mEdit;
}
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mConfigurableTexts.update();
if (mZenButtons != null) {
mZenButtons.update();
}
}
private void confirmZenIntroduction() {
final String prefKey = prefKeyForConfirmation(getSelectedZen(Global.ZEN_MODE_OFF));
if (prefKey == null) return;
if (DEBUG) Log.d(TAG, "confirmZenIntroduction " + prefKey);
Prefs.putBoolean(mContext, prefKey, true);
mHandler.sendEmptyMessage(H.UPDATE_WIDGETS);
}
private static String prefKeyForConfirmation(int zen) {
switch (zen) {
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
return Prefs.Key.DND_CONFIRMED_PRIORITY_INTRODUCTION;
case Global.ZEN_MODE_NO_INTERRUPTIONS:
return Prefs.Key.DND_CONFIRMED_SILENCE_INTRODUCTION;
case Global.ZEN_MODE_ALARMS:
return Prefs.Key.DND_CONFIRMED_ALARM_INTRODUCTION;
case Global.ZEN_MODE_GAME:
return Prefs.Key.DND_CONFIRMED_GAME_INTRODUCTION;
default:
return null;
}
}
private void onAttach() {
setExpanded(true);
mAttached = true;
mAttachedZen = mController.getZen();
ZenRule manualRule = mController.getManualRule();
mExitCondition = manualRule != null ? manualRule.condition : null;
if (DEBUG) Log.d(mTag, "onAttach " + mAttachedZen + " " + manualRule);
handleUpdateManualRule(manualRule);
mZenButtons.setSelectedValue(mAttachedZen, false);
mSessionZen = mAttachedZen;
mTransitionHelper.clear();
mController.addCallback(mZenCallback);
setSessionExitCondition(copy(mExitCondition));
updateWidgets();
setRequestingConditions(!mHidden);
ensureSelection();
}
private void onDetach() {
if (DEBUG) Log.d(mTag, "onDetach");
setExpanded(false);
checkForAttachedZenChange();
mAttached = false;
mAttachedZen = -1;
mSessionZen = -1;
mController.removeCallback(mZenCallback);
setSessionExitCondition(null);
setRequestingConditions(false);
mTransitionHelper.clear();
}
@Override
public void onVisibilityAggregated(boolean isVisible) {
super.onVisibilityAggregated(isVisible);
if (isVisible == mAttached) return;
if (isVisible) {
onAttach();
} else {
onDetach();
}
}
private void setSessionExitCondition(Condition condition) {
if (Objects.equals(condition, mSessionExitCondition)) return;
if (DEBUG) Log.d(mTag, "mSessionExitCondition=" + getConditionId(condition));
mSessionExitCondition = condition;
}
public void setHidden(boolean hidden) {
if (mHidden == hidden) return;
if (DEBUG) Log.d(mTag, "hidden=" + hidden);
mHidden = hidden;
setRequestingConditions(mAttached && !mHidden);
updateWidgets();
}
private void checkForAttachedZenChange() {
final int selectedZen = getSelectedZen(-1);
if (DEBUG) Log.d(mTag, "selectedZen=" + selectedZen);
if (selectedZen != mAttachedZen) {
if (DEBUG) Log.d(mTag, "attachedZen: " + mAttachedZen + " -> " + selectedZen);
if (selectedZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
mPrefs.trackNoneSelected();
}
}
}
private void setExpanded(boolean expanded) {
if (expanded == mExpanded) return;
if (DEBUG) Log.d(mTag, "setExpanded " + expanded);
mExpanded = expanded;
updateWidgets();
fireExpanded();
}
/** Start or stop requesting relevant zen mode exit conditions */
private void setRequestingConditions(final boolean requesting) {
if (mRequestingConditions == requesting) return;
if (DEBUG) Log.d(mTag, "setRequestingConditions " + requesting);
mRequestingConditions = requesting;
if (mRequestingConditions) {
mTimeCondition = parseExistingTimeCondition(mContext, mExitCondition);
if (mTimeCondition != null) {
mBucketIndex = -1;
} else {
mBucketIndex = DEFAULT_BUCKET_INDEX;
mTimeCondition = ZenModeConfig.toTimeCondition(mContext,
MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
}
if (DEBUG) Log.d(mTag, "Initial bucket index: " + mBucketIndex);
mConditions = null; // reset conditions
handleUpdateConditions();
} else {
hideAllConditions();
}
}
protected void addZenConditions(int count) {
for (int i = 0; i < count; i++) {
final View rb = mInflater.inflate(mZenModeButtonLayoutId, mEdit, false);
rb.setId(i);
mZenRadioGroup.addView(rb);
final View rbc = mInflater.inflate(mZenModeConditionLayoutId, mEdit, false);
rbc.setId(i + count);
mZenRadioGroupContent.addView(rbc);
}
}
public void init(ZenModeController controller) {
mController = controller;
mCountdownConditionSupported = mController.isCountdownConditionSupported();
final int countdownDelta = mCountdownConditionSupported ? COUNTDOWN_CONDITION_COUNT : 0;
final int minConditions = 1 /*forever*/ + countdownDelta;
addZenConditions(minConditions);
mSessionZen = getSelectedZen(-1);
handleUpdateManualRule(mController.getManualRule());
if (DEBUG) Log.d(mTag, "init mExitCondition=" + mExitCondition);
hideAllConditions();
}
private void setExitCondition(Condition exitCondition) {
if (Objects.equals(mExitCondition, exitCondition)) return;
mExitCondition = exitCondition;
if (DEBUG) Log.d(mTag, "mExitCondition=" + getConditionId(mExitCondition));
updateWidgets();
}
private static Uri getConditionId(Condition condition) {
return condition != null ? condition.id : null;
}
private Uri getRealConditionId(Condition condition) {
return isForever(condition) ? null : getConditionId(condition);
}
private static boolean sameConditionId(Condition lhs, Condition rhs) {
return lhs == null ? rhs == null : rhs != null && lhs.id.equals(rhs.id);
}
private static Condition copy(Condition condition) {
return condition == null ? null : condition.copy();
}
public void setCallback(Callback callback) {
mCallback = callback;
}
private void handleUpdateManualRule(ZenRule rule) {
final int zen = rule != null ? rule.zenMode : Global.ZEN_MODE_OFF;
handleUpdateZen(zen);
final Condition c = rule == null ? null
: rule.condition != null ? rule.condition
: createCondition(rule.conditionId);
handleExitConditionChanged(c);
}
private Condition createCondition(Uri conditionId) {
if (ZenModeConfig.isValidCountdownConditionId(conditionId)) {
long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
int mins = (int) ((time - System.currentTimeMillis() + DateUtils.MINUTE_IN_MILLIS / 2)
/ DateUtils.MINUTE_IN_MILLIS);
Condition c = ZenModeConfig.toTimeCondition(mContext, time, mins,
ActivityManager.getCurrentUser(), false);
return c;
}
// If there is a manual rule, but it has no condition listed then it is forever.
return forever();
}
private void handleUpdateZen(int zen) {
if (mSessionZen != -1 && mSessionZen != zen) {
mSessionZen = zen;
}
mZenButtons.setSelectedValue(zen, false /* fromClick */);
updateWidgets();
handleUpdateConditions();
if (mExpanded) {
final Condition selected = getSelectedCondition();
if (!Objects.equals(mExitCondition, selected)) {
select(selected);
}
}
}
private void handleExitConditionChanged(Condition exitCondition) {
setExitCondition(exitCondition);
if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitCondition);
if (exitCondition == null) return;
final int N = getVisibleConditions();
for (int i = 0; i < N; i++) {
final ConditionTag tag = getConditionTagAt(i);
if (tag != null && sameConditionId(tag.condition, mExitCondition)) {
bind(exitCondition, mZenRadioGroupContent.getChildAt(i), i);
tag.rb.setChecked(true);
return;
}
}
if (mCountdownConditionSupported && ZenModeConfig.isValidCountdownConditionId(
exitCondition.id)) {
bind(exitCondition, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
COUNTDOWN_CONDITION_INDEX);
getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb.setChecked(true);
}
}
private Condition getSelectedCondition() {
final int N = getVisibleConditions();
for (int i = 0; i < N; i++) {
final ConditionTag tag = getConditionTagAt(i);
if (tag != null && tag.rb.isChecked()) {
return tag.condition;
}
}
return null;
}
private int getSelectedZen(int defValue) {
final Object zen = mZenButtons.getSelectedValue();
return zen != null ? (Integer) zen : defValue;
}
private void updateWidgets() {
if (mTransitionHelper.isTransitioning()) {
mTransitionHelper.pendingUpdateWidgets();
return;
}
final int zen = getSelectedZen(Global.ZEN_MODE_OFF);
final boolean zenImportant = zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS;
final boolean zenAlarm = zen == Global.ZEN_MODE_ALARMS;
final boolean zenGame = zen == Global.ZEN_MODE_GAME;
final boolean introduction = (zenImportant && !mPrefs.mConfirmedPriorityIntroduction
|| zenNone && !mPrefs.mConfirmedSilenceIntroduction
|| zenAlarm && !mPrefs.mConfirmedAlarmIntroduction
|| zenGame && !mPrefs.mConfirmedGameIntroduction);
mZenButtons.setVisibility(mHidden ? GONE : VISIBLE);
mZenIntroduction.setVisibility(introduction ? VISIBLE : GONE);
if (introduction) {
int message = zenImportant
? R.string.zen_priority_introduction
: zenAlarm
? R.string.zen_alarms_introduction
: zenGame
? R.string.zen_game_introduction
: mVoiceCapable
? R.string.zen_silence_introduction_voice
: R.string.zen_silence_introduction;
mConfigurableTexts.add(mZenIntroductionMessage, message);
mConfigurableTexts.update();
mZenIntroductionCustomize.setVisibility(zenImportant ? VISIBLE : GONE);
}
final String warning = computeAlarmWarningText(zenNone);
mZenAlarmWarning.setVisibility(warning != null ? VISIBLE : GONE);
mZenAlarmWarning.setText(warning);
}
private String computeAlarmWarningText(boolean zenNone) {
if (!zenNone) {
return null;
}
final long now = System.currentTimeMillis();
final long nextAlarm = mController.getNextAlarm();
if (nextAlarm < now) {
return null;
}
int warningRes = 0;
if (mSessionExitCondition == null || isForever(mSessionExitCondition)) {
warningRes = R.string.zen_alarm_warning_indef;
} else {
final long time = ZenModeConfig.tryParseCountdownConditionId(mSessionExitCondition.id);
if (time > now && nextAlarm < time) {
warningRes = R.string.zen_alarm_warning;
}
}
if (warningRes == 0) {
return null;
}
final boolean soon = (nextAlarm - now) < 24 * 60 * 60 * 1000;
final boolean is24 = DateFormat.is24HourFormat(mContext, ActivityManager.getCurrentUser());
final String skeleton = soon ? (is24 ? "Hm" : "hma") : (is24 ? "EEEHm" : "EEEhma");
final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
final CharSequence formattedTime = DateFormat.format(pattern, nextAlarm);
final int templateRes = soon ? R.string.alarm_template : R.string.alarm_template_far;
final String template = getResources().getString(templateRes, formattedTime);
return getResources().getString(warningRes, template);
}
private static Condition parseExistingTimeCondition(Context context, Condition condition) {
if (condition == null) return null;
final long time = ZenModeConfig.tryParseCountdownConditionId(condition.id);
if (time == 0) return null;
final long now = System.currentTimeMillis();
final long span = time - now;
if (span <= 0 || span > MAX_BUCKET_MINUTES * MINUTES_MS) return null;
return ZenModeConfig.toTimeCondition(context,
time, Math.round(span / (float) MINUTES_MS), ActivityManager.getCurrentUser(),
false /*shortVersion*/);
}
private void handleUpdateConditions() {
if (mTransitionHelper.isTransitioning()) {
return;
}
final int conditionCount = mConditions == null ? 0 : mConditions.length;
if (DEBUG) Log.d(mTag, "handleUpdateConditions conditionCount=" + conditionCount);
// forever
bind(forever(), mZenRadioGroupContent.getChildAt(FOREVER_CONDITION_INDEX),
FOREVER_CONDITION_INDEX);
// countdown
if (mCountdownConditionSupported && mTimeCondition != null) {
bind(mTimeCondition, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
COUNTDOWN_CONDITION_INDEX);
}
// countdown until alarm
if (mCountdownConditionSupported) {
Condition nextAlarmCondition = getTimeUntilNextAlarmCondition();
if (nextAlarmCondition != null) {
mZenRadioGroup.getChildAt(
COUNTDOWN_ALARM_CONDITION_INDEX).setVisibility(View.VISIBLE);
mZenRadioGroupContent.getChildAt(
COUNTDOWN_ALARM_CONDITION_INDEX).setVisibility(View.VISIBLE);
bind(nextAlarmCondition,
mZenRadioGroupContent.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX),
COUNTDOWN_ALARM_CONDITION_INDEX);
} else {
mZenRadioGroup.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX).setVisibility(View.GONE);
mZenRadioGroupContent.getChildAt(
COUNTDOWN_ALARM_CONDITION_INDEX).setVisibility(View.GONE);
}
}
// ensure something is selected
if (mExpanded) {
ensureSelection();
}
mZenConditions.setVisibility(mSessionZen != Global.ZEN_MODE_OFF ? View.VISIBLE : View.GONE);
}
private Condition forever() {
return new Condition(mForeverId, foreverSummary(mContext), "", "", 0 /*icon*/,
Condition.STATE_TRUE, 0 /*flags*/);
}
private static String foreverSummary(Context context) {
return context.getString(com.android.internal.R.string.zen_mode_forever);
}
// Returns a time condition if the next alarm is within the next week.
private Condition getTimeUntilNextAlarmCondition() {
GregorianCalendar weekRange = new GregorianCalendar();
final long now = weekRange.getTimeInMillis();
setToMidnight(weekRange);
weekRange.add(Calendar.DATE, 6);
final long nextAlarmMs = mController.getNextAlarm();
if (nextAlarmMs > 0) {
GregorianCalendar nextAlarm = new GregorianCalendar();
nextAlarm.setTimeInMillis(nextAlarmMs);
setToMidnight(nextAlarm);
if (weekRange.compareTo(nextAlarm) >= 0) {
return ZenModeConfig.toTimeCondition(mContext, nextAlarmMs,
Math.round((nextAlarmMs - now) / (float) MINUTES_MS),
ActivityManager.getCurrentUser(), true);
}
}
return null;
}
private void setToMidnight(Calendar calendar) {
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
}
private ConditionTag getConditionTagAt(int index) {
return (ConditionTag) mZenRadioGroupContent.getChildAt(index).getTag();
}
private int getVisibleConditions() {
int rt = 0;
final int N = mZenRadioGroupContent.getChildCount();
for (int i = 0; i < N; i++) {
rt += mZenRadioGroupContent.getChildAt(i).getVisibility() == VISIBLE ? 1 : 0;
}
return rt;
}
private void hideAllConditions() {
final int N = mZenRadioGroupContent.getChildCount();
for (int i = 0; i < N; i++) {
mZenRadioGroupContent.getChildAt(i).setVisibility(GONE);
}
}
private void ensureSelection() {
// are we left without anything selected? if so, set a default
final int visibleConditions = getVisibleConditions();
if (visibleConditions == 0) return;
for (int i = 0; i < visibleConditions; i++) {
final ConditionTag tag = getConditionTagAt(i);
if (tag != null && tag.rb.isChecked()) {
if (DEBUG) Log.d(mTag, "Not selecting a default, checked=" + tag.condition);
return;
}
}
final ConditionTag foreverTag = getConditionTagAt(FOREVER_CONDITION_INDEX);
if (foreverTag == null) return;
if (DEBUG) Log.d(mTag, "Selecting a default");
final int favoriteIndex = mPrefs.getMinuteIndex();
if (mExitCondition != null && mExitCondition.equals(mTimeCondition)) {
getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb.setChecked(true);
} else if (favoriteIndex == -1 || !mCountdownConditionSupported ||
mAttachedZen != Global.ZEN_MODE_OFF) {
foreverTag.rb.setChecked(true);
} else {
mTimeCondition = ZenModeConfig.toTimeCondition(mContext,
MINUTE_BUCKETS[favoriteIndex], ActivityManager.getCurrentUser());
mBucketIndex = favoriteIndex;
bind(mTimeCondition, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
COUNTDOWN_CONDITION_INDEX);
getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb.setChecked(true);
}
}
private static boolean isCountdown(Condition c) {
return c != null && ZenModeConfig.isValidCountdownConditionId(c.id);
}
private boolean isForever(Condition c) {
return c != null && mForeverId.equals(c.id);
}
private void bind(final Condition condition, final View row, final int rowId) {
if (condition == null) throw new IllegalArgumentException("condition must not be null");
final boolean enabled = condition.state == Condition.STATE_TRUE;
final ConditionTag tag =
row.getTag() != null ? (ConditionTag) row.getTag() : new ConditionTag();
row.setTag(tag);
final boolean first = tag.rb == null;
if (tag.rb == null) {
tag.rb = (RadioButton) mZenRadioGroup.getChildAt(rowId);
}
tag.condition = condition;
final Uri conditionId = getConditionId(tag.condition);
if (DEBUG) Log.d(mTag, "bind i=" + mZenRadioGroupContent.indexOfChild(row) + " first="
+ first + " condition=" + conditionId);
tag.rb.setEnabled(enabled);
tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (mExpanded && isChecked) {
tag.rb.setChecked(true);
if (DEBUG) Log.d(mTag, "onCheckedChanged " + conditionId);
MetricsLogger.action(mContext, MetricsEvent.QS_DND_CONDITION_SELECT);
select(tag.condition);
announceConditionSelection(tag);
}
}
});
if (tag.lines == null) {
tag.lines = row.findViewById(android.R.id.content);
}
if (tag.line1 == null) {
tag.line1 = (TextView) row.findViewById(android.R.id.text1);
mConfigurableTexts.add(tag.line1);
}
if (tag.line2 == null) {
tag.line2 = (TextView) row.findViewById(android.R.id.text2);
mConfigurableTexts.add(tag.line2);
}
final String line1 = !TextUtils.isEmpty(condition.line1) ? condition.line1
: condition.summary;
final String line2 = condition.line2;
tag.line1.setText(line1);
if (TextUtils.isEmpty(line2)) {
tag.line2.setVisibility(GONE);
} else {
tag.line2.setVisibility(VISIBLE);
tag.line2.setText(line2);
}
tag.lines.setEnabled(enabled);
tag.lines.setAlpha(enabled ? 1 : .4f);
final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onClickTimeButton(row, tag, false /*down*/, rowId);
}
});
final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onClickTimeButton(row, tag, true /*up*/, rowId);
}
});
tag.lines.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
tag.rb.setChecked(true);
}
});
final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
if (rowId != COUNTDOWN_ALARM_CONDITION_INDEX && time > 0) {
button1.setVisibility(VISIBLE);
button2.setVisibility(VISIBLE);
if (mBucketIndex > -1) {
button1.setEnabled(mBucketIndex > 0);
button2.setEnabled(mBucketIndex < MINUTE_BUCKETS.length - 1);
} else {
final long span = time - System.currentTimeMillis();
button1.setEnabled(span > MIN_BUCKET_MINUTES * MINUTES_MS);
final Condition maxCondition = ZenModeConfig.toTimeCondition(mContext,
MAX_BUCKET_MINUTES, ActivityManager.getCurrentUser());
button2.setEnabled(!Objects.equals(condition.summary, maxCondition.summary));
}
button1.setAlpha(button1.isEnabled() ? 1f : .5f);
button2.setAlpha(button2.isEnabled() ? 1f : .5f);
} else {
button1.setVisibility(GONE);
button2.setVisibility(GONE);
}
// wire up interaction callbacks for newly-added condition rows
if (first) {
Interaction.register(tag.rb, mInteractionCallback);
Interaction.register(tag.lines, mInteractionCallback);
Interaction.register(button1, mInteractionCallback);
Interaction.register(button2, mInteractionCallback);
}
row.setVisibility(VISIBLE);
}
private void announceConditionSelection(ConditionTag tag) {
final int zen = getSelectedZen(Global.ZEN_MODE_OFF);
String modeText;
switch(zen) {
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
modeText = mContext.getString(R.string.interruption_level_priority);
break;
case Global.ZEN_MODE_NO_INTERRUPTIONS:
modeText = mContext.getString(R.string.interruption_level_none);
break;
case Global.ZEN_MODE_ALARMS:
modeText = mContext.getString(R.string.interruption_level_alarms);
break;
case Global.ZEN_MODE_GAME:
modeText = mContext.getString(R.string.interruption_level_game);
break;
default:
return;
}
announceForAccessibility(mContext.getString(R.string.zen_mode_and_condition, modeText,
tag.line1.getText()));
}
private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
MetricsLogger.action(mContext, MetricsEvent.QS_DND_TIME, up);
Condition newCondition = null;
final int N = MINUTE_BUCKETS.length;
if (mBucketIndex == -1) {
// not on a known index, search for the next or prev bucket by time
final Uri conditionId = getConditionId(tag.condition);
final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
final long now = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
int j = up ? i : N - 1 - i;
final int bucketMinutes = MINUTE_BUCKETS[j];
final long bucketTime = now + bucketMinutes * MINUTES_MS;
if (up && bucketTime > time || !up && bucketTime < time) {
mBucketIndex = j;
newCondition = ZenModeConfig.toTimeCondition(mContext,
bucketTime, bucketMinutes, ActivityManager.getCurrentUser(),
false /*shortVersion*/);
break;
}
}
if (newCondition == null) {
mBucketIndex = DEFAULT_BUCKET_INDEX;
newCondition = ZenModeConfig.toTimeCondition(mContext,
MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
}
} else {
// on a known index, simply increment or decrement
mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1)));
newCondition = ZenModeConfig.toTimeCondition(mContext,
MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
}
mTimeCondition = newCondition;
bind(mTimeCondition, row, rowId);
tag.rb.setChecked(true);
select(mTimeCondition);
announceConditionSelection(tag);
}
private void select(final Condition condition) {
if (DEBUG) Log.d(mTag, "select " + condition);
if (mSessionZen == -1 || mSessionZen == Global.ZEN_MODE_OFF) {
if (DEBUG) Log.d(mTag, "Ignoring condition selection outside of manual zen");
return;
}
final Uri realConditionId = getRealConditionId(condition);
if (mController != null) {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
mController.setZen(mSessionZen, realConditionId, TAG + ".selectCondition");
}
});
}
setExitCondition(condition);
if (realConditionId == null) {
mPrefs.setMinuteIndex(-1);
} else if (isCountdown(condition) && mBucketIndex != -1) {
mPrefs.setMinuteIndex(mBucketIndex);
}
setSessionExitCondition(copy(condition));
}
private void fireInteraction() {
if (mCallback != null) {
mCallback.onInteraction();
}
}
private void fireExpanded() {
if (mCallback != null) {
mCallback.onExpanded(mExpanded);
}
}
private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
@Override
public void onManualRuleChanged(ZenRule rule) {
mHandler.obtainMessage(H.MANUAL_RULE_CHANGED, rule).sendToTarget();
}
};
private final class H extends Handler {
private static final int MANUAL_RULE_CHANGED = 2;
private static final int UPDATE_WIDGETS = 3;
private H() {
super(Looper.getMainLooper());
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MANUAL_RULE_CHANGED: handleUpdateManualRule((ZenRule) msg.obj); break;
case UPDATE_WIDGETS: updateWidgets(); break;
}
}
}
public interface Callback {
void onPrioritySettings();
void onInteraction();
void onExpanded(boolean expanded);
}
// used as the view tag on condition rows
private static class ConditionTag {
RadioButton rb;
View lines;
TextView line1;
TextView line2;
Condition condition;
}
private final class ZenPrefs implements OnSharedPreferenceChangeListener {
private final int mNoneDangerousThreshold;
private int mMinuteIndex;
private int mNoneSelected;
private boolean mConfirmedPriorityIntroduction;
private boolean mConfirmedSilenceIntroduction;
private boolean mConfirmedAlarmIntroduction;
private boolean mConfirmedGameIntroduction;
private ZenPrefs() {
mNoneDangerousThreshold = mContext.getResources()
.getInteger(R.integer.zen_mode_alarm_warning_threshold);
Prefs.registerListener(mContext, this);
updateMinuteIndex();
updateNoneSelected();
updateConfirmedPriorityIntroduction();
updateConfirmedSilenceIntroduction();
updateConfirmedAlarmIntroduction();
updateConfirmedGameIntroduction();
}
public void trackNoneSelected() {
mNoneSelected = clampNoneSelected(mNoneSelected + 1);
if (DEBUG) Log.d(mTag, "Setting none selected: " + mNoneSelected + " threshold="
+ mNoneDangerousThreshold);
Prefs.putInt(mContext, Prefs.Key.DND_NONE_SELECTED, mNoneSelected);
}
public int getMinuteIndex() {
return mMinuteIndex;
}
public void setMinuteIndex(int minuteIndex) {
minuteIndex = clampIndex(minuteIndex);
if (minuteIndex == mMinuteIndex) return;
mMinuteIndex = clampIndex(minuteIndex);
if (DEBUG) Log.d(mTag, "Setting favorite minute index: " + mMinuteIndex);
Prefs.putInt(mContext, Prefs.Key.DND_FAVORITE_BUCKET_INDEX, mMinuteIndex);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
updateMinuteIndex();
updateNoneSelected();
updateConfirmedPriorityIntroduction();
updateConfirmedSilenceIntroduction();
updateConfirmedAlarmIntroduction();
updateConfirmedGameIntroduction();
}
private void updateMinuteIndex() {
mMinuteIndex = clampIndex(Prefs.getInt(mContext,
Prefs.Key.DND_FAVORITE_BUCKET_INDEX, DEFAULT_BUCKET_INDEX));
if (DEBUG) Log.d(mTag, "Favorite minute index: " + mMinuteIndex);
}
private int clampIndex(int index) {
return MathUtils.constrain(index, -1, MINUTE_BUCKETS.length - 1);
}
private void updateNoneSelected() {
mNoneSelected = clampNoneSelected(Prefs.getInt(mContext,
Prefs.Key.DND_NONE_SELECTED, 0));
if (DEBUG) Log.d(mTag, "None selected: " + mNoneSelected);
}
private int clampNoneSelected(int noneSelected) {
return MathUtils.constrain(noneSelected, 0, Integer.MAX_VALUE);
}
private void updateConfirmedPriorityIntroduction() {
final boolean confirmed = Prefs.getBoolean(mContext,
Prefs.Key.DND_CONFIRMED_PRIORITY_INTRODUCTION, false);
if (confirmed == mConfirmedPriorityIntroduction) return;
mConfirmedPriorityIntroduction = confirmed;
if (DEBUG) Log.d(mTag, "Confirmed priority introduction: "
+ mConfirmedPriorityIntroduction);
}
private void updateConfirmedSilenceIntroduction() {
final boolean confirmed = Prefs.getBoolean(mContext,
Prefs.Key.DND_CONFIRMED_SILENCE_INTRODUCTION, false);
if (confirmed == mConfirmedSilenceIntroduction) return;
mConfirmedSilenceIntroduction = confirmed;
if (DEBUG) Log.d(mTag, "Confirmed silence introduction: "
+ mConfirmedSilenceIntroduction);
}
private void updateConfirmedAlarmIntroduction() {
final boolean confirmed = Prefs.getBoolean(mContext,
Prefs.Key.DND_CONFIRMED_ALARM_INTRODUCTION, false);
if (confirmed == mConfirmedAlarmIntroduction) return;
mConfirmedAlarmIntroduction = confirmed;
if (DEBUG) Log.d(mTag, "Confirmed alarm introduction: "
+ mConfirmedAlarmIntroduction);
}
private void updateConfirmedGameIntroduction() {
final boolean confirmed = Prefs.getBoolean(mContext,
Prefs.Key.DND_CONFIRMED_GAME_INTRODUCTION, false);
if (confirmed == mConfirmedGameIntroduction) return;
mConfirmedGameIntroduction = confirmed;
if (DEBUG) Log.d(mTag, "Confirmed game introduction: "
+ mConfirmedGameIntroduction);
}
}
protected final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() {
@Override
public void onSelected(final Object value, boolean fromClick) {
if (value != null && mZenButtons.isShown() && isAttachedToWindow()) {
final int zen = (Integer) value;
if (fromClick) {
MetricsLogger.action(mContext, MetricsEvent.QS_DND_ZEN_SELECT, zen);
}
if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + zen);
final Uri realConditionId = getRealConditionId(mSessionExitCondition);
AsyncTask.execute(new Runnable() {
@Override
public void run() {
mController.setZen(zen, realConditionId, TAG + ".selectZen");
if (zen != Global.ZEN_MODE_OFF) {
Prefs.putInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, zen);
}
}
});
}
}
@Override
public void onInteraction() {
fireInteraction();
}
};
private final Interaction.Callback mInteractionCallback = new Interaction.Callback() {
@Override
public void onInteraction() {
fireInteraction();
}
};
private final class TransitionHelper implements TransitionListener, Runnable {
private final ArraySet<View> mTransitioningViews = new ArraySet<View>();
private boolean mTransitioning;
private boolean mPendingUpdateWidgets;
public void clear() {
mTransitioningViews.clear();
mPendingUpdateWidgets = false;
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(" TransitionHelper state:");
pw.print(" mPendingUpdateWidgets="); pw.println(mPendingUpdateWidgets);
pw.print(" mTransitioning="); pw.println(mTransitioning);
pw.print(" mTransitioningViews="); pw.println(mTransitioningViews);
}
public void pendingUpdateWidgets() {
mPendingUpdateWidgets = true;
}
public boolean isTransitioning() {
return !mTransitioningViews.isEmpty();
}
@Override
public void startTransition(LayoutTransition transition,
ViewGroup container, View view, int transitionType) {
mTransitioningViews.add(view);
updateTransitioning();
}
@Override
public void endTransition(LayoutTransition transition,
ViewGroup container, View view, int transitionType) {
mTransitioningViews.remove(view);
updateTransitioning();
}
@Override
public void run() {
if (DEBUG) Log.d(mTag, "TransitionHelper run"
+ " mPendingUpdateWidgets=" + mPendingUpdateWidgets);
if (mPendingUpdateWidgets) {
updateWidgets();
}
mPendingUpdateWidgets = false;
}
private void updateTransitioning() {
final boolean transitioning = isTransitioning();
if (mTransitioning == transitioning) return;
mTransitioning = transitioning;
if (DEBUG) Log.d(mTag, "TransitionHelper mTransitioning=" + mTransitioning);
if (!mTransitioning) {
if (mPendingUpdateWidgets) {
mHandler.post(this);
} else {
mPendingUpdateWidgets = false;
}
}
}
}
}
2.实现新加的模式
dnd实现的地方在ZenModeHelper.java,这里会根据不同的模式来做不同的处理,还会监听audiomanager模式的改变,就是按音量键打开dnd。
在打开某个模式的时候,首先会看是否要设置applyZenToRingerMode,然后在去applyRestrictions。我们这里加的模式不会去设置RINGER_MODE_SILENT,而是直接applyRestrictions去设置。
frameworks/base/services/core/java/com/android/server/notification/ZenModeHelper.java
private boolean evaluateZenMode(String reason, boolean setRingerMode) {
if (DEBUG) Log.d(TAG, "evaluateZenMode");
final int zenBefore = mZenMode;
final int zen = computeZenMode();
ZenLog.traceSetZenMode(zen, reason);
mZenMode = zen;
updateRingerModeAffectedStreams();
setZenModeSetting(mZenMode);
if (setRingerMode) {
applyZenToRingerMode();
}
applyRestrictions();
if (zen != zenBefore) {
mHandler.postDispatchOnZenModeChanged();
}
return true;
}
private void applyZenToRingerMode() {
if (mAudioManager == null) return;
// force the ringer mode into compliance
final int ringerModeInternal = mAudioManager.getRingerModeInternal();
int newRingerModeInternal = ringerModeInternal;
switch (mZenMode) {
case Global.ZEN_MODE_NO_INTERRUPTIONS:
case Global.ZEN_MODE_ALARMS:
//case Global.ZEN_MODE_GAME:
if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) {
setPreviousRingerModeSetting(ringerModeInternal);
newRingerModeInternal = AudioManager.RINGER_MODE_SILENT;
}
break;
case Global.ZEN_MODE_GAME:
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
case Global.ZEN_MODE_OFF:
if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) {
newRingerModeInternal = getPreviousRingerModeSetting();
setPreviousRingerModeSetting(null);
}
break;
}
if (newRingerModeInternal != -1) {
mAudioManager.setRingerModeInternal(newRingerModeInternal, TAG);
}
}
根据不同模式,设置哪些声音有效,哪些无效。
private void applyRestrictions() {
final boolean zen = mZenMode != Global.ZEN_MODE_OFF;
// notification restrictions
final boolean muteNotifications =
(mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0;
// call restrictions
final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers
|| (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0;
// total silence restrictions
final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
final boolean mGameMode = mZenMode == Global.ZEN_MODE_GAME;
for (int usage : AudioAttributes.SDK_USAGES) {
final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NEVER) {
applyRestrictions(false /*mute*/, usage);
} else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) {
applyRestrictions(muteNotifications || muteEverything||mGameMode, usage);
} else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) {
applyRestrictions(muteCalls || muteEverything||mGameMode, usage);
} else if(usage==AudioAttributes.SDK_USAGES[4]) {
//Alarm
applyRestrictions(mGameMode, usage);
}
else {
applyRestrictions(muteEverything, usage);
}
}
}
private static int zenSeverity(int zen) {
switch (zen) {
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return 1;
case Global.ZEN_MODE_ALARMS: return 2;
case Global.ZEN_MODE_NO_INTERRUPTIONS: return 3;
case Global.ZEN_MODE_GAME: return 4;
default: return 0;
}
}
注意RingerModeDelegate这个内部类,当执行applyZenToRingerMode改变了ringermode,就会回调这个内部类里的方法,按音量键也会走这里,所以这里也要加入对我们新加模式的一些处理,否则会发生逻辑错误,导致QS那点击的按钮切换错误。
private final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
@Override
public String toString() {
return TAG;
}
@Override
public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
int ringerModeExternal, VolumePolicy policy) {
final boolean isChange = ringerModeOld != ringerModeNew;
int ringerModeExternalOut = ringerModeNew;
int newZen = -1;
switch (ringerModeNew) {
case AudioManager.RINGER_MODE_SILENT:
if (isChange && policy.doNotDisturbWhenSilent) {
if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS
&& mZenMode != Global.ZEN_MODE_ALARMS
&& mZenMode != Global.ZEN_MODE_GAME) {
newZen = Global.ZEN_MODE_ALARMS;
}
setPreviousRingerModeSetting(ringerModeOld);
}
break;
case AudioManager.RINGER_MODE_VIBRATE:
case AudioManager.RINGER_MODE_NORMAL:
if (isChange && ringerModeOld == AudioManager.RINGER_MODE_SILENT
&& (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS
|| mZenMode == Global.ZEN_MODE_ALARMS
/*|| mZenMode == Global.ZEN_MODE_GAME*/)) {
newZen = Global.ZEN_MODE_OFF;
} else if (mZenMode != Global.ZEN_MODE_OFF) {
ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT;
}
break;
}
if (newZen != -1) {
setManualZenMode(newZen, null, "ringerModeInternal", null,
false /*setRingerMode*/);
}
if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) {
ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller,
ringerModeExternal, ringerModeExternalOut);
}
return ringerModeExternalOut;
}
@Override
public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
int ringerModeInternal, VolumePolicy policy) {
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_ALARMS;
}
ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
: AudioManager.RINGER_MODE_SILENT;
} 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) {
setManualZenMode(newZen, null, "ringerModeExternal", caller,
false /*setRingerMode*/);
}
ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller,
ringerModeInternal, ringerModeInternalOut);
return ringerModeInternalOut;
}
@Override
public boolean canVolumeDownEnterSilent() {
return mZenMode == Global.ZEN_MODE_OFF;
}
@Override
public int getRingerModeAffectedStreams(int streams) {
// ringtone, notification and system streams are always affected by ringer mode
streams |= (1 << AudioSystem.STREAM_RING) |
(1 << AudioSystem.STREAM_NOTIFICATION) |
(1 << AudioSystem.STREAM_SYSTEM);
// alarm and music streams are only affected by ringer mode when in total silence
if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
streams |= (1 << AudioSystem.STREAM_ALARM) |
(1 << AudioSystem.STREAM_MUSIC);
} else {
streams &= ~((1 << AudioSystem.STREAM_ALARM) |
(1 << AudioSystem.STREAM_MUSIC));
}
return streams;
}
}
3.音量界面的处理
当你进去某个dnd模式下,在settigns中的sound里面你可以发现,有些音量会滑动条会被disable掉。所以我们在这里也要做些处理。
这个界面在
packages/apps/Settings/src/com/android/settings/notification/SoundSettings.java,但是对应的音量滑动条在frameworks/base/core/java/android/preferences/SeekBarVolumizer.java,每个音量条都会对应new一个SeekBarVolumizer,然后SeekBarVolumizer会根据对应音量的stream和zenmode来判断是否要disable掉。
SeekBarVolumizer.java
private boolean isZenMuted() {
return mNotificationOrRing && mZenMode == Global.ZEN_MODE_ALARMS
|| mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS
|| (mZenMode == Global.ZEN_MODE_GAME && mStreamType == AudioManager.STREAM_ALARM);
}
protected void updateSeekBar() {
final boolean zenMuted = isZenMuted();
mSeekBar.setEnabled(!zenMuted);
if (zenMuted) {
mSeekBar.setProgress(mLastAudibleStreamVolume, true);
} else if (mNotificationOrRing && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
mSeekBar.setProgress(0, true);
} else if (mMuted) {
mSeekBar.setProgress(0, true);
} else {
mSeekBar.setProgress(mLastProgress > -1 ? mLastProgress : mOriginalStreamVolume, true);
}
}
除了settings中有音量,还有个地方也有,就是当你按下音量键时候,从屏幕上方弹下来的界面。
frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
private void updateVolumeRowH(VolumeRow row) {
if (D.BUG) Log.d(TAG, "updateVolumeRowH s=" + row.stream);
if (mState == null) return;
final StreamState ss = mState.states.get(row.stream);
if (ss == null) return;
row.ss = ss;
if (ss.level > 0) {
row.lastAudibleLevel = ss.level;
}
if (ss.level == row.requestedLevel) {
row.requestedLevel = -1;
}
final boolean isA11yStream = row.stream == AudioManager.STREAM_ACCESSIBILITY;
final boolean isRingStream = row.stream == AudioManager.STREAM_RING;
final boolean isSystemStream = row.stream == AudioManager.STREAM_SYSTEM;
final boolean isAlarmStream = row.stream == AudioManager.STREAM_ALARM;
final boolean isMusicStream = row.stream == AudioManager.STREAM_MUSIC;
final boolean isRingVibrate = isRingStream
&& mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
final boolean isRingSilent = isRingStream
&& mState.ringerModeInternal == AudioManager.RINGER_MODE_SILENT;
final boolean isZenAlarms = mState.zenMode == Global.ZEN_MODE_ALARMS;
final boolean isZenNone = mState.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
final boolean isZenGame = mState.zenMode == Global.ZEN_MODE_GAME;
final boolean zenMuted = isZenAlarms ? (isRingStream || isSystemStream)
: isZenNone ? (isRingStream || isSystemStream || isAlarmStream || isMusicStream)
: isZenGame ? (isAlarmStream)
: false;
......
}
isZenAlarms ? (isRingStream || isSystemStream) 如果是alarm模式,就disable掉ringstream和SystemStream。
注意:ZenModeFiltering这个类。
matchesCallFilter和shouldIntercept都要加我们的代码,模仿其他模式。