/*
|
* 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.app.AlarmManager;
|
import android.app.PendingIntent;
|
import android.content.BroadcastReceiver;
|
import android.content.ComponentName;
|
import android.content.Context;
|
import android.content.Intent;
|
import android.content.IntentFilter;
|
import android.net.Uri;
|
import android.service.notification.Condition;
|
import android.service.notification.IConditionProvider;
|
import android.service.notification.ZenModeConfig;
|
import android.text.format.DateUtils;
|
import android.util.Log;
|
import android.util.Slog;
|
|
import com.android.server.notification.NotificationManagerService.DumpFilter;
|
|
import java.io.PrintWriter;
|
|
/** Built-in zen condition provider for simple time-based conditions */
|
public class CountdownConditionProvider extends SystemConditionProviderService {
|
private static final String TAG = "ConditionProviders.CCP";
|
private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG);
|
|
public static final ComponentName COMPONENT =
|
new ComponentName("android", CountdownConditionProvider.class.getName());
|
|
private static final String ACTION = CountdownConditionProvider.class.getName();
|
private static final int REQUEST_CODE = 100;
|
private static final String EXTRA_CONDITION_ID = "condition_id";
|
|
private final Context mContext = this;
|
private final Receiver mReceiver = new Receiver();
|
|
private boolean mConnected;
|
private long mTime;
|
private boolean mIsAlarm;
|
|
public CountdownConditionProvider() {
|
if (DEBUG) Slog.d(TAG, "new CountdownConditionProvider()");
|
}
|
|
@Override
|
public ComponentName getComponent() {
|
return COMPONENT;
|
}
|
|
@Override
|
public boolean isValidConditionId(Uri id) {
|
return ZenModeConfig.isValidCountdownConditionId(id);
|
}
|
|
@Override
|
public void attachBase(Context base) {
|
attachBaseContext(base);
|
}
|
|
@Override
|
public void onBootComplete() {
|
// noop
|
}
|
|
@Override
|
public IConditionProvider asInterface() {
|
return (IConditionProvider) onBind(null);
|
}
|
|
@Override
|
public void dump(PrintWriter pw, DumpFilter filter) {
|
pw.println(" CountdownConditionProvider:");
|
pw.print(" mConnected="); pw.println(mConnected);
|
pw.print(" mTime="); pw.println(mTime);
|
}
|
|
@Override
|
public void onConnected() {
|
if (DEBUG) Slog.d(TAG, "onConnected");
|
mContext.registerReceiver(mReceiver, new IntentFilter(ACTION));
|
mConnected = true;
|
}
|
|
@Override
|
public void onDestroy() {
|
super.onDestroy();
|
if (DEBUG) Slog.d(TAG, "onDestroy");
|
if (mConnected) {
|
mContext.unregisterReceiver(mReceiver);
|
}
|
mConnected = false;
|
}
|
|
@Override
|
public void onSubscribe(Uri conditionId) {
|
if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
|
mTime = ZenModeConfig.tryParseCountdownConditionId(conditionId);
|
mIsAlarm = ZenModeConfig.isValidCountdownToAlarmConditionId(conditionId);
|
final AlarmManager alarms = (AlarmManager)
|
mContext.getSystemService(Context.ALARM_SERVICE);
|
final Intent intent = new Intent(ACTION)
|
.putExtra(EXTRA_CONDITION_ID, conditionId)
|
.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE,
|
intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
alarms.cancel(pendingIntent);
|
if (mTime > 0) {
|
final long now = System.currentTimeMillis();
|
final CharSequence span =
|
DateUtils.getRelativeTimeSpanString(mTime, now, DateUtils.MINUTE_IN_MILLIS);
|
if (mTime <= now) {
|
// in the past, already false
|
notifyCondition(newCondition(mTime, mIsAlarm, Condition.STATE_FALSE));
|
} else {
|
// in the future, set an alarm
|
alarms.setExact(AlarmManager.RTC_WAKEUP, mTime, pendingIntent);
|
}
|
if (DEBUG) Slog.d(TAG, String.format(
|
"%s %s for %s, %s in the future (%s), now=%s",
|
(mTime <= now ? "Not scheduling" : "Scheduling"),
|
ACTION, ts(mTime), mTime - now, span, ts(now)));
|
}
|
}
|
|
@Override
|
public void onUnsubscribe(Uri conditionId) {
|
// noop
|
}
|
|
private final class Receiver extends BroadcastReceiver {
|
@Override
|
public void onReceive(Context context, Intent intent) {
|
if (ACTION.equals(intent.getAction())) {
|
final Uri conditionId = intent.getParcelableExtra(EXTRA_CONDITION_ID);
|
final boolean alarm = ZenModeConfig.isValidCountdownToAlarmConditionId(conditionId);
|
final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
|
if (DEBUG) Slog.d(TAG, "Countdown condition fired: " + conditionId);
|
if (time > 0) {
|
notifyCondition(newCondition(time, alarm, Condition.STATE_FALSE));
|
}
|
}
|
}
|
}
|
|
private static final Condition newCondition(long time, boolean alarm, int state) {
|
return new Condition(ZenModeConfig.toCountdownConditionId(time, alarm),
|
"", "", "", 0, state,Condition.FLAG_RELEVANT_NOW);
|
}
|
|
public static String tryParseDescription(Uri conditionUri) {
|
final long time = ZenModeConfig.tryParseCountdownConditionId(conditionUri);
|
if (time == 0) return null;
|
final long now = System.currentTimeMillis();
|
final CharSequence span =
|
DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS);
|
return String.format("Scheduled for %s, %s in the future (%s), now=%s",
|
ts(time), time - now, span, ts(now));
|
}
|
|
}
|