| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.systemui.volume; |
| |
| import android.animation.Animator; |
| import android.animation.AnimatorListenerAdapter; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.SharedPreferences; |
| import android.content.SharedPreferences.OnSharedPreferenceChangeListener; |
| import android.net.Uri; |
| import android.os.Handler; |
| import android.os.Looper; |
| import android.os.Message; |
| import android.provider.Settings; |
| import android.provider.Settings.Global; |
| import android.service.notification.Condition; |
| import android.service.notification.ZenModeConfig; |
| import android.text.format.DateFormat; |
| import android.text.format.Time; |
| import android.util.AttributeSet; |
| import android.util.Log; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.animation.AnimationUtils; |
| import android.view.animation.Interpolator; |
| import android.widget.CompoundButton; |
| import android.widget.CompoundButton.OnCheckedChangeListener; |
| import android.widget.ImageView; |
| import android.widget.LinearLayout; |
| import android.widget.RadioButton; |
| import android.widget.TextView; |
| |
| import com.android.systemui.R; |
| import com.android.systemui.statusbar.policy.ZenModeController; |
| |
| import java.text.SimpleDateFormat; |
| import java.util.Arrays; |
| import java.util.Date; |
| import java.util.Locale; |
| import java.util.Objects; |
| |
| public class ZenModePanel extends LinearLayout { |
| private static final String TAG = "ZenModePanel"; |
| private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); |
| |
| private static final int SECONDS_MS = 1000; |
| private static final int MINUTES_MS = 60 * SECONDS_MS; |
| |
| private static final int[] MINUTE_BUCKETS = DEBUG |
| ? new int[] { 0, 1, 2, 5, 15, 30, 45, 60, 120, 180, 240, 480 } |
| : new int[] { 15, 30, 45, 60, 120, 180, 240, 480 }; |
| 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 TIME_CONDITION_INDEX = 1; |
| private static final int FIRST_CONDITION_INDEX = 2; |
| private static final float SILENT_HINT_PULSE_SCALE = 1.1f; |
| private static final int ZERO_VALUE_MS = 20 * SECONDS_MS; |
| |
| public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS); |
| |
| private final Context mContext; |
| private final LayoutInflater mInflater; |
| private final H mHandler = new H(); |
| private final Favorites mFavorites; |
| private final Interpolator mFastOutSlowInInterpolator; |
| private final int mTextColor; |
| private final int mAccentColor; |
| |
| private char mLogTag = '?'; |
| private String mTag; |
| |
| private SegmentedButtons mZenButtons; |
| private View mZenSubhead; |
| private TextView mZenSubheadCollapsed; |
| private TextView mZenSubheadExpanded; |
| private View mMoreSettings; |
| private LinearLayout mZenConditions; |
| private TextView mAlarmWarning; |
| |
| private Callback mCallback; |
| private ZenModeController mController; |
| private boolean mRequestingConditions; |
| private Uri mExitConditionId; |
| private int mBucketIndex = -1; |
| private boolean mExpanded; |
| private int mAttachedZen; |
| private String mExitConditionText; |
| private long mNextAlarm; |
| |
| public ZenModePanel(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| mContext = context; |
| mFavorites = new Favorites(); |
| mInflater = LayoutInflater.from(mContext.getApplicationContext()); |
| mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(mContext, |
| android.R.interpolator.fast_out_slow_in); |
| mTextColor = mContext.getResources().getColor(R.color.qs_text); |
| mAccentColor = mContext.getResources().getColor(R.color.system_accent_color); |
| updateTag(); |
| if (DEBUG) Log.d(mTag, "new ZenModePanel"); |
| } |
| |
| private void updateTag() { |
| mTag = TAG + "/" + mLogTag + "/" + Integer.toHexString(System.identityHashCode(this)); |
| } |
| |
| @Override |
| protected void onFinishInflate() { |
| super.onFinishInflate(); |
| |
| mZenButtons = (SegmentedButtons) findViewById(R.id.zen_buttons); |
| mZenButtons.addButton(R.string.interruption_level_none, Global.ZEN_MODE_NO_INTERRUPTIONS); |
| mZenButtons.addButton(R.string.interruption_level_priority, |
| Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); |
| mZenButtons.addButton(R.string.interruption_level_all, Global.ZEN_MODE_OFF); |
| mZenButtons.setCallback(mZenButtonsCallback); |
| |
| mZenSubhead = findViewById(R.id.zen_subhead); |
| |
| mZenSubheadCollapsed = (TextView) findViewById(R.id.zen_subhead_collapsed); |
| mZenSubheadCollapsed.setOnClickListener(new View.OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| setExpanded(true); |
| fireInteraction(); |
| } |
| }); |
| |
| mZenSubheadExpanded = (TextView) findViewById(R.id.zen_subhead_expanded); |
| |
| mMoreSettings = findViewById(R.id.zen_more_settings); |
| mMoreSettings.setOnClickListener(new View.OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| fireMoreSettings(); |
| fireInteraction(); |
| } |
| }); |
| |
| mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions); |
| mAlarmWarning = (TextView) findViewById(R.id.zen_alarm_warning); |
| } |
| |
| @Override |
| protected void onAttachedToWindow() { |
| super.onAttachedToWindow(); |
| if (DEBUG) Log.d(mTag, "onAttachedToWindow"); |
| mAttachedZen = getSelectedZen(-1); |
| refreshExitConditionText(); |
| refreshNextAlarm(); |
| updateWidgets(); |
| } |
| |
| @Override |
| protected void onDetachedFromWindow() { |
| super.onDetachedFromWindow(); |
| if (DEBUG) Log.d(mTag, "onDetachedFromWindow"); |
| mAttachedZen = -1; |
| setExpanded(false); |
| } |
| |
| private void setExpanded(boolean expanded) { |
| if (expanded == mExpanded) return; |
| mExpanded = expanded; |
| updateWidgets(); |
| setRequestingConditions(mExpanded); |
| fireExpanded(); |
| } |
| |
| /** Start or stop requesting relevant zen mode exit conditions */ |
| private void setRequestingConditions(boolean requesting) { |
| if (mRequestingConditions == requesting) return; |
| if (DEBUG) Log.d(mTag, "setRequestingConditions " + requesting); |
| mRequestingConditions = requesting; |
| if (mController != null) { |
| mController.requestConditions(mRequestingConditions); |
| } |
| if (mRequestingConditions) { |
| Condition timeCondition = parseExistingTimeCondition(mExitConditionId); |
| if (timeCondition != null) { |
| mBucketIndex = -1; |
| } else { |
| mBucketIndex = DEFAULT_BUCKET_INDEX; |
| timeCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]); |
| } |
| if (DEBUG) Log.d(mTag, "Initial bucket index: " + mBucketIndex); |
| handleUpdateConditions(new Condition[0]); // ensures forever exists |
| bind(timeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX)); |
| checkForDefault(); |
| } else { |
| mZenConditions.removeAllViews(); |
| } |
| } |
| |
| public void init(ZenModeController controller, char logTag) { |
| mController = controller; |
| mLogTag = logTag; |
| updateTag(); |
| setExitConditionId(mController.getExitConditionId()); |
| refreshExitConditionText(); |
| mAttachedZen = getSelectedZen(-1); |
| handleUpdateZen(mController.getZen()); |
| if (DEBUG) Log.d(mTag, "init mExitConditionId=" + mExitConditionId); |
| mZenConditions.removeAllViews(); |
| mController.addCallback(mZenCallback); |
| } |
| |
| private void setExitConditionId(Uri exitConditionId) { |
| if (Objects.equals(mExitConditionId, exitConditionId)) return; |
| mExitConditionId = exitConditionId; |
| refreshExitConditionText(); |
| updateWidgets(); |
| } |
| |
| private void refreshExitConditionText() { |
| final String forever = mContext.getString(R.string.zen_mode_forever); |
| if (mExitConditionId == null) { |
| mExitConditionText = forever; |
| } else if (ZenModeConfig.isValidCountdownConditionId(mExitConditionId)) { |
| final Condition condition = parseExistingTimeCondition(mExitConditionId); |
| mExitConditionText = condition != null ? condition.summary : forever; |
| } else { |
| mExitConditionText = "(until condition ends)"; // TODO persist current description |
| } |
| } |
| |
| public void setCallback(Callback callback) { |
| mCallback = callback; |
| } |
| |
| public void showSilentHint() { |
| if (DEBUG) Log.d(mTag, "showSilentHint"); |
| if (mZenButtons == null || mZenButtons.getChildCount() == 0) return; |
| final View noneButton = mZenButtons.getChildAt(0); |
| if (noneButton.getScaleX() != 1) return; // already running |
| noneButton.animate().cancel(); |
| noneButton.animate().scaleX(SILENT_HINT_PULSE_SCALE).scaleY(SILENT_HINT_PULSE_SCALE) |
| .setInterpolator(mFastOutSlowInInterpolator) |
| .setListener(new AnimatorListenerAdapter() { |
| @Override |
| public void onAnimationEnd(Animator animation) { |
| noneButton.animate().scaleX(1).scaleY(1).setListener(null); |
| } |
| }); |
| } |
| |
| private void handleUpdateZen(int zen) { |
| if (mAttachedZen != -1 && mAttachedZen != zen) { |
| setExpanded(zen != Global.ZEN_MODE_OFF); |
| mAttachedZen = zen; |
| } |
| mZenButtons.setSelectedValue(zen); |
| updateWidgets(); |
| } |
| |
| private int getSelectedZen(int defValue) { |
| final Object zen = mZenButtons.getSelectedValue(); |
| return zen != null ? (Integer) zen : defValue; |
| } |
| |
| private void updateWidgets() { |
| final int zen = getSelectedZen(Global.ZEN_MODE_OFF); |
| final boolean zenOff = zen == Global.ZEN_MODE_OFF; |
| final boolean zenImportant = zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; |
| final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS; |
| final boolean foreverSelected = mExitConditionId == null; |
| final boolean hasNextAlarm = mNextAlarm != 0; |
| |
| mZenSubhead.setVisibility(!zenOff && (mExpanded || !foreverSelected) ? VISIBLE : GONE); |
| mZenSubheadExpanded.setVisibility(mExpanded ? VISIBLE : GONE); |
| mZenSubheadCollapsed.setVisibility(!mExpanded ? VISIBLE : GONE); |
| mMoreSettings.setVisibility(zenImportant && mExpanded ? VISIBLE : GONE); |
| mZenConditions.setVisibility(!zenOff && mExpanded ? VISIBLE : GONE); |
| mAlarmWarning.setVisibility(zenNone && mExpanded && hasNextAlarm ? VISIBLE : GONE); |
| |
| if (zenNone && mExpanded && hasNextAlarm) { |
| final long exitTime = ZenModeConfig.tryParseCountdownConditionId(mExitConditionId); |
| final long now = System.currentTimeMillis(); |
| final boolean alarmToday = time(mNextAlarm).yearDay == time(now).yearDay; |
| final String skeleton = (alarmToday ? "" : "E") |
| + (DateFormat.is24HourFormat(mContext) ? "Hm" : "hma"); |
| final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton); |
| final String alarm = new SimpleDateFormat(pattern).format(new Date(mNextAlarm)); |
| final boolean isWarning = exitTime > 0 && mNextAlarm > now && mNextAlarm < exitTime; |
| if (isWarning) { |
| mAlarmWarning.setText(mContext.getString(R.string.zen_alarm_warning, alarm)); |
| mAlarmWarning.setTextColor(mAccentColor); |
| } else { |
| mAlarmWarning.setText(mContext.getString(alarmToday |
| ? R.string.zen_alarm_information_time |
| : R.string.zen_alarm_information_day_time, alarm)); |
| mAlarmWarning.setTextColor(mTextColor); |
| } |
| } |
| |
| if (zenNone) { |
| mZenSubheadExpanded.setText(R.string.zen_no_interruptions_with_warning); |
| mZenSubheadCollapsed.setText(mExitConditionText); |
| } else if (zenImportant) { |
| mZenSubheadExpanded.setText(R.string.zen_important_interruptions); |
| mZenSubheadCollapsed.setText(mExitConditionText); |
| } |
| } |
| |
| private static Time time(long millis) { |
| final Time t = new Time(); |
| t.set(millis); |
| return t; |
| } |
| |
| private Condition parseExistingTimeCondition(Uri conditionId) { |
| final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId); |
| if (time == 0) return null; |
| final long span = time - System.currentTimeMillis(); |
| if (span <= 0 || span > MAX_BUCKET_MINUTES * MINUTES_MS) return null; |
| return timeCondition(time, Math.round(span / (float)MINUTES_MS)); |
| } |
| |
| private Condition newTimeCondition(int minutesFromNow) { |
| final long now = System.currentTimeMillis(); |
| final long millis = minutesFromNow == 0 ? ZERO_VALUE_MS : minutesFromNow * MINUTES_MS; |
| return timeCondition(now + millis, minutesFromNow); |
| } |
| |
| private Condition timeCondition(long time, int minutes) { |
| final int num = minutes < 60 ? minutes : Math.round(minutes / 60f); |
| final int resId = minutes < 60 |
| ? R.plurals.zen_mode_duration_minutes |
| : R.plurals.zen_mode_duration_hours; |
| final String caption = mContext.getResources().getQuantityString(resId, num, num); |
| final Uri id = ZenModeConfig.toCountdownConditionId(time); |
| return new Condition(id, caption, "", "", 0, Condition.STATE_TRUE, |
| Condition.FLAG_RELEVANT_NOW); |
| } |
| |
| private void refreshNextAlarm() { |
| mNextAlarm = mController.getNextAlarm(); |
| } |
| |
| private void handleNextAlarmChanged() { |
| refreshNextAlarm(); |
| updateWidgets(); |
| } |
| |
| private void handleUpdateConditions(Condition[] conditions) { |
| final int newCount = conditions == null ? 0 : conditions.length; |
| if (DEBUG) Log.d(mTag, "handleUpdateConditions newCount=" + newCount); |
| for (int i = mZenConditions.getChildCount(); i >= newCount + FIRST_CONDITION_INDEX; i--) { |
| mZenConditions.removeViewAt(i); |
| } |
| bind(null, mZenConditions.getChildAt(FOREVER_CONDITION_INDEX)); |
| for (int i = 0; i < newCount; i++) { |
| bind(conditions[i], mZenConditions.getChildAt(FIRST_CONDITION_INDEX + i)); |
| } |
| } |
| |
| private ConditionTag getConditionTagAt(int index) { |
| return (ConditionTag) mZenConditions.getChildAt(index).getTag(); |
| } |
| |
| private void checkForDefault() { |
| // are we left without anything selected? if so, set a default |
| for (int i = 0; i < mZenConditions.getChildCount(); i++) { |
| if (getConditionTagAt(i).rb.isChecked()) { |
| return; |
| } |
| } |
| if (DEBUG) Log.d(mTag, "Selecting a default"); |
| final int favoriteIndex = mFavorites.getMinuteIndex(); |
| if (favoriteIndex == -1) { |
| getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true); |
| } else { |
| final Condition c = newTimeCondition(MINUTE_BUCKETS[favoriteIndex]); |
| mBucketIndex = favoriteIndex; |
| bind(c, mZenConditions.getChildAt(TIME_CONDITION_INDEX)); |
| getConditionTagAt(TIME_CONDITION_INDEX).rb.setChecked(true); |
| } |
| } |
| |
| private void handleExitConditionChanged(Uri exitCondition) { |
| setExitConditionId(exitCondition); |
| if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitConditionId); |
| final int N = mZenConditions.getChildCount(); |
| for (int i = 0; i < N; i++) { |
| final ConditionTag tag = getConditionTagAt(i); |
| tag.rb.setChecked(Objects.equals(tag.conditionId, exitCondition)); |
| } |
| } |
| |
| private void bind(final Condition condition, View convertView) { |
| final boolean enabled = condition == null || condition.state == Condition.STATE_TRUE; |
| final View row; |
| if (convertView == null) { |
| row = mInflater.inflate(R.layout.zen_mode_condition, this, false); |
| if (DEBUG) Log.d(mTag, "Adding new condition view for: " + condition); |
| mZenConditions.addView(row); |
| } else { |
| row = convertView; |
| } |
| final ConditionTag tag = |
| row.getTag() != null ? (ConditionTag) row.getTag() : new ConditionTag(); |
| row.setTag(tag); |
| if (tag.rb == null) { |
| tag.rb = (RadioButton) row.findViewById(android.R.id.checkbox); |
| } |
| tag.conditionId = condition != null ? condition.id : null; |
| tag.rb.setEnabled(enabled); |
| if (Objects.equals(tag.conditionId, mExitConditionId)) { |
| tag.rb.setChecked(true); |
| } |
| tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() { |
| @Override |
| public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { |
| if (mExpanded && isChecked) { |
| if (DEBUG) Log.d(mTag, "onCheckedChanged " + tag.conditionId); |
| final int N = mZenConditions.getChildCount(); |
| for (int i = 0; i < N; i++) { |
| ConditionTag childTag = getConditionTagAt(i); |
| if (childTag == tag) continue; |
| childTag.rb.setChecked(false); |
| } |
| select(tag.conditionId); |
| fireInteraction(); |
| } |
| } |
| }); |
| final TextView title = (TextView) row.findViewById(android.R.id.title); |
| if (condition == null) { |
| title.setText(R.string.zen_mode_forever); |
| } else { |
| title.setText(condition.summary); |
| } |
| title.setEnabled(enabled); |
| title.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*/); |
| } |
| }); |
| |
| 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*/); |
| } |
| }); |
| title.setOnClickListener(new OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| tag.rb.setChecked(true); |
| fireInteraction(); |
| } |
| }); |
| |
| final long time = ZenModeConfig.tryParseCountdownConditionId(tag.conditionId); |
| if (time > 0) { |
| 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 = newTimeCondition(MAX_BUCKET_MINUTES); |
| button2.setEnabled(!Objects.equals(condition.summary, maxCondition.summary)); |
| } |
| |
| button1.setAlpha(button1.isEnabled() ? 1f : .5f); |
| button2.setAlpha(button2.isEnabled() ? 1f : .5f); |
| } else { |
| button1.setVisibility(View.GONE); |
| button2.setVisibility(View.GONE); |
| } |
| } |
| |
| private void onClickTimeButton(View row, ConditionTag tag, boolean 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 long time = ZenModeConfig.tryParseCountdownConditionId(tag.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 = timeCondition(bucketTime, bucketMinutes); |
| break; |
| } |
| } |
| if (newCondition == null) { |
| mBucketIndex = DEFAULT_BUCKET_INDEX; |
| newCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]); |
| } |
| } else { |
| // on a known index, simply increment or decrement |
| mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1))); |
| newCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]); |
| } |
| bind(newCondition, row); |
| tag.rb.setChecked(true); |
| select(newCondition.id); |
| fireInteraction(); |
| } |
| |
| private void select(Uri conditionId) { |
| if (DEBUG) Log.d(mTag, "select " + conditionId); |
| if (mController != null) { |
| mController.setExitConditionId(conditionId); |
| } |
| setExitConditionId(conditionId); |
| if (conditionId == null) { |
| mFavorites.setMinuteIndex(-1); |
| } else if (ZenModeConfig.isValidCountdownConditionId(conditionId) && mBucketIndex != -1) { |
| mFavorites.setMinuteIndex(mBucketIndex); |
| } |
| } |
| |
| private void fireMoreSettings() { |
| if (mCallback != null) { |
| mCallback.onMoreSettings(); |
| } |
| } |
| |
| 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 onZenChanged(int zen) { |
| mHandler.obtainMessage(H.UPDATE_ZEN, zen, 0).sendToTarget(); |
| } |
| @Override |
| public void onConditionsChanged(Condition[] conditions) { |
| mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget(); |
| } |
| |
| @Override |
| public void onExitConditionChanged(Uri exitConditionId) { |
| mHandler.obtainMessage(H.EXIT_CONDITION_CHANGED, exitConditionId).sendToTarget(); |
| } |
| |
| @Override |
| public void onNextAlarmChanged() { |
| mHandler.sendEmptyMessage(H.NEXT_ALARM_CHANGED); |
| } |
| }; |
| |
| private final class H extends Handler { |
| private static final int UPDATE_CONDITIONS = 1; |
| private static final int EXIT_CONDITION_CHANGED = 2; |
| private static final int UPDATE_ZEN = 3; |
| private static final int NEXT_ALARM_CHANGED = 4; |
| |
| private H() { |
| super(Looper.getMainLooper()); |
| } |
| |
| @Override |
| public void handleMessage(Message msg) { |
| if (msg.what == UPDATE_CONDITIONS) { |
| handleUpdateConditions((Condition[]) msg.obj); |
| checkForDefault(); |
| } else if (msg.what == EXIT_CONDITION_CHANGED) { |
| handleExitConditionChanged((Uri) msg.obj); |
| } else if (msg.what == UPDATE_ZEN) { |
| handleUpdateZen(msg.arg1); |
| } else if (msg.what == NEXT_ALARM_CHANGED) { |
| handleNextAlarmChanged(); |
| } |
| } |
| } |
| |
| public interface Callback { |
| void onMoreSettings(); |
| void onInteraction(); |
| void onExpanded(boolean expanded); |
| } |
| |
| // used as the view tag on condition rows |
| private static class ConditionTag { |
| RadioButton rb; |
| Uri conditionId; |
| } |
| |
| private final class Favorites implements OnSharedPreferenceChangeListener { |
| private static final String KEY_MINUTE_INDEX = "minuteIndex"; |
| |
| private int mMinuteIndex; |
| |
| private Favorites() { |
| prefs().registerOnSharedPreferenceChangeListener(this); |
| updateMinuteIndex(); |
| } |
| |
| public int getMinuteIndex() { |
| return mMinuteIndex; |
| } |
| |
| public void setMinuteIndex(int minuteIndex) { |
| minuteIndex = clamp(minuteIndex); |
| if (minuteIndex == mMinuteIndex) return; |
| mMinuteIndex = clamp(minuteIndex); |
| if (DEBUG) Log.d(mTag, "Setting favorite minute index: " + mMinuteIndex); |
| prefs().edit().putInt(KEY_MINUTE_INDEX, mMinuteIndex).apply(); |
| } |
| |
| @Override |
| public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { |
| updateMinuteIndex(); |
| } |
| |
| private SharedPreferences prefs() { |
| return mContext.getSharedPreferences(ZenModePanel.class.getSimpleName(), 0); |
| } |
| |
| private void updateMinuteIndex() { |
| mMinuteIndex = clamp(prefs().getInt(KEY_MINUTE_INDEX, DEFAULT_BUCKET_INDEX)); |
| if (DEBUG) Log.d(mTag, "Favorite minute index: " + mMinuteIndex); |
| } |
| |
| private int clamp(int index) { |
| return Math.max(-1, Math.min(MINUTE_BUCKETS.length - 1, index)); |
| } |
| } |
| |
| private final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() { |
| @Override |
| public void onSelected(Object value) { |
| if (value != null && mZenButtons.isShown()) { |
| if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + value); |
| mController.setZen((Integer) value); |
| mController.setExitConditionId(null); |
| } |
| } |
| }; |
| } |