am 2ea3650d: Merge "Zen: New behavior for built-in downtime + nextalarm conditions." into lmp-mr1-dev
* commit '2ea3650d18ab0ce4dba2cee101d639400b411452': Zen: New behavior for built-in downtime + nextalarm conditions.
This commit is contained in:
@@ -71,6 +71,7 @@ interface INotificationManager
|
||||
|
||||
ComponentName getEffectsSuppressor();
|
||||
boolean matchesCallFilter(in Bundle extras);
|
||||
boolean isSystemConditionProviderEnabled(String path);
|
||||
|
||||
ZenModeConfig getZenModeConfig();
|
||||
boolean setZenModeConfig(in ZenModeConfig config);
|
||||
|
||||
@@ -264,5 +264,17 @@ public class NotificationManager
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public boolean isSystemConditionProviderEnabled(String path) {
|
||||
INotificationManager service = getService();
|
||||
try {
|
||||
return service.isSystemConditionProviderEnabled(path);
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Context mContext;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public class ZenModeConfig implements Parcelable {
|
||||
public static final int[] MINUTE_BUCKETS = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
|
||||
private static final int SECONDS_MS = 1000;
|
||||
private static final int MINUTES_MS = 60 * SECONDS_MS;
|
||||
private static final int ZERO_VALUE_MS = 20 * SECONDS_MS;
|
||||
private static final int ZERO_VALUE_MS = 10 * SECONDS_MS;
|
||||
|
||||
private static final boolean DEFAULT_ALLOW_EVENTS = true;
|
||||
|
||||
@@ -471,6 +471,8 @@ public class ZenModeConfig implements Parcelable {
|
||||
downtime.startMinute = sleepStartMinute;
|
||||
downtime.endHour = sleepEndHour;
|
||||
downtime.endMinute = sleepEndMinute;
|
||||
downtime.mode = sleepMode;
|
||||
downtime.none = sleepNone;
|
||||
return downtime;
|
||||
}
|
||||
|
||||
@@ -510,7 +512,7 @@ public class ZenModeConfig implements Parcelable {
|
||||
public static final String SYSTEM_AUTHORITY = "android";
|
||||
|
||||
// Built-in countdown conditions, e.g. condition://android/countdown/1399917958951
|
||||
private static final String COUNTDOWN_PATH = "countdown";
|
||||
public static final String COUNTDOWN_PATH = "countdown";
|
||||
|
||||
public static Uri toCountdownConditionId(long time) {
|
||||
return new Uri.Builder().scheme(Condition.SCHEME)
|
||||
@@ -536,8 +538,9 @@ public class ZenModeConfig implements Parcelable {
|
||||
return tryParseCountdownConditionId(conditionId) != 0;
|
||||
}
|
||||
|
||||
// Built-in downtime conditions, e.g. condition://android/downtime?start=10.00&end=7.00
|
||||
private static final String DOWNTIME_PATH = "downtime";
|
||||
// Built-in downtime conditions
|
||||
// e.g. condition://android/downtime?start=10.00&end=7.00&mode=days%3A5%2C6&none=false
|
||||
public static final String DOWNTIME_PATH = "downtime";
|
||||
|
||||
public static Uri toDowntimeConditionId(DowntimeInfo downtime) {
|
||||
return new Uri.Builder().scheme(Condition.SCHEME)
|
||||
@@ -545,6 +548,8 @@ public class ZenModeConfig implements Parcelable {
|
||||
.appendPath(DOWNTIME_PATH)
|
||||
.appendQueryParameter("start", downtime.startHour + "." + downtime.startMinute)
|
||||
.appendQueryParameter("end", downtime.endHour + "." + downtime.endMinute)
|
||||
.appendQueryParameter("mode", downtime.mode)
|
||||
.appendQueryParameter("none", Boolean.toString(downtime.none))
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -562,6 +567,8 @@ public class ZenModeConfig implements Parcelable {
|
||||
downtime.startMinute = start[1];
|
||||
downtime.endHour = end[0];
|
||||
downtime.endMinute = end[1];
|
||||
downtime.mode = conditionId.getQueryParameter("mode");
|
||||
downtime.none = Boolean.toString(true).equals(conditionId.getQueryParameter("none"));
|
||||
return downtime;
|
||||
}
|
||||
|
||||
@@ -583,6 +590,8 @@ public class ZenModeConfig implements Parcelable {
|
||||
public int startMinute; // 0-59
|
||||
public int endHour;
|
||||
public int endMinute;
|
||||
public String mode;
|
||||
public boolean none;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
@@ -596,7 +605,12 @@ public class ZenModeConfig implements Parcelable {
|
||||
return startHour == other.startHour
|
||||
&& startMinute == other.startMinute
|
||||
&& endHour == other.endHour
|
||||
&& endMinute == other.endMinute;
|
||||
&& endMinute == other.endMinute
|
||||
&& Objects.equals(mode, other.mode)
|
||||
&& none == other.none;
|
||||
}
|
||||
}
|
||||
|
||||
// built-in next alarm conditions
|
||||
public static final String NEXT_ALARM_PATH = "next_alarm";
|
||||
}
|
||||
|
||||
@@ -1927,9 +1927,19 @@
|
||||
-->
|
||||
<integer name="config_LTE_RSRP_threshold_type">1</integer>
|
||||
|
||||
<!-- Enabled built-in zen mode condition providers -->
|
||||
<string-array translatable="false" name="config_system_condition_providers">
|
||||
<item>countdown</item>
|
||||
<item>downtime</item>
|
||||
<item>next_alarm</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Show the next-alarm as a zen exit condition if it occurs in the next n hours. -->
|
||||
<integer name="config_next_alarm_condition_lookahead_threshold_hrs">12</integer>
|
||||
|
||||
<!-- Show downtime as a zen exit condition if it starts in the next n hours. -->
|
||||
<integer name="config_downtime_condition_lookahead_threshold_hrs">4</integer>
|
||||
|
||||
<!-- Flags enabling default window features. See Window.java -->
|
||||
<bool name="config_defaultWindowFeatureOptionsPanel">true</bool>
|
||||
<bool name="config_defaultWindowFeatureContextMenu">true</bool>
|
||||
|
||||
@@ -2017,7 +2017,9 @@
|
||||
<java-symbol type="string" name="zen_mode_until" />
|
||||
<java-symbol type="string" name="zen_mode_next_alarm_summary" />
|
||||
<java-symbol type="string" name="zen_mode_next_alarm_line_one" />
|
||||
<java-symbol type="array" name="config_system_condition_providers" />
|
||||
<java-symbol type="integer" name="config_next_alarm_condition_lookahead_threshold_hrs" />
|
||||
<java-symbol type="integer" name="config_downtime_condition_lookahead_threshold_hrs" />
|
||||
<java-symbol type="string" name="muted_by" />
|
||||
|
||||
<java-symbol type="string" name="item_is_selected" />
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
android:orientation="vertical" >
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/zen_buttons_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="8dp"
|
||||
|
||||
@@ -287,8 +287,8 @@
|
||||
<!-- Number of times to show the strong alarm warning text in the volume dialog -->
|
||||
<integer name="zen_mode_alarm_warning_threshold">5</integer>
|
||||
|
||||
<!-- Maximum number of optional conditions to display in the zen mode selection panel -->
|
||||
<integer name="zen_mode_max_conditions">3</integer>
|
||||
<!-- Maximum number of total conditions to display in the zen mode selection panel -->
|
||||
<integer name="zen_mode_max_conditions">5</integer>
|
||||
|
||||
<!-- Enable the default volume dialog -->
|
||||
<bool name="enable_volume_ui">true</bool>
|
||||
|
||||
@@ -124,8 +124,7 @@ public class VolumePanel extends Handler implements DemoMode {
|
||||
private static final int MSG_ZEN_MODE_AVAILABLE_CHANGED = 13;
|
||||
private static final int MSG_USER_ACTIVITY = 14;
|
||||
private static final int MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED = 15;
|
||||
private static final int MSG_ZEN_MODE_CHANGED = 16;
|
||||
private static final int MSG_INTERNAL_RINGER_MODE_CHANGED = 17;
|
||||
private static final int MSG_INTERNAL_RINGER_MODE_CHANGED = 16;
|
||||
|
||||
// Pseudo stream type for master volume
|
||||
private static final int STREAM_MASTER = -100;
|
||||
@@ -511,6 +510,9 @@ public class VolumePanel extends Handler implements DemoMode {
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
if (mZenPanel != null) {
|
||||
mZenPanel.dump(fd, pw, args);
|
||||
}
|
||||
}
|
||||
|
||||
private void initZenModePanel() {
|
||||
@@ -723,7 +725,7 @@ public class VolumePanel extends Handler implements DemoMode {
|
||||
mSliderPanel.addView(active.group);
|
||||
mActiveStreamType = activeStreamType;
|
||||
active.group.setVisibility(View.VISIBLE);
|
||||
updateSlider(active);
|
||||
updateSlider(active, true /*forceReloadIcon*/);
|
||||
updateTimeoutDelay();
|
||||
updateZenPanelVisible();
|
||||
}
|
||||
@@ -799,11 +801,12 @@ public class VolumePanel extends Handler implements DemoMode {
|
||||
}
|
||||
|
||||
/** Update the mute and progress state of a slider */
|
||||
private void updateSlider(StreamControl sc) {
|
||||
private void updateSlider(StreamControl sc, boolean forceReloadIcon) {
|
||||
updateSliderProgress(sc, -1);
|
||||
final boolean muted = isMuted(sc.streamType);
|
||||
// Force reloading the image resource
|
||||
sc.icon.setImageDrawable(null);
|
||||
if (forceReloadIcon) {
|
||||
sc.icon.setImageDrawable(null);
|
||||
}
|
||||
updateSliderIcon(sc, muted);
|
||||
updateSliderEnabled(sc, muted, false);
|
||||
updateSliderSuppressor(sc);
|
||||
@@ -907,11 +910,18 @@ public class VolumePanel extends Handler implements DemoMode {
|
||||
}
|
||||
}
|
||||
|
||||
public void updateStates() {
|
||||
private void updateStates() {
|
||||
final int count = mSliderPanel.getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
StreamControl sc = (StreamControl) mSliderPanel.getChildAt(i).getTag();
|
||||
updateSlider(sc);
|
||||
updateSlider(sc, true /*forceReloadIcon*/);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateActiveSlider() {
|
||||
final StreamControl active = mStreamControls.get(mActiveStreamType);
|
||||
if (active != null) {
|
||||
updateSlider(active, false /*forceReloadIcon*/);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1449,12 +1459,11 @@ public class VolumePanel extends Handler implements DemoMode {
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_ZEN_MODE_CHANGED:
|
||||
case MSG_RINGER_MODE_CHANGED:
|
||||
case MSG_INTERNAL_RINGER_MODE_CHANGED:
|
||||
case MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED: {
|
||||
if (isShowing()) {
|
||||
updateStates();
|
||||
updateActiveSlider();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1563,10 +1572,6 @@ public class VolumePanel extends Handler implements DemoMode {
|
||||
mNotificationEffectsSuppressor = mZenController.getEffectsSuppressor();
|
||||
sendEmptyMessage(MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED);
|
||||
}
|
||||
|
||||
public void onZenChanged(int zen) {
|
||||
sendEmptyMessage(MSG_ZEN_MODE_CHANGED);
|
||||
}
|
||||
};
|
||||
|
||||
private final MediaController.Callback mMediaControllerCb = new MediaController.Callback() {
|
||||
@@ -1591,6 +1596,7 @@ public class VolumePanel extends Handler implements DemoMode {
|
||||
|
||||
public void start(StreamControl sc) {
|
||||
if (sc == null) throw new IllegalArgumentException();
|
||||
if (LOGD) Log.d(mTag, "Secondary icon animation start");
|
||||
if (mTarget != null) {
|
||||
cancel();
|
||||
}
|
||||
@@ -1643,6 +1649,7 @@ public class VolumePanel extends Handler implements DemoMode {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mTarget == null) return;
|
||||
if (LOGD) Log.d(mTag, "Secondary icon animation complete, show notification slider");
|
||||
mAudioManager.forceVolumeControlStream(StreamResources.NotificationStream.streamType);
|
||||
mAudioManager.adjustStreamVolume(StreamResources.NotificationStream.streamType,
|
||||
AudioManager.ADJUST_SAME, AudioManager.FLAG_SHOW_UI);
|
||||
|
||||
@@ -17,13 +17,16 @@
|
||||
package com.android.systemui.volume;
|
||||
|
||||
import android.animation.LayoutTransition;
|
||||
import android.animation.LayoutTransition.TransitionListener;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
@@ -32,6 +35,7 @@ import android.provider.Settings.Global;
|
||||
import android.service.notification.Condition;
|
||||
import android.service.notification.ZenModeConfig;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.MathUtils;
|
||||
@@ -50,6 +54,8 @@ import android.widget.TextView;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -67,8 +73,7 @@ public class ZenModePanel extends LinearLayout {
|
||||
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 int COUNTDOWN_CONDITION_INDEX = 1;
|
||||
|
||||
public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
|
||||
|
||||
@@ -81,6 +86,10 @@ public class ZenModePanel extends LinearLayout {
|
||||
private final int mSubheadColor;
|
||||
private final Interpolator mInterpolator;
|
||||
private final int mMaxConditions;
|
||||
private final int mMaxOptionalConditions;
|
||||
private final boolean mCountdownConditionSupported;
|
||||
private final int mFirstConditionIndex;
|
||||
private final TransitionHelper mTransitionHelper = new TransitionHelper();
|
||||
|
||||
private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
|
||||
|
||||
@@ -98,7 +107,7 @@ public class ZenModePanel extends LinearLayout {
|
||||
private String mExitConditionText;
|
||||
private int mBucketIndex = -1;
|
||||
private boolean mExpanded;
|
||||
private boolean mHidden = false;
|
||||
private boolean mHidden;
|
||||
private int mSessionZen;
|
||||
private int mAttachedZen;
|
||||
private boolean mAttached;
|
||||
@@ -117,11 +126,30 @@ public class ZenModePanel extends LinearLayout {
|
||||
mSubheadColor = res.getColor(R.color.qs_subhead);
|
||||
mInterpolator = AnimationUtils.loadInterpolator(mContext,
|
||||
com.android.internal.R.interpolator.fast_out_slow_in);
|
||||
mCountdownConditionSupported = NotificationManager.from(mContext)
|
||||
.isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH);
|
||||
final int countdownDelta = mCountdownConditionSupported ? 1 : 0;
|
||||
mFirstConditionIndex = COUNTDOWN_CONDITION_INDEX + countdownDelta;
|
||||
final int minConditions = 1 /*forever*/ + countdownDelta;
|
||||
mMaxConditions = MathUtils.constrain(res.getInteger(R.integer.zen_mode_max_conditions),
|
||||
1, 100);
|
||||
minConditions, 100);
|
||||
mMaxOptionalConditions = mMaxConditions - minConditions;
|
||||
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(" mMaxConditions="); pw.println(mMaxConditions);
|
||||
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);
|
||||
mTransitionHelper.dump(fd, pw, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
@@ -135,6 +163,9 @@ public class ZenModePanel extends LinearLayout {
|
||||
Global.ZEN_MODE_OFF);
|
||||
mZenButtons.setCallback(mZenButtonsCallback);
|
||||
|
||||
final ViewGroup zenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
|
||||
zenButtonsContainer.setLayoutTransition(newLayoutTransition(null));
|
||||
|
||||
mZenSubhead = findViewById(R.id.zen_subhead);
|
||||
|
||||
mZenSubheadCollapsed = (TextView) findViewById(R.id.zen_subhead_collapsed);
|
||||
@@ -159,15 +190,22 @@ public class ZenModePanel extends LinearLayout {
|
||||
Interaction.register(mMoreSettings, mInteractionCallback);
|
||||
|
||||
mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions);
|
||||
setLayoutTransition(newLayoutTransition());
|
||||
for (int i = 0; i < mMaxConditions; i++) {
|
||||
mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
|
||||
}
|
||||
|
||||
setLayoutTransition(newLayoutTransition(mTransitionHelper));
|
||||
}
|
||||
|
||||
private LayoutTransition newLayoutTransition() {
|
||||
private LayoutTransition newLayoutTransition(TransitionListener listener) {
|
||||
final LayoutTransition transition = new LayoutTransition();
|
||||
transition.disableTransitionType(LayoutTransition.DISAPPEARING);
|
||||
transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
|
||||
transition.setInterpolator(LayoutTransition.APPEARING, mInterpolator);
|
||||
transition.disableTransitionType(LayoutTransition.APPEARING);
|
||||
transition.setInterpolator(LayoutTransition.CHANGE_APPEARING, mInterpolator);
|
||||
if (listener != null) {
|
||||
transition.addTransitionListener(listener);
|
||||
}
|
||||
return transition;
|
||||
}
|
||||
|
||||
@@ -175,11 +213,11 @@ public class ZenModePanel extends LinearLayout {
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
if (DEBUG) Log.d(mTag, "onAttachedToWindow");
|
||||
((ViewGroup) getParent()).setLayoutTransition(newLayoutTransition());
|
||||
mAttached = true;
|
||||
mAttachedZen = getSelectedZen(-1);
|
||||
mSessionZen = mAttachedZen;
|
||||
mSessionExitCondition = copy(mExitCondition);
|
||||
mTransitionHelper.clear();
|
||||
setSessionExitCondition(copy(mExitCondition));
|
||||
refreshExitConditionText();
|
||||
updateWidgets();
|
||||
setRequestingConditions(!mHidden);
|
||||
@@ -193,9 +231,16 @@ public class ZenModePanel extends LinearLayout {
|
||||
mAttached = false;
|
||||
mAttachedZen = -1;
|
||||
mSessionZen = -1;
|
||||
mSessionExitCondition = null;
|
||||
setSessionExitCondition(null);
|
||||
setExpanded(false);
|
||||
setRequestingConditions(false);
|
||||
mTransitionHelper.clear();
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -228,12 +273,17 @@ public class ZenModePanel extends LinearLayout {
|
||||
}
|
||||
|
||||
/** Start or stop requesting relevant zen mode exit conditions */
|
||||
private void setRequestingConditions(boolean requesting) {
|
||||
private void setRequestingConditions(final boolean requesting) {
|
||||
if (mRequestingConditions == requesting) return;
|
||||
if (DEBUG) Log.d(mTag, "setRequestingConditions " + requesting);
|
||||
mRequestingConditions = requesting;
|
||||
if (mController != null) {
|
||||
mController.requestConditions(mRequestingConditions);
|
||||
AsyncTask.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mController.requestConditions(requesting);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (mRequestingConditions) {
|
||||
mTimeCondition = parseExistingTimeCondition(mExitCondition);
|
||||
@@ -248,7 +298,7 @@ public class ZenModePanel extends LinearLayout {
|
||||
mConditions = null; // reset conditions
|
||||
handleUpdateConditions();
|
||||
} else {
|
||||
mZenConditions.removeAllViews();
|
||||
hideAllConditions();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +309,7 @@ public class ZenModePanel extends LinearLayout {
|
||||
mSessionZen = getSelectedZen(-1);
|
||||
handleUpdateZen(mController.getZen());
|
||||
if (DEBUG) Log.d(mTag, "init mExitCondition=" + mExitCondition);
|
||||
mZenConditions.removeAllViews();
|
||||
hideAllConditions();
|
||||
mController.addCallback(mZenCallback);
|
||||
}
|
||||
|
||||
@@ -270,6 +320,7 @@ public class ZenModePanel extends LinearLayout {
|
||||
private void setExitCondition(Condition exitCondition) {
|
||||
if (Objects.equals(mExitCondition, exitCondition)) return;
|
||||
mExitCondition = exitCondition;
|
||||
if (DEBUG) Log.d(mTag, "mExitCondition=" + getConditionId(mExitCondition));
|
||||
refreshExitConditionText();
|
||||
updateWidgets();
|
||||
}
|
||||
@@ -290,7 +341,7 @@ public class ZenModePanel extends LinearLayout {
|
||||
final String forever = mContext.getString(com.android.internal.R.string.zen_mode_forever);
|
||||
if (mExitCondition == null) {
|
||||
mExitConditionText = forever;
|
||||
} else if (ZenModeConfig.isValidCountdownConditionId(mExitCondition.id)) {
|
||||
} else if (isCountdown(mExitCondition)) {
|
||||
final Condition condition = parseExistingTimeCondition(mExitCondition);
|
||||
mExitConditionText = condition != null ? condition.summary : forever;
|
||||
} else {
|
||||
@@ -316,6 +367,24 @@ public class ZenModePanel extends LinearLayout {
|
||||
}
|
||||
mZenButtons.setSelectedValue(zen);
|
||||
updateWidgets();
|
||||
handleUpdateConditions();
|
||||
if (mExpanded) {
|
||||
final Condition selected = getSelectedCondition();
|
||||
if (!Objects.equals(mExitCondition, selected)) {
|
||||
select(selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -324,6 +393,10 @@ public class ZenModePanel extends LinearLayout {
|
||||
}
|
||||
|
||||
private void updateWidgets() {
|
||||
if (mTransitionHelper.isTransitioning()) {
|
||||
mTransitionHelper.pendingUpdateWidgets();
|
||||
return;
|
||||
}
|
||||
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;
|
||||
@@ -371,7 +444,7 @@ public class ZenModePanel extends LinearLayout {
|
||||
}
|
||||
|
||||
private Condition[] trimConditions(Condition[] conditions) {
|
||||
if (conditions == null || conditions.length <= mMaxConditions) {
|
||||
if (conditions == null || conditions.length <= mMaxOptionalConditions) {
|
||||
// no need to trim
|
||||
return conditions;
|
||||
}
|
||||
@@ -384,33 +457,34 @@ public class ZenModePanel extends LinearLayout {
|
||||
break;
|
||||
}
|
||||
}
|
||||
final Condition[] rt = Arrays.copyOf(conditions, mMaxConditions);
|
||||
if (found >= mMaxConditions) {
|
||||
final Condition[] rt = Arrays.copyOf(conditions, mMaxOptionalConditions);
|
||||
if (found >= mMaxOptionalConditions) {
|
||||
// found after the first N, promote to the end of the first N
|
||||
rt[mMaxConditions - 1] = conditions[found];
|
||||
rt[mMaxOptionalConditions - 1] = conditions[found];
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
|
||||
private void handleUpdateConditions() {
|
||||
if (mTransitionHelper.isTransitioning()) {
|
||||
mTransitionHelper.pendingUpdateConditions();
|
||||
return;
|
||||
}
|
||||
final int conditionCount = mConditions == null ? 0 : mConditions.length;
|
||||
if (DEBUG) Log.d(mTag, "handleUpdateConditions conditionCount=" + conditionCount);
|
||||
for (int i = mZenConditions.getChildCount() - 1; i >= FIRST_CONDITION_INDEX; i--) {
|
||||
mZenConditions.removeViewAt(i);
|
||||
}
|
||||
// forever
|
||||
bind(null, mZenConditions.getChildAt(FOREVER_CONDITION_INDEX));
|
||||
// countdown
|
||||
bind(mTimeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
|
||||
// provider conditions
|
||||
boolean foundDowntime = false;
|
||||
for (int i = 0; i < conditionCount; i++) {
|
||||
bind(mConditions[i], mZenConditions.getChildAt(FIRST_CONDITION_INDEX + i));
|
||||
foundDowntime |= isDowntime(mConditions[i]);
|
||||
if (mCountdownConditionSupported) {
|
||||
bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX));
|
||||
}
|
||||
// ensure downtime exists, if active
|
||||
if (isDowntime(mSessionExitCondition) && !foundDowntime) {
|
||||
bind(mSessionExitCondition, null);
|
||||
// provider conditions
|
||||
for (int i = 0; i < conditionCount; i++) {
|
||||
bind(mConditions[i], mZenConditions.getChildAt(mFirstConditionIndex + i));
|
||||
}
|
||||
// hide the rest
|
||||
for (int i = mZenConditions.getChildCount() - 1; i > mFirstConditionIndex + conditionCount; i--) {
|
||||
mZenConditions.getChildAt(i).setVisibility(GONE);
|
||||
}
|
||||
// ensure something is selected
|
||||
if (mExpanded) {
|
||||
@@ -418,78 +492,101 @@ public class ZenModePanel extends LinearLayout {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isDowntime(Condition c) {
|
||||
return ZenModeConfig.isValidDowntimeConditionId(getConditionId(c));
|
||||
}
|
||||
|
||||
private ConditionTag getConditionTagAt(int index) {
|
||||
return (ConditionTag) mZenConditions.getChildAt(index).getTag();
|
||||
}
|
||||
|
||||
private int getVisibleConditions() {
|
||||
int rt = 0;
|
||||
final int N = mZenConditions.getChildCount();
|
||||
for (int i = 0; i < N; i++) {
|
||||
rt += mZenConditions.getChildAt(i).getVisibility() == VISIBLE ? 1 : 0;
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
|
||||
private void hideAllConditions() {
|
||||
final int N = mZenConditions.getChildCount();
|
||||
for (int i = 0; i < N; i++) {
|
||||
mZenConditions.getChildAt(i).setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureSelection() {
|
||||
// are we left without anything selected? if so, set a default
|
||||
if (mZenConditions.getChildCount() == 0) return;
|
||||
for (int i = 0; i < mZenConditions.getChildCount(); i++) {
|
||||
if (getConditionTagAt(i).rb.isChecked()) {
|
||||
if (DEBUG) Log.d(mTag, "Not selecting a default, checked="
|
||||
+ getConditionTagAt(i).condition);
|
||||
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 (favoriteIndex == -1) {
|
||||
getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true);
|
||||
if (favoriteIndex == -1 || !mCountdownConditionSupported) {
|
||||
foreverTag.rb.setChecked(true);
|
||||
} else {
|
||||
mTimeCondition = ZenModeConfig.toTimeCondition(mContext,
|
||||
MINUTE_BUCKETS[favoriteIndex], ActivityManager.getCurrentUser());
|
||||
mBucketIndex = favoriteIndex;
|
||||
bind(mTimeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
|
||||
getConditionTagAt(TIME_CONDITION_INDEX).rb.setChecked(true);
|
||||
bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX));
|
||||
getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb.setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleExitConditionChanged(Condition exitCondition) {
|
||||
setExitCondition(exitCondition);
|
||||
if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitCondition);
|
||||
final int N = mZenConditions.getChildCount();
|
||||
final int N = getVisibleConditions();
|
||||
for (int i = 0; i < N; i++) {
|
||||
final ConditionTag tag = getConditionTagAt(i);
|
||||
tag.rb.setChecked(sameConditionId(tag.condition, mExitCondition));
|
||||
if (tag != null) {
|
||||
if (sameConditionId(tag.condition, mExitCondition)) {
|
||||
bind(exitCondition, mZenConditions.getChildAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void bind(final Condition condition, View convertView) {
|
||||
private boolean isCountdown(Condition c) {
|
||||
return c != null && ZenModeConfig.isValidCountdownConditionId(c.id);
|
||||
}
|
||||
|
||||
private void bind(final Condition condition, final View row) {
|
||||
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);
|
||||
final boolean first = tag.rb == null;
|
||||
if (tag.rb == null) {
|
||||
tag.rb = (RadioButton) row.findViewById(android.R.id.checkbox);
|
||||
}
|
||||
tag.condition = condition;
|
||||
final Uri conditionId = getConditionId(tag.condition);
|
||||
if (DEBUG) Log.d(mTag, "bind i=" + mZenConditions.indexOfChild(row) + " first=" + first
|
||||
+ " condition=" + conditionId);
|
||||
tag.rb.setEnabled(enabled);
|
||||
if ((mSessionExitCondition != null || mAttachedZen != Global.ZEN_MODE_OFF)
|
||||
&& sameConditionId(mSessionExitCondition, tag.condition)) {
|
||||
tag.rb.setChecked(true);
|
||||
final boolean checked = (mSessionExitCondition != null
|
||||
|| mAttachedZen != Global.ZEN_MODE_OFF)
|
||||
&& (sameConditionId(mSessionExitCondition, tag.condition)
|
||||
|| isCountdown(mSessionExitCondition) && isCountdown(tag.condition));
|
||||
if (checked != tag.rb.isChecked()) {
|
||||
if (DEBUG) Log.d(mTag, "bind checked=" + checked + " condition=" + conditionId);
|
||||
tag.rb.setChecked(checked);
|
||||
}
|
||||
tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (mExpanded && isChecked) {
|
||||
if (DEBUG) Log.d(mTag, "onCheckedChanged " + tag.condition);
|
||||
final int N = mZenConditions.getChildCount();
|
||||
if (DEBUG) Log.d(mTag, "onCheckedChanged " + conditionId);
|
||||
final int N = getVisibleConditions();
|
||||
for (int i = 0; i < N; i++) {
|
||||
ConditionTag childTag = getConditionTagAt(i);
|
||||
if (childTag == tag) continue;
|
||||
final ConditionTag childTag = getConditionTagAt(i);
|
||||
if (childTag == null || childTag == tag) continue;
|
||||
childTag.rb.setChecked(false);
|
||||
}
|
||||
select(tag.condition);
|
||||
@@ -547,8 +644,10 @@ public class ZenModePanel extends LinearLayout {
|
||||
}
|
||||
});
|
||||
|
||||
final long time = ZenModeConfig.tryParseCountdownConditionId(getConditionId(tag.condition));
|
||||
final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
|
||||
if (time > 0) {
|
||||
button1.setVisibility(VISIBLE);
|
||||
button2.setVisibility(VISIBLE);
|
||||
if (mBucketIndex > -1) {
|
||||
button1.setEnabled(mBucketIndex > 0);
|
||||
button2.setEnabled(mBucketIndex < MINUTE_BUCKETS.length - 1);
|
||||
@@ -563,16 +662,17 @@ public class ZenModePanel extends LinearLayout {
|
||||
button1.setAlpha(button1.isEnabled() ? 1f : .5f);
|
||||
button2.setAlpha(button2.isEnabled() ? 1f : .5f);
|
||||
} else {
|
||||
button1.setVisibility(View.GONE);
|
||||
button2.setVisibility(View.GONE);
|
||||
button1.setVisibility(GONE);
|
||||
button2.setVisibility(GONE);
|
||||
}
|
||||
// wire up interaction callbacks for newly-added condition rows
|
||||
if (convertView == null) {
|
||||
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) {
|
||||
@@ -629,18 +729,23 @@ public class ZenModePanel extends LinearLayout {
|
||||
announceConditionSelection(tag);
|
||||
}
|
||||
|
||||
private void select(Condition condition) {
|
||||
private void select(final Condition condition) {
|
||||
if (DEBUG) Log.d(mTag, "select " + condition);
|
||||
if (mController != null) {
|
||||
mController.setExitCondition(condition);
|
||||
AsyncTask.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mController.setExitCondition(condition);
|
||||
}
|
||||
});
|
||||
}
|
||||
setExitCondition(condition);
|
||||
if (condition == null) {
|
||||
mPrefs.setMinuteIndex(-1);
|
||||
} else if (ZenModeConfig.isValidCountdownConditionId(condition.id) && mBucketIndex != -1) {
|
||||
} else if (isCountdown(condition) && mBucketIndex != -1) {
|
||||
mPrefs.setMinuteIndex(mBucketIndex);
|
||||
}
|
||||
mSessionExitCondition = copy(condition);
|
||||
setSessionExitCondition(copy(condition));
|
||||
}
|
||||
|
||||
private void fireMoreSettings() {
|
||||
@@ -784,10 +889,15 @@ public class ZenModePanel extends LinearLayout {
|
||||
|
||||
private final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() {
|
||||
@Override
|
||||
public void onSelected(Object value) {
|
||||
public void onSelected(final Object value) {
|
||||
if (value != null && mZenButtons.isShown()) {
|
||||
if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + value);
|
||||
mController.setZen((Integer) value);
|
||||
AsyncTask.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mController.setZen((Integer) value);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -803,4 +913,79 @@ public class ZenModePanel extends LinearLayout {
|
||||
fireInteraction();
|
||||
}
|
||||
};
|
||||
|
||||
private final class TransitionHelper implements TransitionListener, Runnable {
|
||||
private final ArraySet<View> mTransitioningViews = new ArraySet<View>();
|
||||
|
||||
private boolean mTransitioning;
|
||||
private boolean mPendingUpdateConditions;
|
||||
private boolean mPendingUpdateWidgets;
|
||||
|
||||
public void clear() {
|
||||
mTransitioningViews.clear();
|
||||
mPendingUpdateConditions = mPendingUpdateWidgets = false;
|
||||
}
|
||||
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println(" TransitionHelper state:");
|
||||
pw.print(" mPendingUpdateConditions="); pw.println(mPendingUpdateConditions);
|
||||
pw.print(" mPendingUpdateWidgets="); pw.println(mPendingUpdateWidgets);
|
||||
pw.print(" mTransitioning="); pw.println(mTransitioning);
|
||||
pw.print(" mTransitioningViews="); pw.println(mTransitioningViews);
|
||||
}
|
||||
|
||||
public void pendingUpdateConditions() {
|
||||
mPendingUpdateConditions = true;
|
||||
}
|
||||
|
||||
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
|
||||
+ " mPendingUpdateConditions=" + mPendingUpdateConditions);
|
||||
if (mPendingUpdateWidgets) {
|
||||
updateWidgets();
|
||||
}
|
||||
if (mPendingUpdateConditions) {
|
||||
handleUpdateConditions();
|
||||
}
|
||||
mPendingUpdateWidgets = mPendingUpdateConditions = 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 (mPendingUpdateConditions || mPendingUpdateWidgets) {
|
||||
mHandler.post(this);
|
||||
} else {
|
||||
mPendingUpdateConditions = mPendingUpdateWidgets = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,10 +50,11 @@ public class ConditionProviders extends ManagedServices {
|
||||
private final ArrayMap<IBinder, IConditionListener> mListeners
|
||||
= new ArrayMap<IBinder, IConditionListener>();
|
||||
private final ArrayList<ConditionRecord> mRecords = new ArrayList<ConditionRecord>();
|
||||
private final CountdownConditionProvider mCountdown = new CountdownConditionProvider();
|
||||
private final ArraySet<String> mSystemConditionProviders;
|
||||
private final CountdownConditionProvider mCountdown;
|
||||
private final DowntimeConditionProvider mDowntime;
|
||||
private final NextAlarmConditionProvider mNextAlarm;
|
||||
private final NextAlarmTracker mNextAlarmTracker;
|
||||
private final DowntimeConditionProvider mDowntime = new DowntimeConditionProvider();
|
||||
private final NextAlarmConditionProvider mNextAlarm = new NextAlarmConditionProvider();
|
||||
|
||||
private Condition mExitCondition;
|
||||
private ComponentName mExitConditionComponent;
|
||||
@@ -63,8 +64,22 @@ public class ConditionProviders extends ManagedServices {
|
||||
super(context, handler, new Object(), userProfiles);
|
||||
mZenModeHelper = zenModeHelper;
|
||||
mZenModeHelper.addCallback(new ZenModeHelperCallback());
|
||||
mSystemConditionProviders = safeSet(PropConfig.getStringArray(mContext,
|
||||
"system.condition.providers",
|
||||
R.array.config_system_condition_providers));
|
||||
final boolean countdown = mSystemConditionProviders.contains(ZenModeConfig.COUNTDOWN_PATH);
|
||||
final boolean downtime = mSystemConditionProviders.contains(ZenModeConfig.DOWNTIME_PATH);
|
||||
final boolean nextAlarm = mSystemConditionProviders.contains(ZenModeConfig.NEXT_ALARM_PATH);
|
||||
mNextAlarmTracker = (downtime || nextAlarm) ? new NextAlarmTracker(mContext) : null;
|
||||
mCountdown = countdown ? new CountdownConditionProvider() : null;
|
||||
mDowntime = downtime ? new DowntimeConditionProvider(this, mNextAlarmTracker,
|
||||
mZenModeHelper) : null;
|
||||
mNextAlarm = nextAlarm ? new NextAlarmConditionProvider(mNextAlarmTracker) : null;
|
||||
loadZenConfig();
|
||||
mNextAlarmTracker = new NextAlarmTracker(context);
|
||||
}
|
||||
|
||||
public boolean isSystemConditionProviderEnabled(String path) {
|
||||
return mSystemConditionProviders.contains(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,10 +115,19 @@ public class ConditionProviders extends ManagedServices {
|
||||
}
|
||||
}
|
||||
}
|
||||
mCountdown.dump(pw, filter);
|
||||
mDowntime.dump(pw, filter);
|
||||
mNextAlarm.dump(pw, filter);
|
||||
mNextAlarmTracker.dump(pw, filter);
|
||||
pw.print(" mSystemConditionProviders: "); pw.println(mSystemConditionProviders);
|
||||
if (mCountdown != null) {
|
||||
mCountdown.dump(pw, filter);
|
||||
}
|
||||
if (mDowntime != null) {
|
||||
mDowntime.dump(pw, filter);
|
||||
}
|
||||
if (mNextAlarm != null) {
|
||||
mNextAlarm.dump(pw, filter);
|
||||
}
|
||||
if (mNextAlarmTracker != null) {
|
||||
mNextAlarmTracker.dump(pw, filter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,24 +138,32 @@ public class ConditionProviders extends ManagedServices {
|
||||
@Override
|
||||
public void onBootPhaseAppsCanStart() {
|
||||
super.onBootPhaseAppsCanStart();
|
||||
mNextAlarmTracker.init();
|
||||
mCountdown.attachBase(mContext);
|
||||
registerService(mCountdown.asInterface(), CountdownConditionProvider.COMPONENT,
|
||||
UserHandle.USER_OWNER);
|
||||
mDowntime.attachBase(mContext);
|
||||
registerService(mDowntime.asInterface(), DowntimeConditionProvider.COMPONENT,
|
||||
UserHandle.USER_OWNER);
|
||||
mDowntime.setCallback(new DowntimeCallback());
|
||||
mNextAlarm.attachBase(mContext);
|
||||
registerService(mNextAlarm.asInterface(), NextAlarmConditionProvider.COMPONENT,
|
||||
UserHandle.USER_OWNER);
|
||||
mNextAlarm.setCallback(new NextAlarmCallback());
|
||||
if (mNextAlarmTracker != null) {
|
||||
mNextAlarmTracker.init();
|
||||
}
|
||||
if (mCountdown != null) {
|
||||
mCountdown.attachBase(mContext);
|
||||
registerService(mCountdown.asInterface(), CountdownConditionProvider.COMPONENT,
|
||||
UserHandle.USER_OWNER);
|
||||
}
|
||||
if (mDowntime != null) {
|
||||
mDowntime.attachBase(mContext);
|
||||
registerService(mDowntime.asInterface(), DowntimeConditionProvider.COMPONENT,
|
||||
UserHandle.USER_OWNER);
|
||||
}
|
||||
if (mNextAlarm != null) {
|
||||
mNextAlarm.attachBase(mContext);
|
||||
registerService(mNextAlarm.asInterface(), NextAlarmConditionProvider.COMPONENT,
|
||||
UserHandle.USER_OWNER);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserSwitched() {
|
||||
super.onUserSwitched();
|
||||
mNextAlarmTracker.onUserSwitched();
|
||||
if (mNextAlarmTracker != null) {
|
||||
mNextAlarmTracker.onUserSwitched();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -171,6 +203,7 @@ public class ConditionProviders extends ManagedServices {
|
||||
if (!r.component.equals(removed.component)) continue;
|
||||
if (r.isManual) {
|
||||
// removing the current manual condition, exit zen
|
||||
onManualConditionClearing();
|
||||
mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "manualServiceRemoved");
|
||||
}
|
||||
if (r.isAutomatic) {
|
||||
@@ -273,6 +306,7 @@ public class ConditionProviders extends ManagedServices {
|
||||
} else if (DEBUG) {
|
||||
Slog.d(TAG, "Exit zen: manual condition false: " + c);
|
||||
}
|
||||
onManualConditionClearing();
|
||||
mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF,
|
||||
"manualConditionExit");
|
||||
unsubscribeLocked(r);
|
||||
@@ -304,28 +338,28 @@ public class ConditionProviders extends ManagedServices {
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureRecordExists(Condition condition, IConditionProvider provider,
|
||||
ComponentName component) {
|
||||
// constructed by convention, make sure the record exists...
|
||||
final ConditionRecord r = getRecordLocked(condition.id, component);
|
||||
if (r.info == null) {
|
||||
// ... and is associated with the in-process service
|
||||
r.info = checkServiceTokenLocked(provider);
|
||||
}
|
||||
}
|
||||
|
||||
public void setZenModeCondition(Condition condition, String reason) {
|
||||
if (DEBUG) Slog.d(TAG, "setZenModeCondition " + condition);
|
||||
if (DEBUG) Slog.d(TAG, "setZenModeCondition " + condition + " reason=" + reason);
|
||||
synchronized(mMutex) {
|
||||
ComponentName conditionComponent = null;
|
||||
if (condition != null) {
|
||||
if (ZenModeConfig.isValidCountdownConditionId(condition.id)) {
|
||||
// constructed by the client, make sure the record exists...
|
||||
final ConditionRecord r = getRecordLocked(condition.id,
|
||||
if (mCountdown != null && ZenModeConfig.isValidCountdownConditionId(condition.id)) {
|
||||
ensureRecordExists(condition, mCountdown.asInterface(),
|
||||
CountdownConditionProvider.COMPONENT);
|
||||
if (r.info == null) {
|
||||
// ... and is associated with the in-process service
|
||||
r.info = checkServiceTokenLocked(mCountdown.asInterface());
|
||||
}
|
||||
}
|
||||
if (ZenModeConfig.isValidDowntimeConditionId(condition.id)) {
|
||||
// constructed by the client, make sure the record exists...
|
||||
final ConditionRecord r = getRecordLocked(condition.id,
|
||||
if (mDowntime != null && ZenModeConfig.isValidDowntimeConditionId(condition.id)) {
|
||||
ensureRecordExists(condition, mDowntime.asInterface(),
|
||||
DowntimeConditionProvider.COMPONENT);
|
||||
if (r.info == null) {
|
||||
// ... and is associated with the in-process service
|
||||
r.info = checkServiceTokenLocked(mDowntime.asInterface());
|
||||
}
|
||||
}
|
||||
}
|
||||
final int N = mRecords.size();
|
||||
@@ -370,6 +404,7 @@ public class ConditionProviders extends ManagedServices {
|
||||
ZenLog.traceSubscribe(r != null ? r.id : null, provider, re);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private static <T> ArraySet<T> safeSet(T... items) {
|
||||
final ArraySet<T> rt = new ArraySet<T>();
|
||||
if (items == null || items.length == 0) return rt;
|
||||
@@ -485,7 +520,9 @@ public class ConditionProviders extends ManagedServices {
|
||||
if (changingExit) {
|
||||
ZenLog.traceExitCondition(mExitCondition, mExitConditionComponent, "config");
|
||||
}
|
||||
mDowntime.setConfig(config);
|
||||
if (mDowntime != null) {
|
||||
mDowntime.setConfig(config);
|
||||
}
|
||||
if (config.conditionComponents == null || config.conditionIds == null
|
||||
|| config.conditionComponents.length != config.conditionIds.length) {
|
||||
if (DEBUG) Slog.d(TAG, "loadZenConfig: no conditions");
|
||||
@@ -538,6 +575,12 @@ public class ConditionProviders extends ManagedServices {
|
||||
mZenModeHelper.setConfig(config);
|
||||
}
|
||||
|
||||
private void onManualConditionClearing() {
|
||||
if (mDowntime != null) {
|
||||
mDowntime.onManualConditionClearing();
|
||||
}
|
||||
}
|
||||
|
||||
private class ZenModeHelperCallback extends ZenModeHelper.Callback {
|
||||
@Override
|
||||
void onConfigChanged() {
|
||||
@@ -554,46 +597,6 @@ public class ConditionProviders extends ManagedServices {
|
||||
}
|
||||
}
|
||||
|
||||
private class DowntimeCallback implements DowntimeConditionProvider.Callback {
|
||||
@Override
|
||||
public void onDowntimeChanged(int downtimeMode) {
|
||||
final int mode = mZenModeHelper.getZenMode();
|
||||
final ZenModeConfig config = mZenModeHelper.getConfig();
|
||||
final boolean inDowntime = downtimeMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
|
||||
|| downtimeMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
|
||||
final boolean downtimeCurrent = mDowntime.isDowntimeCondition(mExitCondition);
|
||||
// enter downtime, or update mode if reconfigured during an active downtime
|
||||
if (inDowntime && (mode == Global.ZEN_MODE_OFF || downtimeCurrent) && config != null) {
|
||||
final Condition condition = mDowntime.createCondition(config.toDowntimeInfo(),
|
||||
config.sleepNone, Condition.STATE_TRUE);
|
||||
mZenModeHelper.setZenMode(downtimeMode, "downtimeEnter");
|
||||
setZenModeCondition(condition, "downtime");
|
||||
}
|
||||
// exit downtime
|
||||
if (!inDowntime && downtimeCurrent && (mode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
|
||||
|| mode == Global.ZEN_MODE_NO_INTERRUPTIONS)) {
|
||||
mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "downtimeExit");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NextAlarmTracker getNextAlarmTracker() {
|
||||
return mNextAlarmTracker;
|
||||
}
|
||||
}
|
||||
|
||||
private class NextAlarmCallback implements NextAlarmConditionProvider.Callback {
|
||||
@Override
|
||||
public boolean isInDowntime() {
|
||||
return mDowntime.isInDowntime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NextAlarmTracker getNextAlarmTracker() {
|
||||
return mNextAlarmTracker;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConditionRecord {
|
||||
public final Uri id;
|
||||
public final ComponentName component;
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* 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.server.notification;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import android.service.notification.ZenModeConfig;
|
||||
import android.service.notification.ZenModeConfig.DowntimeInfo;
|
||||
import android.util.ArraySet;
|
||||
|
||||
public class DowntimeCalendar {
|
||||
|
||||
private final ArraySet<Integer> mDays = new ArraySet<Integer>();
|
||||
private final Calendar mCalendar = Calendar.getInstance();
|
||||
|
||||
private DowntimeInfo mInfo;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DowntimeCalendar[mDays=" + mDays + "]";
|
||||
}
|
||||
|
||||
public void setDowntimeInfo(DowntimeInfo info) {
|
||||
if (Objects.equals(mInfo, info)) return;
|
||||
mInfo = info;
|
||||
updateDays();
|
||||
}
|
||||
|
||||
public long nextDowntimeStart(long time) {
|
||||
if (mInfo == null || mDays.size() == 0) return Long.MAX_VALUE;
|
||||
final long start = getTime(time, mInfo.startHour, mInfo.startMinute);
|
||||
for (int i = 0; i < Calendar.SATURDAY; i++) {
|
||||
final long t = addDays(start, i);
|
||||
if (t > time && isInDowntime(t)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
public void setTimeZone(TimeZone tz) {
|
||||
mCalendar.setTimeZone(tz);
|
||||
}
|
||||
|
||||
public long getNextTime(long now, int hr, int min) {
|
||||
final long time = getTime(now, hr, min);
|
||||
return time <= now ? addDays(time, 1) : time;
|
||||
}
|
||||
|
||||
private long getTime(long millis, int hour, int min) {
|
||||
mCalendar.setTimeInMillis(millis);
|
||||
mCalendar.set(Calendar.HOUR_OF_DAY, hour);
|
||||
mCalendar.set(Calendar.MINUTE, min);
|
||||
mCalendar.set(Calendar.SECOND, 0);
|
||||
mCalendar.set(Calendar.MILLISECOND, 0);
|
||||
return mCalendar.getTimeInMillis();
|
||||
}
|
||||
|
||||
public boolean isInDowntime(long time) {
|
||||
if (mInfo == null || mDays.size() == 0) return false;
|
||||
final long start = getTime(time, mInfo.startHour, mInfo.startMinute);
|
||||
long end = getTime(time, mInfo.endHour, mInfo.endMinute);
|
||||
if (end <= start) {
|
||||
end = addDays(end, 1);
|
||||
}
|
||||
return isInDowntime(-1, time, start, end) || isInDowntime(0, time, start, end);
|
||||
}
|
||||
|
||||
private boolean isInDowntime(int daysOffset, long time, long start, long end) {
|
||||
final int n = Calendar.SATURDAY;
|
||||
final int day = ((getDayOfWeek(time) - 1) + (daysOffset % n) + n) % n + 1;
|
||||
start = addDays(start, daysOffset);
|
||||
end = addDays(end, daysOffset);
|
||||
return mDays.contains(day) && time >= start && time < end;
|
||||
}
|
||||
|
||||
private int getDayOfWeek(long time) {
|
||||
mCalendar.setTimeInMillis(time);
|
||||
return mCalendar.get(Calendar.DAY_OF_WEEK);
|
||||
}
|
||||
|
||||
private void updateDays() {
|
||||
mDays.clear();
|
||||
if (mInfo != null) {
|
||||
final int[] days = ZenModeConfig.tryParseDays(mInfo.mode);
|
||||
for (int i = 0; days != null && i < days.length; i++) {
|
||||
mDays.add(days[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long addDays(long time, int days) {
|
||||
mCalendar.setTimeInMillis(time);
|
||||
mCalendar.add(Calendar.DATE, days);
|
||||
return mCalendar.getTimeInMillis();
|
||||
}
|
||||
}
|
||||
@@ -35,13 +35,13 @@ import android.text.format.DateFormat;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.server.notification.NotificationManagerService.DumpFilter;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
@@ -61,26 +61,44 @@ public class DowntimeConditionProvider extends ConditionProviderService {
|
||||
private static final int EXIT_CODE = 101;
|
||||
private static final String EXTRA_TIME = "time";
|
||||
|
||||
private final Calendar mCalendar = Calendar.getInstance();
|
||||
private static final long SECONDS = 1000;
|
||||
private static final long MINUTES = 60 * SECONDS;
|
||||
private static final long HOURS = 60 * MINUTES;
|
||||
|
||||
private final Context mContext = this;
|
||||
private final ArraySet<Integer> mDays = new ArraySet<Integer>();
|
||||
private final ArraySet<Long> mFiredAlarms = new ArraySet<Long>();
|
||||
private final DowntimeCalendar mCalendar = new DowntimeCalendar();
|
||||
private final FiredAlarms mFiredAlarms = new FiredAlarms();
|
||||
private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
|
||||
private final ConditionProviders mConditionProviders;
|
||||
private final NextAlarmTracker mTracker;
|
||||
private final ZenModeHelper mZenModeHelper;
|
||||
|
||||
private boolean mConnected;
|
||||
private NextAlarmTracker mTracker;
|
||||
private int mDowntimeMode;
|
||||
private long mLookaheadThreshold;
|
||||
private ZenModeConfig mConfig;
|
||||
private Callback mCallback;
|
||||
private boolean mDowntimed;
|
||||
private boolean mConditionClearing;
|
||||
private boolean mRequesting;
|
||||
|
||||
public DowntimeConditionProvider() {
|
||||
public DowntimeConditionProvider(ConditionProviders conditionProviders,
|
||||
NextAlarmTracker tracker, ZenModeHelper zenModeHelper) {
|
||||
if (DEBUG) Slog.d(TAG, "new DowntimeConditionProvider()");
|
||||
mConditionProviders = conditionProviders;
|
||||
mTracker = tracker;
|
||||
mZenModeHelper = zenModeHelper;
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw, DumpFilter filter) {
|
||||
pw.println(" DowntimeConditionProvider:");
|
||||
pw.print(" mConnected="); pw.println(mConnected);
|
||||
pw.print(" mDowntimeMode="); pw.println(Global.zenModeToString(mDowntimeMode));
|
||||
pw.print(" mSubscriptions="); pw.println(mSubscriptions);
|
||||
pw.print(" mLookaheadThreshold="); pw.print(mLookaheadThreshold);
|
||||
pw.print(" ("); TimeUtils.formatDuration(mLookaheadThreshold, pw); pw.println(")");
|
||||
pw.print(" mCalendar="); pw.println(mCalendar);
|
||||
pw.print(" mFiredAlarms="); pw.println(mFiredAlarms);
|
||||
pw.print(" mDowntimed="); pw.println(mDowntimed);
|
||||
pw.print(" mConditionClearing="); pw.println(mConditionClearing);
|
||||
pw.print(" mRequesting="); pw.println(mRequesting);
|
||||
}
|
||||
|
||||
public void attachBase(Context base) {
|
||||
@@ -91,22 +109,20 @@ public class DowntimeConditionProvider extends ConditionProviderService {
|
||||
return (IConditionProvider) onBind(null);
|
||||
}
|
||||
|
||||
public void setCallback(Callback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnected() {
|
||||
if (DEBUG) Slog.d(TAG, "onConnected");
|
||||
mConnected = true;
|
||||
mLookaheadThreshold = PropConfig.getInt(mContext, "downtime.condition.lookahead",
|
||||
R.integer.config_downtime_condition_lookahead_threshold_hrs) * HOURS;
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ENTER_ACTION);
|
||||
filter.addAction(EXIT_ACTION);
|
||||
filter.addAction(Intent.ACTION_TIME_CHANGED);
|
||||
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
|
||||
mContext.registerReceiver(mReceiver, filter);
|
||||
mTracker = mCallback.getNextAlarmTracker();
|
||||
mTracker.addCallback(mTrackerCallback);
|
||||
mZenModeHelper.addCallback(mZenCallback);
|
||||
init();
|
||||
}
|
||||
|
||||
@@ -114,59 +130,125 @@ public class DowntimeConditionProvider extends ConditionProviderService {
|
||||
public void onDestroy() {
|
||||
if (DEBUG) Slog.d(TAG, "onDestroy");
|
||||
mTracker.removeCallback(mTrackerCallback);
|
||||
mZenModeHelper.removeCallback(mZenCallback);
|
||||
mConnected = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestConditions(int relevance) {
|
||||
if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
|
||||
if ((relevance & Condition.FLAG_RELEVANT_NOW) != 0) {
|
||||
if (isInDowntime() && mConfig != null) {
|
||||
notifyCondition(createCondition(mConfig.toDowntimeInfo(), mConfig.sleepNone,
|
||||
Condition.STATE_TRUE));
|
||||
}
|
||||
}
|
||||
if (!mConnected) return;
|
||||
mRequesting = (relevance & Condition.FLAG_RELEVANT_NOW) != 0;
|
||||
evaluateSubscriptions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSubscribe(Uri conditionId) {
|
||||
if (DEBUG) Slog.d(TAG, "onSubscribe conditionId=" + conditionId);
|
||||
final DowntimeInfo downtime = ZenModeConfig.tryParseDowntimeConditionId(conditionId);
|
||||
if (downtime != null && mConfig != null) {
|
||||
final int state = mConfig.toDowntimeInfo().equals(downtime) && isInDowntime()
|
||||
? Condition.STATE_TRUE : Condition.STATE_FALSE;
|
||||
if (DEBUG) Slog.d(TAG, "notify condition state: " + Condition.stateToString(state));
|
||||
notifyCondition(createCondition(downtime, mConfig.sleepNone, state));
|
||||
if (downtime == null) return;
|
||||
mFiredAlarms.clear();
|
||||
mSubscriptions.add(conditionId);
|
||||
notifyCondition(downtime);
|
||||
}
|
||||
|
||||
private boolean shouldShowCondition() {
|
||||
final long now = System.currentTimeMillis();
|
||||
if (DEBUG) Slog.d(TAG, "shouldShowCondition now=" + mCalendar.isInDowntime(now)
|
||||
+ " lookahead="
|
||||
+ (mCalendar.nextDowntimeStart(now) <= (now + mLookaheadThreshold)));
|
||||
return mCalendar.isInDowntime(now)
|
||||
|| mCalendar.nextDowntimeStart(now) <= (now + mLookaheadThreshold);
|
||||
}
|
||||
|
||||
private void notifyCondition(DowntimeInfo downtime) {
|
||||
if (mConfig == null) {
|
||||
// we don't know yet
|
||||
notifyCondition(createCondition(downtime, Condition.STATE_UNKNOWN));
|
||||
return;
|
||||
}
|
||||
if (!downtime.equals(mConfig.toDowntimeInfo())) {
|
||||
// not the configured downtime, consider it false
|
||||
notifyCondition(createCondition(downtime, Condition.STATE_FALSE));
|
||||
return;
|
||||
}
|
||||
if (!shouldShowCondition()) {
|
||||
// configured downtime, but not within the time range
|
||||
notifyCondition(createCondition(downtime, Condition.STATE_FALSE));
|
||||
return;
|
||||
}
|
||||
if (isZenNone() && mFiredAlarms.findBefore(System.currentTimeMillis())) {
|
||||
// within the configured time range, but wake up if none and the next alarm is fired
|
||||
notifyCondition(createCondition(downtime, Condition.STATE_FALSE));
|
||||
return;
|
||||
}
|
||||
// within the configured time range, condition still valid
|
||||
notifyCondition(createCondition(downtime, Condition.STATE_TRUE));
|
||||
}
|
||||
|
||||
private boolean isZenNone() {
|
||||
return mZenModeHelper.getZenMode() == Global.ZEN_MODE_NO_INTERRUPTIONS;
|
||||
}
|
||||
|
||||
private boolean isZenOff() {
|
||||
return mZenModeHelper.getZenMode() == Global.ZEN_MODE_OFF;
|
||||
}
|
||||
|
||||
private void evaluateSubscriptions() {
|
||||
ArraySet<Uri> conditions = mSubscriptions;
|
||||
if (mConfig != null && mRequesting && shouldShowCondition()) {
|
||||
final Uri id = ZenModeConfig.toDowntimeConditionId(mConfig.toDowntimeInfo());
|
||||
if (!conditions.contains(id)) {
|
||||
conditions = new ArraySet<Uri>(conditions);
|
||||
conditions.add(id);
|
||||
}
|
||||
}
|
||||
for (Uri conditionId : conditions) {
|
||||
final DowntimeInfo downtime = ZenModeConfig.tryParseDowntimeConditionId(conditionId);
|
||||
if (downtime != null) {
|
||||
notifyCondition(downtime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnsubscribe(Uri conditionId) {
|
||||
if (DEBUG) Slog.d(TAG, "onUnsubscribe conditionId=" + conditionId);
|
||||
final boolean current = mSubscriptions.contains(conditionId);
|
||||
if (DEBUG) Slog.d(TAG, "onUnsubscribe conditionId=" + conditionId + " current=" + current);
|
||||
mSubscriptions.remove(conditionId);
|
||||
mFiredAlarms.clear();
|
||||
}
|
||||
|
||||
public void setConfig(ZenModeConfig config) {
|
||||
if (Objects.equals(mConfig, config)) return;
|
||||
if (DEBUG) Slog.d(TAG, "setConfig");
|
||||
final boolean downtimeChanged = mConfig == null || config == null
|
||||
|| !mConfig.toDowntimeInfo().equals(config.toDowntimeInfo());
|
||||
mConfig = config;
|
||||
if (mConnected) {
|
||||
if (DEBUG) Slog.d(TAG, "setConfig downtimeChanged=" + downtimeChanged);
|
||||
if (mConnected && downtimeChanged) {
|
||||
mDowntimed = false;
|
||||
init();
|
||||
}
|
||||
// when active, mark downtime as entered for today
|
||||
if (mConfig != null && mConfig.exitCondition != null
|
||||
&& ZenModeConfig.isValidDowntimeConditionId(mConfig.exitCondition.id)) {
|
||||
mDowntimed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isInDowntime() {
|
||||
return mDowntimeMode != Global.ZEN_MODE_OFF;
|
||||
public void onManualConditionClearing() {
|
||||
mConditionClearing = true;
|
||||
}
|
||||
|
||||
public Condition createCondition(DowntimeInfo downtime, boolean orAlarm, int state) {
|
||||
private Condition createCondition(DowntimeInfo downtime, int state) {
|
||||
if (downtime == null) return null;
|
||||
final Uri id = ZenModeConfig.toDowntimeConditionId(downtime);
|
||||
final String skeleton = DateFormat.is24HourFormat(mContext) ? "Hm" : "hma";
|
||||
final Locale locale = Locale.getDefault();
|
||||
final String pattern = DateFormat.getBestDateTimePattern(locale, skeleton);
|
||||
final long now = System.currentTimeMillis();
|
||||
long endTime = getTime(now, downtime.endHour, downtime.endMinute);
|
||||
if (orAlarm) {
|
||||
long endTime = mCalendar.getNextTime(now, downtime.endHour, downtime.endMinute);
|
||||
if (isZenNone()) {
|
||||
final AlarmClockInfo nextAlarm = mTracker.getNextAlarm();
|
||||
final long nextAlarmTime = nextAlarm != null ? nextAlarm.getTriggerTime() : 0;
|
||||
if (nextAlarmTime > now && nextAlarmTime < endTime) {
|
||||
@@ -179,79 +261,11 @@ public class DowntimeConditionProvider extends ConditionProviderService {
|
||||
return new Condition(id, summary, line1, formatted, 0, state, Condition.FLAG_RELEVANT_NOW);
|
||||
}
|
||||
|
||||
public boolean isDowntimeCondition(Condition condition) {
|
||||
return condition != null && ZenModeConfig.isValidDowntimeConditionId(condition.id);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
updateDays();
|
||||
reevaluateDowntime();
|
||||
mCalendar.setDowntimeInfo(mConfig != null ? mConfig.toDowntimeInfo() : null);
|
||||
evaluateSubscriptions();
|
||||
updateAlarms();
|
||||
}
|
||||
|
||||
private void updateDays() {
|
||||
mDays.clear();
|
||||
if (mConfig != null) {
|
||||
final int[] days = ZenModeConfig.tryParseDays(mConfig.sleepMode);
|
||||
for (int i = 0; days != null && i < days.length; i++) {
|
||||
mDays.add(days[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInDowntime(long time) {
|
||||
if (mConfig == null || mDays.size() == 0) return false;
|
||||
final long start = getTime(time, mConfig.sleepStartHour, mConfig.sleepStartMinute);
|
||||
long end = getTime(time, mConfig.sleepEndHour, mConfig.sleepEndMinute);
|
||||
if (start == end) return false;
|
||||
if (end < start) {
|
||||
end = addDays(end, 1);
|
||||
}
|
||||
final boolean orAlarm = mConfig.sleepNone;
|
||||
return isInDowntime(-1, time, start, end, orAlarm)
|
||||
|| isInDowntime(0, time, start, end, orAlarm);
|
||||
}
|
||||
|
||||
private boolean isInDowntime(int daysOffset, long time, long start, long end, boolean orAlarm) {
|
||||
final int n = Calendar.SATURDAY;
|
||||
final int day = ((getDayOfWeek(time) - 1) + (daysOffset % n) + n) % n + 1;
|
||||
start = addDays(start, daysOffset);
|
||||
end = addDays(end, daysOffset);
|
||||
if (orAlarm) {
|
||||
end = findFiredAlarm(start, end);
|
||||
}
|
||||
return mDays.contains(day) && time >= start && time < end;
|
||||
}
|
||||
|
||||
private long findFiredAlarm(long start, long end) {
|
||||
final int N = mFiredAlarms.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
final long firedAlarm = mFiredAlarms.valueAt(i);
|
||||
if (firedAlarm > start && firedAlarm < end) {
|
||||
return firedAlarm;
|
||||
}
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
private void reevaluateDowntime() {
|
||||
final long now = System.currentTimeMillis();
|
||||
final boolean inDowntimeNow = isInDowntime(now);
|
||||
final int downtimeMode = inDowntimeNow ? (mConfig.sleepNone
|
||||
? Global.ZEN_MODE_NO_INTERRUPTIONS : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
|
||||
: Global.ZEN_MODE_OFF;
|
||||
if (DEBUG) Slog.d(TAG, "downtimeMode=" + downtimeMode);
|
||||
if (downtimeMode == mDowntimeMode) return;
|
||||
mDowntimeMode = downtimeMode;
|
||||
Slog.i(TAG, (isInDowntime() ? "Entering" : "Exiting" ) + " downtime");
|
||||
ZenLog.traceDowntime(mDowntimeMode, getDayOfWeek(now), mDays);
|
||||
fireDowntimeChanged();
|
||||
}
|
||||
|
||||
private void fireDowntimeChanged() {
|
||||
if (mCallback != null) {
|
||||
mCallback.onDowntimeChanged(mDowntimeMode);
|
||||
}
|
||||
evaluateAutotrigger();
|
||||
}
|
||||
|
||||
private void updateAlarms() {
|
||||
@@ -260,38 +274,11 @@ public class DowntimeConditionProvider extends ConditionProviderService {
|
||||
updateAlarm(EXIT_ACTION, EXIT_CODE, mConfig.sleepEndHour, mConfig.sleepEndMinute);
|
||||
}
|
||||
|
||||
private int getDayOfWeek(long time) {
|
||||
mCalendar.setTimeInMillis(time);
|
||||
return mCalendar.get(Calendar.DAY_OF_WEEK);
|
||||
}
|
||||
|
||||
private long getTime(long millis, int hour, int min) {
|
||||
mCalendar.setTimeInMillis(millis);
|
||||
mCalendar.set(Calendar.HOUR_OF_DAY, hour);
|
||||
mCalendar.set(Calendar.MINUTE, min);
|
||||
mCalendar.set(Calendar.SECOND, 0);
|
||||
mCalendar.set(Calendar.MILLISECOND, 0);
|
||||
return mCalendar.getTimeInMillis();
|
||||
}
|
||||
|
||||
private long addDays(long time, int days) {
|
||||
mCalendar.setTimeInMillis(time);
|
||||
mCalendar.add(Calendar.DATE, days);
|
||||
return mCalendar.getTimeInMillis();
|
||||
}
|
||||
|
||||
private void updateAlarm(String action, int requestCode, int hr, int min) {
|
||||
final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
|
||||
final long now = System.currentTimeMillis();
|
||||
mCalendar.setTimeInMillis(now);
|
||||
mCalendar.set(Calendar.HOUR_OF_DAY, hr);
|
||||
mCalendar.set(Calendar.MINUTE, min);
|
||||
mCalendar.set(Calendar.SECOND, 0);
|
||||
mCalendar.set(Calendar.MILLISECOND, 0);
|
||||
long time = mCalendar.getTimeInMillis();
|
||||
if (time <= now) {
|
||||
time = addDays(time, 1);
|
||||
}
|
||||
final long time = mCalendar.getNextTime(now, hr, min);
|
||||
final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, requestCode,
|
||||
new Intent(action)
|
||||
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
|
||||
@@ -311,31 +298,34 @@ public class DowntimeConditionProvider extends ConditionProviderService {
|
||||
|
||||
private void onEvaluateNextAlarm(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted) {
|
||||
if (!booted) return; // we don't know yet
|
||||
// update condition description if we're in downtime (mode = none)
|
||||
if (isInDowntime() && mConfig != null && mConfig.sleepNone) {
|
||||
notifyCondition(createCondition(mConfig.toDowntimeInfo(), true /*orAlarm*/,
|
||||
Condition.STATE_TRUE));
|
||||
}
|
||||
if (nextAlarm == null) return; // not fireable
|
||||
if (DEBUG) Slog.d(TAG, "onEvaluateNextAlarm " + mTracker.formatAlarmDebug(nextAlarm));
|
||||
if (System.currentTimeMillis() > wakeupTime) {
|
||||
if (nextAlarm != null && wakeupTime > 0 && System.currentTimeMillis() > wakeupTime) {
|
||||
if (DEBUG) Slog.d(TAG, "Alarm fired: " + mTracker.formatAlarmDebug(wakeupTime));
|
||||
trimFiredAlarms();
|
||||
mFiredAlarms.add(wakeupTime);
|
||||
}
|
||||
reevaluateDowntime();
|
||||
evaluateSubscriptions();
|
||||
}
|
||||
|
||||
private void trimFiredAlarms() {
|
||||
// remove fired alarms over 2 days old
|
||||
final long keepAfter = System.currentTimeMillis() - 2 * 24 * 60 * 60 * 1000;
|
||||
final int N = mFiredAlarms.size();
|
||||
for (int i = N - 1; i >= 0; i--) {
|
||||
final long firedAlarm = mFiredAlarms.valueAt(i);
|
||||
if (firedAlarm < keepAfter) {
|
||||
mFiredAlarms.removeAt(i);
|
||||
}
|
||||
private void evaluateAutotrigger() {
|
||||
String skipReason = null;
|
||||
if (mConfig == null) {
|
||||
skipReason = "no config";
|
||||
} else if (mDowntimed) {
|
||||
skipReason = "already downtimed";
|
||||
} else if (mZenModeHelper.getZenMode() != Global.ZEN_MODE_OFF) {
|
||||
skipReason = "already in zen";
|
||||
} else if (!mCalendar.isInDowntime(System.currentTimeMillis())) {
|
||||
skipReason = "not in downtime";
|
||||
}
|
||||
if (skipReason != null) {
|
||||
ZenLog.traceDowntimeAutotrigger("Autotrigger skipped: " + skipReason);
|
||||
return;
|
||||
}
|
||||
ZenLog.traceDowntimeAutotrigger("Autotrigger fired");
|
||||
mZenModeHelper.setZenMode(mConfig.sleepNone ? Global.ZEN_MODE_NO_INTERRUPTIONS
|
||||
: Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, "downtime");
|
||||
final Condition condition = createCondition(mConfig.toDowntimeInfo(), Condition.STATE_TRUE);
|
||||
mConditionProviders.setZenModeCondition(condition, "downtime");
|
||||
}
|
||||
|
||||
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@@ -347,6 +337,12 @@ public class DowntimeConditionProvider extends ConditionProviderService {
|
||||
final long schTime = intent.getLongExtra(EXTRA_TIME, 0);
|
||||
if (DEBUG) Slog.d(TAG, String.format("%s scheduled for %s, fired at %s, delta=%s",
|
||||
action, ts(schTime), ts(now), now - schTime));
|
||||
if (ENTER_ACTION.equals(action)) {
|
||||
evaluateAutotrigger();
|
||||
} else /*EXIT_ACTION*/ {
|
||||
mDowntimed = false;
|
||||
}
|
||||
mFiredAlarms.clear();
|
||||
} else if (Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
|
||||
if (DEBUG) Slog.d(TAG, "timezone changed to " + TimeZone.getDefault());
|
||||
mCalendar.setTimeZone(TimeZone.getDefault());
|
||||
@@ -357,7 +353,7 @@ public class DowntimeConditionProvider extends ConditionProviderService {
|
||||
} else {
|
||||
if (DEBUG) Slog.d(TAG, action + " fired at " + now);
|
||||
}
|
||||
reevaluateDowntime();
|
||||
evaluateSubscriptions();
|
||||
updateAlarms();
|
||||
}
|
||||
};
|
||||
@@ -369,8 +365,45 @@ public class DowntimeConditionProvider extends ConditionProviderService {
|
||||
}
|
||||
};
|
||||
|
||||
public interface Callback {
|
||||
void onDowntimeChanged(int downtimeMode);
|
||||
NextAlarmTracker getNextAlarmTracker();
|
||||
private final ZenModeHelper.Callback mZenCallback = new ZenModeHelper.Callback() {
|
||||
@Override
|
||||
void onZenModeChanged() {
|
||||
if (mConditionClearing && isZenOff()) {
|
||||
evaluateAutotrigger();
|
||||
}
|
||||
mConditionClearing = false;
|
||||
evaluateSubscriptions();
|
||||
}
|
||||
};
|
||||
|
||||
private class FiredAlarms {
|
||||
private final ArraySet<Long> mFiredAlarms = new ArraySet<Long>();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < mFiredAlarms.size(); i++) {
|
||||
if (i > 0) sb.append(',');
|
||||
sb.append(mTracker.formatAlarmDebug(mFiredAlarms.valueAt(i)));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void add(long firedAlarm) {
|
||||
mFiredAlarms.add(firedAlarm);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mFiredAlarms.clear();
|
||||
}
|
||||
|
||||
public boolean findBefore(long time) {
|
||||
for (int i = 0; i < mFiredAlarms.size(); i++) {
|
||||
if (mFiredAlarms.valueAt(i) < time) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ import android.service.notification.Condition;
|
||||
import android.service.notification.ConditionProviderService;
|
||||
import android.service.notification.IConditionProvider;
|
||||
import android.service.notification.ZenModeConfig;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.TimeUtils;
|
||||
@@ -38,10 +40,7 @@ import java.io.PrintWriter;
|
||||
* Built-in zen condition provider for alarm-clock-based conditions.
|
||||
*
|
||||
* <p>If the user's next alarm is within a lookahead threshold (config, default 12hrs), advertise
|
||||
* it as an exit condition for zen mode (unless the built-in downtime condition is also available).
|
||||
*
|
||||
* <p>When this next alarm is selected as the active exit condition, follow subsequent changes
|
||||
* to the user's next alarm, assuming it remains within the 12-hr window.
|
||||
* it as an exit condition for zen mode.
|
||||
*
|
||||
* <p>The next alarm is defined as {@link AlarmManager#getNextAlarmClock(int)}, which does not
|
||||
* survive a reboot. Maintain the illusion of a consistent next alarm value by holding on to
|
||||
@@ -55,20 +54,22 @@ public class NextAlarmConditionProvider extends ConditionProviderService {
|
||||
private static final long MINUTES = 60 * SECONDS;
|
||||
private static final long HOURS = 60 * MINUTES;
|
||||
|
||||
private static final String NEXT_ALARM_PATH = "next_alarm";
|
||||
private static final long BAD_CONDITION = -1;
|
||||
|
||||
public static final ComponentName COMPONENT =
|
||||
new ComponentName("android", NextAlarmConditionProvider.class.getName());
|
||||
|
||||
private final Context mContext = this;
|
||||
private final NextAlarmTracker mTracker;
|
||||
private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
|
||||
|
||||
private NextAlarmTracker mTracker;
|
||||
private boolean mConnected;
|
||||
private long mLookaheadThreshold;
|
||||
private Callback mCallback;
|
||||
private Uri mCurrentSubscription;
|
||||
private boolean mRequesting;
|
||||
|
||||
public NextAlarmConditionProvider() {
|
||||
public NextAlarmConditionProvider(NextAlarmTracker tracker) {
|
||||
if (DEBUG) Slog.d(TAG, "new NextAlarmConditionProvider()");
|
||||
mTracker = tracker;
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw, DumpFilter filter) {
|
||||
@@ -76,20 +77,16 @@ public class NextAlarmConditionProvider extends ConditionProviderService {
|
||||
pw.print(" mConnected="); pw.println(mConnected);
|
||||
pw.print(" mLookaheadThreshold="); pw.print(mLookaheadThreshold);
|
||||
pw.print(" ("); TimeUtils.formatDuration(mLookaheadThreshold, pw); pw.println(")");
|
||||
pw.print(" mCurrentSubscription="); pw.println(mCurrentSubscription);
|
||||
}
|
||||
|
||||
public void setCallback(Callback callback) {
|
||||
mCallback = callback;
|
||||
pw.print(" mSubscriptions="); pw.println(mSubscriptions);
|
||||
pw.print(" mRequesting="); pw.println(mRequesting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnected() {
|
||||
if (DEBUG) Slog.d(TAG, "onConnected");
|
||||
mLookaheadThreshold = mContext.getResources()
|
||||
.getInteger(R.integer.config_next_alarm_condition_lookahead_threshold_hrs) * HOURS;
|
||||
mLookaheadThreshold = PropConfig.getInt(mContext, "nextalarm.condition.lookahead",
|
||||
R.integer.config_next_alarm_condition_lookahead_threshold_hrs) * HOURS;
|
||||
mConnected = true;
|
||||
mTracker = mCallback.getNextAlarmTracker();
|
||||
mTracker.addCallback(mTrackerCallback);
|
||||
}
|
||||
|
||||
@@ -103,34 +100,27 @@ public class NextAlarmConditionProvider extends ConditionProviderService {
|
||||
|
||||
@Override
|
||||
public void onRequestConditions(int relevance) {
|
||||
if (!mConnected || (relevance & Condition.FLAG_RELEVANT_NOW) == 0) return;
|
||||
|
||||
final AlarmClockInfo nextAlarm = mTracker.getNextAlarm();
|
||||
if (nextAlarm == null) return; // no next alarm
|
||||
if (mCallback != null && mCallback.isInDowntime()) return; // prefer downtime condition
|
||||
if (!isWithinLookaheadThreshold(nextAlarm)) return; // alarm not within window
|
||||
|
||||
// next alarm exists, and is within the configured lookahead threshold
|
||||
notifyCondition(newConditionId(), nextAlarm, Condition.STATE_TRUE, "request");
|
||||
if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
|
||||
if (!mConnected) return;
|
||||
mRequesting = (relevance & Condition.FLAG_RELEVANT_NOW) != 0;
|
||||
mTracker.evaluate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSubscribe(Uri conditionId) {
|
||||
if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
|
||||
if (!isNextAlarmCondition(conditionId)) {
|
||||
if (tryParseNextAlarmCondition(conditionId) == BAD_CONDITION) {
|
||||
notifyCondition(conditionId, null, Condition.STATE_FALSE, "badCondition");
|
||||
return;
|
||||
}
|
||||
mCurrentSubscription = conditionId;
|
||||
mSubscriptions.add(conditionId);
|
||||
mTracker.evaluate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnsubscribe(Uri conditionId) {
|
||||
if (DEBUG) Slog.d(TAG, "onUnsubscribe " + conditionId);
|
||||
if (conditionId != null && conditionId.equals(mCurrentSubscription)) {
|
||||
mCurrentSubscription = null;
|
||||
}
|
||||
mSubscriptions.remove(conditionId);
|
||||
}
|
||||
|
||||
public void attachBase(Context base) {
|
||||
@@ -157,43 +147,72 @@ public class NextAlarmConditionProvider extends ConditionProviderService {
|
||||
formattedAlarm, 0, state, Condition.FLAG_RELEVANT_NOW));
|
||||
}
|
||||
|
||||
private Uri newConditionId() {
|
||||
private Uri newConditionId(AlarmClockInfo nextAlarm) {
|
||||
return new Uri.Builder().scheme(Condition.SCHEME)
|
||||
.authority(ZenModeConfig.SYSTEM_AUTHORITY)
|
||||
.appendPath(NEXT_ALARM_PATH)
|
||||
.appendPath(ZenModeConfig.NEXT_ALARM_PATH)
|
||||
.appendPath(Integer.toString(mTracker.getCurrentUserId()))
|
||||
.appendPath(Long.toString(nextAlarm.getTriggerTime()))
|
||||
.build();
|
||||
}
|
||||
|
||||
private boolean isNextAlarmCondition(Uri conditionId) {
|
||||
private long tryParseNextAlarmCondition(Uri conditionId) {
|
||||
return conditionId != null && conditionId.getScheme().equals(Condition.SCHEME)
|
||||
&& conditionId.getAuthority().equals(ZenModeConfig.SYSTEM_AUTHORITY)
|
||||
&& conditionId.getPathSegments().size() == 2
|
||||
&& conditionId.getPathSegments().get(0).equals(NEXT_ALARM_PATH)
|
||||
&& conditionId.getPathSegments().size() == 3
|
||||
&& conditionId.getPathSegments().get(0).equals(ZenModeConfig.NEXT_ALARM_PATH)
|
||||
&& conditionId.getPathSegments().get(1)
|
||||
.equals(Integer.toString(mTracker.getCurrentUserId()));
|
||||
.equals(Integer.toString(mTracker.getCurrentUserId()))
|
||||
? tryParseLong(conditionId.getPathSegments().get(2), BAD_CONDITION)
|
||||
: BAD_CONDITION;
|
||||
}
|
||||
|
||||
private static long tryParseLong(String value, long defValue) {
|
||||
if (TextUtils.isEmpty(value)) return defValue;
|
||||
try {
|
||||
return Long.valueOf(value);
|
||||
} catch (NumberFormatException e) {
|
||||
return defValue;
|
||||
}
|
||||
}
|
||||
|
||||
private void onEvaluate(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted) {
|
||||
final boolean withinThreshold = isWithinLookaheadThreshold(nextAlarm);
|
||||
if (DEBUG) Slog.d(TAG, "onEvaluate mCurrentSubscription=" + mCurrentSubscription
|
||||
final long nextAlarmTime = nextAlarm != null ? nextAlarm.getTriggerTime() : 0;
|
||||
if (DEBUG) Slog.d(TAG, "onEvaluate mSubscriptions=" + mSubscriptions
|
||||
+ " nextAlarmTime=" + mTracker.formatAlarmDebug(nextAlarmTime)
|
||||
+ " nextAlarmWakeup=" + mTracker.formatAlarmDebug(wakeupTime)
|
||||
+ " withinThreshold=" + withinThreshold
|
||||
+ " booted=" + booted);
|
||||
if (mCurrentSubscription == null) return; // no one cares
|
||||
if (!booted) {
|
||||
// we don't know yet
|
||||
notifyCondition(mCurrentSubscription, nextAlarm, Condition.STATE_UNKNOWN, "!booted");
|
||||
return;
|
||||
|
||||
ArraySet<Uri> conditions = mSubscriptions;
|
||||
if (mRequesting && nextAlarm != null && withinThreshold) {
|
||||
final Uri id = newConditionId(nextAlarm);
|
||||
if (!conditions.contains(id)) {
|
||||
conditions = new ArraySet<Uri>(conditions);
|
||||
conditions.add(id);
|
||||
}
|
||||
}
|
||||
if (!withinThreshold) {
|
||||
// next alarm outside threshold or in the past, condition = false
|
||||
notifyCondition(mCurrentSubscription, nextAlarm, Condition.STATE_FALSE, "!within");
|
||||
mCurrentSubscription = null;
|
||||
return;
|
||||
for (Uri conditionId : conditions) {
|
||||
final long time = tryParseNextAlarmCondition(conditionId);
|
||||
if (time == BAD_CONDITION) {
|
||||
notifyCondition(conditionId, nextAlarm, Condition.STATE_FALSE, "badCondition");
|
||||
} else if (!booted) {
|
||||
// we don't know yet
|
||||
if (mSubscriptions.contains(conditionId)) {
|
||||
notifyCondition(conditionId, nextAlarm, Condition.STATE_UNKNOWN, "!booted");
|
||||
}
|
||||
} else if (time != nextAlarmTime) {
|
||||
// next alarm changed since subscription, consider obsolete
|
||||
notifyCondition(conditionId, nextAlarm, Condition.STATE_FALSE, "changed");
|
||||
} else if (!withinThreshold) {
|
||||
// next alarm outside threshold or in the past, condition = false
|
||||
notifyCondition(conditionId, nextAlarm, Condition.STATE_FALSE, "!within");
|
||||
} else {
|
||||
// next alarm within threshold and in the future, condition = true
|
||||
notifyCondition(conditionId, nextAlarm, Condition.STATE_TRUE, "within");
|
||||
}
|
||||
}
|
||||
// next alarm in the future and within threshold, condition = true
|
||||
notifyCondition(mCurrentSubscription, nextAlarm, Condition.STATE_TRUE, "within");
|
||||
}
|
||||
|
||||
private final NextAlarmTracker.Callback mTrackerCallback = new NextAlarmTracker.Callback() {
|
||||
@@ -202,9 +221,4 @@ public class NextAlarmConditionProvider extends ConditionProviderService {
|
||||
NextAlarmConditionProvider.this.onEvaluate(nextAlarm, wakeupTime, booted);
|
||||
}
|
||||
};
|
||||
|
||||
public interface Callback {
|
||||
boolean isInDowntime();
|
||||
NextAlarmTracker getNextAlarmTracker();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1551,6 +1551,12 @@ public class NotificationManagerService extends SystemService {
|
||||
MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
|
||||
MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSystemConditionProviderEnabled(String path) {
|
||||
enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
|
||||
return mConditionProviders.isSystemConditionProviderEnabled(path);
|
||||
}
|
||||
};
|
||||
|
||||
private String[] getActiveNotificationKeys(INotificationListener token) {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.server.notification;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.SystemProperties;
|
||||
|
||||
public class PropConfig {
|
||||
private static final String UNSET = "UNSET";
|
||||
|
||||
public static int getInt(Context context, String propName, int resId) {
|
||||
return SystemProperties.getInt(propName, context.getResources().getInteger(resId));
|
||||
}
|
||||
|
||||
public static String[] getStringArray(Context context, String propName, int resId) {
|
||||
final String prop = SystemProperties.get(propName, UNSET);
|
||||
return !UNSET.equals(prop) ? prop.split(",") : context.getResources().getStringArray(resId);
|
||||
}
|
||||
}
|
||||
@@ -89,12 +89,12 @@ public class ZenLog {
|
||||
ringerModeToString(ringerModeExternalOut));
|
||||
}
|
||||
|
||||
public static void traceDowntime(int downtimeMode, int day, ArraySet<Integer> days) {
|
||||
append(TYPE_DOWNTIME, zenModeToString(downtimeMode) + ",day=" + day + ",days=" + days);
|
||||
public static void traceDowntimeAutotrigger(String result) {
|
||||
append(TYPE_DOWNTIME, result);
|
||||
}
|
||||
|
||||
public static void traceSetZenMode(int mode, String reason) {
|
||||
append(TYPE_SET_ZEN_MODE, zenModeToString(mode) + "," + reason);
|
||||
public static void traceSetZenMode(int zenMode, String reason) {
|
||||
append(TYPE_SET_ZEN_MODE, zenModeToString(zenMode) + "," + reason);
|
||||
}
|
||||
|
||||
public static void traceUpdateZenMode(int fromMode, int toMode) {
|
||||
|
||||
@@ -108,6 +108,10 @@ public class ZenModeHelper implements AudioManagerInternal.RingerModeDelegate {
|
||||
mCallbacks.add(callback);
|
||||
}
|
||||
|
||||
public void removeCallback(Callback callback) {
|
||||
mCallbacks.remove(callback);
|
||||
}
|
||||
|
||||
public void onSystemReady() {
|
||||
mAudioManager = LocalServices.getService(AudioManagerInternal.class);
|
||||
if (mAudioManager != null) {
|
||||
@@ -208,9 +212,9 @@ public class ZenModeHelper implements AudioManagerInternal.RingerModeDelegate {
|
||||
return mZenMode;
|
||||
}
|
||||
|
||||
public void setZenMode(int zenModeValue, String reason) {
|
||||
ZenLog.traceSetZenMode(zenModeValue, reason);
|
||||
Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zenModeValue);
|
||||
public void setZenMode(int zenMode, String reason) {
|
||||
ZenLog.traceSetZenMode(zenMode, reason);
|
||||
Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zenMode);
|
||||
}
|
||||
|
||||
public void updateZenMode() {
|
||||
|
||||
Reference in New Issue
Block a user