Android8.0 Do not disturb(DND)/Zenmode 添加一个新的模式
来源:互联网 发布:linux make安装包下载 编辑:程序博客网 时间:2024/06/08 00:01
这里添加的模式可能涉及的地方不全面,目前把已知的地方都加上。可以搜索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); } public void setEmptyState(int icon, int text) { mEmptyIcon.post(() -> { mEmptyIcon.setImageResource(icon); mEmptyText.setText(text); }); } public void setAutoText(CharSequence text) { mAutoTitle.post(() -> mAutoTitle.setText(text)); } public void setState(int state) { if (mState == state) return; transitionFrom(getView(mState), getView(state)); mState = state; } private void transitionFrom(View from, View to) { from.post(() -> { // TODO: Better transitions to.setAlpha(0); to.setVisibility(VISIBLE); to.bringToFront(); to.animate().cancel(); to.animate().alpha(1) .setDuration(TRANSITION_DURATION) .withEndAction(() -> from.setVisibility(INVISIBLE)) .start(); }); } 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都要加我们的代码,模仿其他模式。
- Android8.0 Do not disturb(DND)/Zenmode 添加一个新的模式
- Android8.0 ZenMode 静音模式
- Android8.0 修改默认铃声 添加新铃声
- Android:java.lang.SecurityException: Not allowed to change Do Not Disturb state
- Android8.0 Oreo新特性
- Android8.0中对指纹的新要求
- Android8.0新系统刷机新尝鲜
- android8.0/android O 新特性
- Android8.0新特性和API
- Android8.0 Email 一个Bug修改方案
- Android8.0 在settings中添加蓝牙耳机的电池电量信息
- Android8.0
- Nexus6P终于吃上Android8.0奥利奥 & 8.0新特性
- 每天一点小知识【5】— Android8.0新特性
- android8.0的vdex文件格式分析
- java里的dnd
- java里的dnd
- DnD
- SnapHelper,对RecyclerView的功能拓展
- 单例
- 用tf.slim微调vgg模型时遇到的小坑
- Eclipse中修改SVN用户名和密码方法
- RabbitMQ相关
- Android8.0 Do not disturb(DND)/Zenmode 添加一个新的模式
- 535. Encode and Decode TinyURL
- java_多线程
- AMD异步模块定义介绍和Require.js中使用jQuery及jQuery插件的方法
- latex 引号记录
- 斐波那契系列问题的递归和动态规划
- 近期活动盘点:工业大数据讲座、大数据自杀风险感知讲座、数据法学研讨会、海外学者短期讲学(12.3-12.13)
- [教程]VC++6.0的简单使用
- 惊呼!阿里云云服务器ECS最低3折售卖啦