FileDocCategorySizeDatePackage
DowntimeConditionProvider.javaAPI DocAndroid 5.1 API16945Thu Mar 12 22:22:42 GMT 2015com.android.server.notification

DowntimeConditionProvider

public class DowntimeConditionProvider extends android.service.notification.ConditionProviderService
Built-in zen condition provider for managing downtime

Fields Summary
private static final String
TAG
private static final boolean
DEBUG
public static final android.content.ComponentName
COMPONENT
private static final String
ENTER_ACTION
private static final int
ENTER_CODE
private static final String
EXIT_ACTION
private static final int
EXIT_CODE
private static final String
EXTRA_TIME
private static final long
SECONDS
private static final long
MINUTES
private static final long
HOURS
private final android.content.Context
mContext
private final DowntimeCalendar
mCalendar
private final FiredAlarms
mFiredAlarms
private final android.util.ArraySet
mSubscriptions
private final ConditionProviders
mConditionProviders
private final NextAlarmTracker
mTracker
private final ZenModeHelper
mZenModeHelper
private boolean
mConnected
private long
mLookaheadThreshold
private android.service.notification.ZenModeConfig
mConfig
private boolean
mDowntimed
private boolean
mConditionClearing
private boolean
mRequesting
private android.content.BroadcastReceiver
mReceiver
private final NextAlarmTracker.Callback
mTrackerCallback
private final ZenModeHelper.Callback
mZenCallback
Constructors Summary
public DowntimeConditionProvider(ConditionProviders conditionProviders, NextAlarmTracker tracker, ZenModeHelper zenModeHelper)


      
                
        if (DEBUG) Slog.d(TAG, "new DowntimeConditionProvider()");
        mConditionProviders = conditionProviders;
        mTracker = tracker;
        mZenModeHelper = zenModeHelper;
    
Methods Summary
public android.service.notification.IConditionProviderasInterface()

        return (IConditionProvider) onBind(null);
    
public voidattachBase(android.content.Context base)

        attachBaseContext(base);
    
private android.service.notification.ConditioncreateCondition(android.service.notification.ZenModeConfig.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 = 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) {
                endTime = nextAlarmTime;
            }
        }
        final String formatted = new SimpleDateFormat(pattern, locale).format(new Date(endTime));
        final String summary = mContext.getString(R.string.downtime_condition_summary, formatted);
        final String line1 = mContext.getString(R.string.downtime_condition_line_one);
        return new Condition(id, summary, line1, formatted, 0, state, Condition.FLAG_RELEVANT_NOW);
    
public voiddump(java.io.PrintWriter pw, com.android.server.notification.NotificationManagerService.DumpFilter filter)

        pw.println("    DowntimeConditionProvider:");
        pw.print("      mConnected="); pw.println(mConnected);
        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);
    
private voidevaluateAutotrigger()

        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 voidevaluateSubscriptions()

        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);
            }
        }
    
private voidinit()

        mCalendar.setDowntimeInfo(mConfig != null ? mConfig.toDowntimeInfo() : null);
        evaluateSubscriptions();
        updateAlarms();
        evaluateAutotrigger();
    
private booleanisZenNone()

        return mZenModeHelper.getZenMode() == Global.ZEN_MODE_NO_INTERRUPTIONS;
    
private booleanisZenOff()

        return mZenModeHelper.getZenMode() == Global.ZEN_MODE_OFF;
    
private voidnotifyCondition(android.service.notification.ZenModeConfig.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));
    
public voidonConnected()

        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.addCallback(mTrackerCallback);
        mZenModeHelper.addCallback(mZenCallback);
        init();
    
public voidonDestroy()

        if (DEBUG) Slog.d(TAG, "onDestroy");
        mTracker.removeCallback(mTrackerCallback);
        mZenModeHelper.removeCallback(mZenCallback);
        mConnected = false;
    
private voidonEvaluateNextAlarm(android.app.AlarmManager.AlarmClockInfo nextAlarm, long wakeupTime, boolean booted)

        if (!booted) return;  // we don't know yet
        if (DEBUG) Slog.d(TAG, "onEvaluateNextAlarm " + mTracker.formatAlarmDebug(nextAlarm));
        if (nextAlarm != null && wakeupTime > 0 && System.currentTimeMillis() > wakeupTime) {
            if (DEBUG) Slog.d(TAG, "Alarm fired: " + mTracker.formatAlarmDebug(wakeupTime));
            mFiredAlarms.add(wakeupTime);
        }
        evaluateSubscriptions();
    
public voidonManualConditionClearing()

        mConditionClearing = true;
    
public voidonRequestConditions(int relevance)

        if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
        if (!mConnected) return;
        mRequesting = (relevance & Condition.FLAG_RELEVANT_NOW) != 0;
        evaluateSubscriptions();
    
public voidonSubscribe(android.net.Uri conditionId)

        if (DEBUG) Slog.d(TAG, "onSubscribe conditionId=" + conditionId);
        final DowntimeInfo downtime = ZenModeConfig.tryParseDowntimeConditionId(conditionId);
        if (downtime == null) return;
        mFiredAlarms.clear();
        mSubscriptions.add(conditionId);
        notifyCondition(downtime);
    
public voidonUnsubscribe(android.net.Uri conditionId)

        final boolean current = mSubscriptions.contains(conditionId);
        if (DEBUG) Slog.d(TAG, "onUnsubscribe conditionId=" + conditionId + " current=" + current);
        mSubscriptions.remove(conditionId);
        mFiredAlarms.clear();
    
public voidsetConfig(android.service.notification.ZenModeConfig config)

        if (Objects.equals(mConfig, config)) return;
        final boolean downtimeChanged = mConfig == null || config == null
                || !mConfig.toDowntimeInfo().equals(config.toDowntimeInfo());
        mConfig = config;
        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;
        }
    
private booleanshouldShowCondition()

        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 static java.lang.Stringts(long time)

        return new Date(time) + " (" + time + ")";
    
private voidupdateAlarm(java.lang.String action, int requestCode, int hr, int min)

        final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
        final long now = System.currentTimeMillis();
        final long time = mCalendar.getNextTime(now, hr, min);
        final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, requestCode,
                new Intent(action)
                    .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
                    .putExtra(EXTRA_TIME, time),
                PendingIntent.FLAG_UPDATE_CURRENT);
        alarms.cancel(pendingIntent);
        if (mConfig.sleepMode != null) {
            if (DEBUG) Slog.d(TAG, String.format("Scheduling %s for %s, in %s, now=%s",
                    action, ts(time), NextAlarmTracker.formatDuration(time - now), ts(now)));
            alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
        }
    
private voidupdateAlarms()

        if (mConfig == null) return;
        updateAlarm(ENTER_ACTION, ENTER_CODE, mConfig.sleepStartHour, mConfig.sleepStartMinute);
        updateAlarm(EXIT_ACTION, EXIT_CODE, mConfig.sleepEndHour, mConfig.sleepEndMinute);