16b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock/*
26b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock * Copyright (C) 2014 The Android Open Source Project
36b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock *
46b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock * Licensed under the Apache License, Version 2.0 (the "License");
56b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock * you may not use this file except in compliance with the License.
66b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock * You may obtain a copy of the License at
76b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock *
86b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock *      http://www.apache.org/licenses/LICENSE-2.0
96b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock *
106b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock * Unless required by applicable law or agreed to in writing, software
116b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock * distributed under the License is distributed on an "AS IS" BASIS,
126b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock * See the License for the specific language governing permissions and
146b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock * limitations under the License.
156b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock */
166b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
176b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockpackage com.android.server.notification;
186b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
196b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.app.ActivityManager;
206b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.app.AlarmManager;
216b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.app.AlarmManager.AlarmClockInfo;
226b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.app.PendingIntent;
236b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.content.BroadcastReceiver;
246b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.content.Context;
256b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.content.Intent;
266b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.content.IntentFilter;
276b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.os.Handler;
286b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.os.Message;
296b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.os.PowerManager;
306b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.os.UserHandle;
316b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.text.format.DateFormat;
326b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.util.Log;
336b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.util.Slog;
346b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport android.util.TimeUtils;
356b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
366b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport com.android.server.notification.NotificationManagerService.DumpFilter;
376b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
386b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport java.io.PrintWriter;
396b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport java.util.ArrayList;
406b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockimport java.util.Locale;
416b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
426b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock/** Helper for tracking updates to the current user's next alarm. */
436b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlockpublic class NextAlarmTracker {
446b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private static final String TAG = "NextAlarmTracker";
456b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
466b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
476b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private static final String ACTION_TRIGGER = TAG + ".trigger";
486b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private static final String EXTRA_TRIGGER = "trigger";
496b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private static final int REQUEST_CODE = 100;
506b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
516b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private static final long SECONDS = 1000;
526b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private static final long MINUTES = 60 * SECONDS;
536b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private static final long NEXT_ALARM_UPDATE_DELAY = 1 * SECONDS;  // treat clear+set as update
546b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private static final long EARLY = 5 * SECONDS;  // fire early, ensure alarm stream is unmuted
556b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private static final long WAIT_AFTER_INIT = 5 * MINUTES;// for initial alarm re-registration
566b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private static final long WAIT_AFTER_BOOT = 20 * SECONDS;  // for initial alarm re-registration
576b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
586b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private final Context mContext;
596b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private final H mHandler = new H();
606b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
616b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
626b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private long mInit;
636b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private boolean mRegistered;
646b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private AlarmManager mAlarmManager;
656b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private int mCurrentUserId;
666b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private long mScheduledAlarmTime;
676b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private long mBootCompleted;
686b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private PowerManager.WakeLock mWakeLock;
696b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
706b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public NextAlarmTracker(Context context) {
716b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        mContext = context;
726b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
736b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
746b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public void dump(PrintWriter pw, DumpFilter filter) {
756b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        pw.println("    NextAlarmTracker:");
766b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        pw.print("      len(mCallbacks)="); pw.println(mCallbacks.size());
776b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        pw.print("      mRegistered="); pw.println(mRegistered);
786b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        pw.print("      mInit="); pw.println(mInit);
796b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        pw.print("      mBootCompleted="); pw.println(mBootCompleted);
806b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        pw.print("      mCurrentUserId="); pw.println(mCurrentUserId);
816b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        pw.print("      mScheduledAlarmTime="); pw.println(formatAlarmDebug(mScheduledAlarmTime));
826b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        pw.print("      mWakeLock="); pw.println(mWakeLock);
836b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
846b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
856b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public void addCallback(Callback callback) {
866b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        mCallbacks.add(callback);
876b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
886b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
896b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public void removeCallback(Callback callback) {
906b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        mCallbacks.remove(callback);
916b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
926b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
936b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public int getCurrentUserId() {
946b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        return mCurrentUserId;
956b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
966b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
976b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public AlarmClockInfo getNextAlarm() {
986b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        return mAlarmManager.getNextAlarmClock(mCurrentUserId);
996b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
1006b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
1016b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public void onUserSwitched() {
1026b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        reset();
1036b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
1046b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
1056b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public void init() {
1066b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
1076b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        final PowerManager p = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
1086b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        mWakeLock = p.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
1096b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        mInit = System.currentTimeMillis();
1106b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        reset();
1116b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
1126b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
1136b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public void reset() {
1146b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        if (mRegistered) {
1156b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            mContext.unregisterReceiver(mReceiver);
1166b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        }
1176b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        mCurrentUserId = ActivityManager.getCurrentUser();
1186b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        final IntentFilter filter = new IntentFilter();
1196b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
1206b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        filter.addAction(ACTION_TRIGGER);
1216b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        filter.addAction(Intent.ACTION_TIME_CHANGED);
1226b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
1236b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
1246b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        mContext.registerReceiverAsUser(mReceiver, new UserHandle(mCurrentUserId), filter, null,
1256b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock                null);
1266b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        mRegistered = true;
1276b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        evaluate();
1286b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
1296b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
1306b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public void destroy() {
1316b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        if (mRegistered) {
1326b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            mContext.unregisterReceiver(mReceiver);
1336b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            mRegistered = false;
1346b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        }
1356b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
1366b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
1376b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public void evaluate() {
1386b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        mHandler.postEvaluate(0);
1396b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
1406b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
1416b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private void fireEvaluate(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted) {
1426b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        for (Callback callback : mCallbacks) {
1436b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            callback.onEvaluate(nextAlarm, wakeupTime, booted);
1446b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        }
1456b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
1466b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
1476b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private void handleEvaluate() {
1486b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        final AlarmClockInfo nextAlarm = mAlarmManager.getNextAlarmClock(mCurrentUserId);
1496b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        final long triggerTime = getEarlyTriggerTime(nextAlarm);
1506b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        final long now = System.currentTimeMillis();
1516b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        final boolean alarmUpcoming = triggerTime > now;
1526b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        final boolean booted = isDoneWaitingAfterBoot(now);
1536b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        if (DEBUG) Slog.d(TAG, "handleEvaluate nextAlarm=" + formatAlarmDebug(triggerTime)
1546b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock                + " alarmUpcoming=" + alarmUpcoming
1556b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock                + " booted=" + booted);
1566b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        fireEvaluate(nextAlarm, triggerTime, booted);
1576b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        if (!booted) {
1586b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            // recheck after boot
1596b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            final long recheckTime = (mBootCompleted > 0 ? mBootCompleted : now) + WAIT_AFTER_BOOT;
1606b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            rescheduleAlarm(recheckTime);
1616b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            return;
1626b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        }
1636b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        if (alarmUpcoming) {
1646b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            // wake up just before the next alarm
1656b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            rescheduleAlarm(triggerTime);
1666b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        }
1676b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
1686b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
1696b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public static long getEarlyTriggerTime(AlarmClockInfo alarm) {
1706b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        return alarm != null ? (alarm.getTriggerTime() - EARLY) : 0;
1716b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
1726b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
1736b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private boolean isDoneWaitingAfterBoot(long time) {
1746b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        if (mBootCompleted > 0) return (time - mBootCompleted) > WAIT_AFTER_BOOT;
1756b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        if (mInit > 0) return (time - mInit) > WAIT_AFTER_INIT;
1766b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        return true;
1776b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
1786b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
1793c984d67ebf07e1215c6b403f0e18e309f2604e9John Spurlock    public static String formatDuration(long millis) {
1806b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        final StringBuilder sb = new StringBuilder();
1816b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        TimeUtils.formatDuration(millis, sb);
1826b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        return sb.toString();
1836b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
1846b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
1856b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public String formatAlarm(AlarmClockInfo alarm) {
1866b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        return alarm != null ? formatAlarm(alarm.getTriggerTime()) : null;
1876b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
1886b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
1896b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private String formatAlarm(long time) {
1906b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        return formatAlarm(time, "Hm", "hma");
1916b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
1926b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
1936b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private String formatAlarm(long time, String skeleton24, String skeleton12) {
1946b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        final String skeleton = DateFormat.is24HourFormat(mContext) ? skeleton24 : skeleton12;
1956b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
1966b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        return DateFormat.format(pattern, time).toString();
1976b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
1986b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
1993c984d67ebf07e1215c6b403f0e18e309f2604e9John Spurlock    public String formatAlarmDebug(AlarmClockInfo alarm) {
2006b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        return formatAlarmDebug(alarm != null ? alarm.getTriggerTime() : 0);
2016b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
2026b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
2036b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public String formatAlarmDebug(long time) {
2046b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        if (time <= 0) return Long.toString(time);
2056b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        return String.format("%s (%s)", time, formatAlarm(time, "Hms", "hmsa"));
2066b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
2076b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
2086b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private void rescheduleAlarm(long time) {
2096b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        if (DEBUG) Slog.d(TAG, "rescheduleAlarm " + time);
2106b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
2116b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE,
2126b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock                new Intent(ACTION_TRIGGER)
2136b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2146b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock                        .putExtra(EXTRA_TRIGGER, time),
2156b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock                PendingIntent.FLAG_UPDATE_CURRENT);
2166b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        alarms.cancel(pendingIntent);
2176b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        mScheduledAlarmTime = time;
2186b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        if (time > 0) {
2196b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            if (DEBUG) Slog.d(TAG, String.format("Scheduling alarm for %s (in %s)",
2206b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock                    formatAlarmDebug(time), formatDuration(time - System.currentTimeMillis())));
2216b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
2226b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        }
2236b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
2246b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
2256b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
2266b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        @Override
2276b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        public void onReceive(Context context, Intent intent) {
2286b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            final String action = intent.getAction();
2296b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            if (DEBUG) Slog.d(TAG, "onReceive " + action);
2306b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            long delay = 0;
2316b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            if (action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) {
2326b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock                delay = NEXT_ALARM_UPDATE_DELAY;
2336b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock                if (DEBUG) Slog.d(TAG, String.format("  next alarm for user %s: %s",
2346b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock                        mCurrentUserId,
2356b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock                        formatAlarmDebug(mAlarmManager.getNextAlarmClock(mCurrentUserId))));
2366b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
2376b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock                mBootCompleted = System.currentTimeMillis();
2386b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            }
2396b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            mHandler.postEvaluate(delay);
2406b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            mWakeLock.acquire(delay + 5000);  // stay awake during evaluate
2416b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        }
2426b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    };
2436b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
2446b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    private class H extends Handler {
2456b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        private static final int MSG_EVALUATE = 1;
2466b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
2476b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        public void postEvaluate(long delay) {
2486b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            removeMessages(MSG_EVALUATE);
2496b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            sendEmptyMessageDelayed(MSG_EVALUATE, delay);
2506b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        }
2516b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
2526b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        @Override
2536b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        public void handleMessage(Message msg) {
2546b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            if (msg.what == MSG_EVALUATE) {
2556b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock                handleEvaluate();
2566b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock            }
2576b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        }
2586b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
2596b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock
2606b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    public interface Callback {
2616b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock        void onEvaluate(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted);
2626b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock    }
2636b0623a1129a7e1bc4949b7dca4fa133ff322c4aJohn Spurlock}
264