CountdownConditionProvider.java revision 856edebad73560e9b1cce021a7de9a0470d07176
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.notification;
18
19import android.app.AlarmManager;
20import android.app.PendingIntent;
21import android.content.BroadcastReceiver;
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.net.Uri;
27import android.service.notification.Condition;
28import android.service.notification.ConditionProviderService;
29import android.service.notification.IConditionProvider;
30import android.service.notification.ZenModeConfig;
31import android.text.format.DateUtils;
32import android.util.Slog;
33
34import java.util.Date;
35
36/** Built-in zen condition provider for simple time-based conditions */
37public class CountdownConditionProvider extends ConditionProviderService {
38    private static final String TAG = "CountdownConditionProvider";
39    private static final boolean DEBUG = false;
40
41    public static final ComponentName COMPONENT =
42            new ComponentName("android", CountdownConditionProvider.class.getName());
43
44    private static final String ACTION = CountdownConditionProvider.class.getName();
45    private static final int REQUEST_CODE = 100;
46    private static final String EXTRA_CONDITION_ID = "condition_id";
47
48    private final Context mContext = this;
49    private final Receiver mReceiver = new Receiver();
50
51    private boolean mConnected;
52
53    public CountdownConditionProvider() {
54        if (DEBUG) Slog.d(TAG, "new CountdownConditionProvider()");
55    }
56
57    @Override
58    public void onConnected() {
59        if (DEBUG) Slog.d(TAG, "onConnected");
60        mContext.registerReceiver(mReceiver, new IntentFilter(ACTION));
61        mConnected = true;
62    }
63
64    @Override
65    public void onDestroy() {
66        super.onDestroy();
67        if (DEBUG) Slog.d(TAG, "onDestroy");
68        if (mConnected) {
69            mContext.unregisterReceiver(mReceiver);
70        }
71        mConnected = false;
72    }
73
74    @Override
75    public void onRequestConditions(int relevance) {
76        // by convention
77    }
78
79    @Override
80    public void onSubscribe(Uri conditionId) {
81        if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
82        final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
83        final AlarmManager alarms = (AlarmManager)
84                mContext.getSystemService(Context.ALARM_SERVICE);
85        final Intent intent = new Intent(ACTION).putExtra(EXTRA_CONDITION_ID, conditionId)
86                .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
87        final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE,
88                intent, PendingIntent.FLAG_UPDATE_CURRENT);
89        alarms.cancel(pendingIntent);
90        if (time > 0) {
91            final long now = System.currentTimeMillis();
92            final CharSequence span =
93                    DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS);
94            if (DEBUG) Slog.d(TAG, String.format(
95                    "Scheduling %s for %s, %s in the future (%s), now=%s",
96                    ACTION, ts(time), time - now, span, ts(now)));
97            alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
98        }
99    }
100
101    @Override
102    public void onUnsubscribe(Uri conditionId) {
103        // noop
104    }
105
106    private final class Receiver extends BroadcastReceiver {
107        @Override
108        public void onReceive(Context context, Intent intent) {
109            if (ACTION.equals(intent.getAction())) {
110                final Uri conditionId = intent.getParcelableExtra(EXTRA_CONDITION_ID);
111                final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
112                if (DEBUG) Slog.d(TAG, "Countdown condition fired: " + conditionId);
113                if (time > 0) {
114                    notifyCondition(newCondition(time, Condition.STATE_FALSE));
115                }
116            }
117        }
118    }
119
120    private static final Condition newCondition(long time, int state) {
121        return new Condition(ZenModeConfig.toCountdownConditionId(time),
122                "", "", "", 0, state,Condition.FLAG_RELEVANT_NOW);
123    }
124
125    public static String tryParseDescription(Uri conditionUri) {
126        final long time = ZenModeConfig.tryParseCountdownConditionId(conditionUri);
127        if (time == 0) return null;
128        final long now = System.currentTimeMillis();
129        final CharSequence span =
130                DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS);
131        return String.format("Scheduled for %s, %s in the future (%s), now=%s",
132                ts(time), time - now, span, ts(now));
133    }
134
135    private static String ts(long time) {
136        return new Date(time) + " (" + time + ")";
137    }
138
139    public void attachBase(Context base) {
140        attachBaseContext(base);
141    }
142
143    public IConditionProvider asInterface() {
144        return (IConditionProvider) onBind(null);
145    }
146}
147