Home | History | Annotate | Download | only in notification
      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 
     17 package com.android.server.notification;
     18 
     19 import android.app.AlarmManager;
     20 import android.app.PendingIntent;
     21 import android.content.BroadcastReceiver;
     22 import android.content.ComponentName;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.IntentFilter;
     26 import android.net.Uri;
     27 import android.service.notification.Condition;
     28 import android.service.notification.IConditionProvider;
     29 import android.service.notification.ZenModeConfig;
     30 import android.text.format.DateUtils;
     31 import android.util.Log;
     32 import android.util.Slog;
     33 
     34 import com.android.server.notification.NotificationManagerService.DumpFilter;
     35 
     36 import java.io.PrintWriter;
     37 
     38 /** Built-in zen condition provider for simple time-based conditions */
     39 public class CountdownConditionProvider extends SystemConditionProviderService {
     40     private static final String TAG = "ConditionProviders.CCP";
     41     private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG);
     42 
     43     public static final ComponentName COMPONENT =
     44             new ComponentName("android", CountdownConditionProvider.class.getName());
     45 
     46     private static final String ACTION = CountdownConditionProvider.class.getName();
     47     private static final int REQUEST_CODE = 100;
     48     private static final String EXTRA_CONDITION_ID = "condition_id";
     49 
     50     private final Context mContext = this;
     51     private final Receiver mReceiver = new Receiver();
     52 
     53     private boolean mConnected;
     54     private long mTime;
     55 
     56     public CountdownConditionProvider() {
     57         if (DEBUG) Slog.d(TAG, "new CountdownConditionProvider()");
     58     }
     59 
     60     @Override
     61     public ComponentName getComponent() {
     62         return COMPONENT;
     63     }
     64 
     65     @Override
     66     public boolean isValidConditionId(Uri id) {
     67         return ZenModeConfig.isValidCountdownConditionId(id);
     68     }
     69 
     70     @Override
     71     public void attachBase(Context base) {
     72         attachBaseContext(base);
     73     }
     74 
     75     @Override
     76     public void onBootComplete() {
     77         // noop
     78     }
     79 
     80     @Override
     81     public IConditionProvider asInterface() {
     82         return (IConditionProvider) onBind(null);
     83     }
     84 
     85     @Override
     86     public void dump(PrintWriter pw, DumpFilter filter) {
     87         pw.println("    CountdownConditionProvider:");
     88         pw.print("      mConnected="); pw.println(mConnected);
     89         pw.print("      mTime="); pw.println(mTime);
     90     }
     91 
     92     @Override
     93     public void onConnected() {
     94         if (DEBUG) Slog.d(TAG, "onConnected");
     95         mContext.registerReceiver(mReceiver, new IntentFilter(ACTION));
     96         mConnected = true;
     97     }
     98 
     99     @Override
    100     public void onDestroy() {
    101         super.onDestroy();
    102         if (DEBUG) Slog.d(TAG, "onDestroy");
    103         if (mConnected) {
    104             mContext.unregisterReceiver(mReceiver);
    105         }
    106         mConnected = false;
    107     }
    108 
    109     @Override
    110     public void onSubscribe(Uri conditionId) {
    111         if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
    112         mTime = ZenModeConfig.tryParseCountdownConditionId(conditionId);
    113         final AlarmManager alarms = (AlarmManager)
    114                 mContext.getSystemService(Context.ALARM_SERVICE);
    115         final Intent intent = new Intent(ACTION).putExtra(EXTRA_CONDITION_ID, conditionId)
    116                 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    117         final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE,
    118                 intent, PendingIntent.FLAG_UPDATE_CURRENT);
    119         alarms.cancel(pendingIntent);
    120         if (mTime > 0) {
    121             final long now = System.currentTimeMillis();
    122             final CharSequence span =
    123                     DateUtils.getRelativeTimeSpanString(mTime, now, DateUtils.MINUTE_IN_MILLIS);
    124             if (mTime <= now) {
    125                 // in the past, already false
    126                 notifyCondition(newCondition(mTime, Condition.STATE_FALSE));
    127             } else {
    128                 // in the future, set an alarm
    129                 alarms.setExact(AlarmManager.RTC_WAKEUP, mTime, pendingIntent);
    130             }
    131             if (DEBUG) Slog.d(TAG, String.format(
    132                     "%s %s for %s, %s in the future (%s), now=%s",
    133                     (mTime <= now ? "Not scheduling" : "Scheduling"),
    134                     ACTION, ts(mTime), mTime - now, span, ts(now)));
    135         }
    136     }
    137 
    138     @Override
    139     public void onUnsubscribe(Uri conditionId) {
    140         // noop
    141     }
    142 
    143     private final class Receiver extends BroadcastReceiver {
    144         @Override
    145         public void onReceive(Context context, Intent intent) {
    146             if (ACTION.equals(intent.getAction())) {
    147                 final Uri conditionId = intent.getParcelableExtra(EXTRA_CONDITION_ID);
    148                 final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
    149                 if (DEBUG) Slog.d(TAG, "Countdown condition fired: " + conditionId);
    150                 if (time > 0) {
    151                     notifyCondition(newCondition(time, Condition.STATE_FALSE));
    152                 }
    153             }
    154         }
    155     }
    156 
    157     private static final Condition newCondition(long time, int state) {
    158         return new Condition(ZenModeConfig.toCountdownConditionId(time),
    159                 "", "", "", 0, state,Condition.FLAG_RELEVANT_NOW);
    160     }
    161 
    162     public static String tryParseDescription(Uri conditionUri) {
    163         final long time = ZenModeConfig.tryParseCountdownConditionId(conditionUri);
    164         if (time == 0) return null;
    165         final long now = System.currentTimeMillis();
    166         final CharSequence span =
    167                 DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS);
    168         return String.format("Scheduled for %s, %s in the future (%s), now=%s",
    169                 ts(time), time - now, span, ts(now));
    170     }
    171 
    172 }
    173