FileDocCategorySizeDatePackage
SipWakeupTimer.javaAPI DocAndroid 5.1 API11053Thu Mar 12 22:22:52 GMT 2015com.android.server.sip

SipWakeupTimer

public class SipWakeupTimer extends android.content.BroadcastReceiver
Timer that can schedule events to occur even when the device is in sleep.

Fields Summary
private static final String
TAG
private static final boolean
DBG
private static final String
TRIGGER_TIME
private android.content.Context
mContext
private android.app.AlarmManager
mAlarmManager
private TreeSet
mEventQueue
private android.app.PendingIntent
mPendingIntent
private Executor
mExecutor
Constructors Summary
public SipWakeupTimer(android.content.Context context, Executor executor)


         
        mContext = context;
        mAlarmManager = (AlarmManager)
                context.getSystemService(Context.ALARM_SERVICE);

        IntentFilter filter = new IntentFilter(getAction());
        context.registerReceiver(this, filter);
        mExecutor = executor;
    
Methods Summary
public synchronized voidcancel(java.lang.Runnable callback)
Cancels all the timer events with the specified callback.

param
callback the callback

        if (stopped() || mEventQueue.isEmpty()) return;
        if (DBG) log("cancel:" + callback);

        MyEvent firstEvent = mEventQueue.first();
        for (Iterator<MyEvent> iter = mEventQueue.iterator();
                iter.hasNext();) {
            MyEvent event = iter.next();
            if (event.mCallback == callback) {
                iter.remove();
                if (DBG) log("    cancel found:" + event);
            }
        }
        if (mEventQueue.isEmpty()) {
            cancelAlarm();
        } else if (mEventQueue.first() != firstEvent) {
            cancelAlarm();
            firstEvent = mEventQueue.first();
            firstEvent.mPeriod = firstEvent.mMaxPeriod;
            firstEvent.mTriggerTime = firstEvent.mLastTriggerTime
                    + firstEvent.mPeriod;
            recalculatePeriods();
            scheduleNext();
        }
        if (DBG) {
            log("cancel: X");
            printQueue();
        }
    
private voidcancelAlarm()

        mAlarmManager.cancel(mPendingIntent);
        mPendingIntent = null;
    
private voidexecute(long triggerTime)

        if (DBG) log("time's up, triggerTime = "
                + showTime(triggerTime) + ": " + mEventQueue.size());
        if (stopped() || mEventQueue.isEmpty()) return;

        for (MyEvent event : mEventQueue) {
            if (event.mTriggerTime != triggerTime) continue;
            if (DBG) log("execute " + event);

            event.mLastTriggerTime = triggerTime;
            event.mTriggerTime += event.mPeriod;

            // run the callback in the handler thread to prevent deadlock
            mExecutor.execute(event.mCallback);
        }
        if (DBG) {
            log("after timeout execution");
            printQueue();
        }
        scheduleNext();
    
private java.lang.StringgetAction()

        return toString();
    
private voidinsertEvent(com.android.server.sip.SipWakeupTimer$MyEvent event)

        long now = SystemClock.elapsedRealtime();
        if (mEventQueue.isEmpty()) {
            event.mTriggerTime = now + event.mPeriod;
            mEventQueue.add(event);
            return;
        }
        MyEvent firstEvent = mEventQueue.first();
        int minPeriod = firstEvent.mPeriod;
        if (minPeriod <= event.mMaxPeriod) {
            event.mPeriod = event.mMaxPeriod / minPeriod * minPeriod;
            int interval = event.mMaxPeriod;
            interval -= (int) (firstEvent.mTriggerTime - now);
            interval = interval / minPeriod * minPeriod;
            event.mTriggerTime = firstEvent.mTriggerTime + interval;
            mEventQueue.add(event);
        } else {
            long triggerTime = now + event.mPeriod;
            if (firstEvent.mTriggerTime < triggerTime) {
                event.mTriggerTime = firstEvent.mTriggerTime;
                event.mLastTriggerTime -= event.mPeriod;
            } else {
                event.mTriggerTime = triggerTime;
            }
            mEventQueue.add(event);
            recalculatePeriods();
        }
    
private voidlog(java.lang.String s)

        Rlog.d(TAG, s);
    
public synchronized voidonReceive(android.content.Context context, android.content.Intent intent)

        // This callback is already protected by AlarmManager's wake lock.
        String action = intent.getAction();
        if (getAction().equals(action)
                && intent.getExtras().containsKey(TRIGGER_TIME)) {
            mPendingIntent = null;
            long triggerTime = intent.getLongExtra(TRIGGER_TIME, -1L);
            execute(triggerTime);
        } else {
            log("onReceive: unrecognized intent: " + intent);
        }
    
private voidprintQueue()

        int count = 0;
        for (MyEvent event : mEventQueue) {
            log("     " + event + ": scheduled at "
                    + showTime(event.mTriggerTime) + ": last at "
                    + showTime(event.mLastTriggerTime));
            if (++count >= 5) break;
        }
        if (mEventQueue.size() > count) {
            log("     .....");
        } else if (count == 0) {
            log("     <empty>");
        }
    
private voidrecalculatePeriods()

        if (mEventQueue.isEmpty()) return;

        MyEvent firstEvent = mEventQueue.first();
        int minPeriod = firstEvent.mMaxPeriod;
        long minTriggerTime = firstEvent.mTriggerTime;
        for (MyEvent e : mEventQueue) {
            e.mPeriod = e.mMaxPeriod / minPeriod * minPeriod;
            int interval = (int) (e.mLastTriggerTime + e.mMaxPeriod
                    - minTriggerTime);
            interval = interval / minPeriod * minPeriod;
            e.mTriggerTime = minTriggerTime + interval;
        }
        TreeSet<MyEvent> newQueue = new TreeSet<MyEvent>(
                mEventQueue.comparator());
        newQueue.addAll(mEventQueue);
        mEventQueue.clear();
        mEventQueue = newQueue;
        if (DBG) {
            log("queue re-calculated");
            printQueue();
        }
    
private voidscheduleNext()

        if (stopped() || mEventQueue.isEmpty()) return;

        if (mPendingIntent != null) {
            throw new RuntimeException("pendingIntent is not null!");
        }

        MyEvent event = mEventQueue.first();
        Intent intent = new Intent(getAction());
        intent.putExtra(TRIGGER_TIME, event.mTriggerTime);
        PendingIntent pendingIntent = mPendingIntent =
                PendingIntent.getBroadcast(mContext, 0, intent,
                        PendingIntent.FLAG_UPDATE_CURRENT);
        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                event.mTriggerTime, pendingIntent);
    
public synchronized voidset(int period, java.lang.Runnable callback)
Sets a periodic timer.

param
period the timer period; in milli-second
param
callback is called back when the timer goes off; the same callback can be specified in multiple timer events

        if (stopped()) return;

        long now = SystemClock.elapsedRealtime();
        MyEvent event = new MyEvent(period, callback, now);
        insertEvent(event);

        if (mEventQueue.first() == event) {
            if (mEventQueue.size() > 1) cancelAlarm();
            scheduleNext();
        }

        long triggerTime = event.mTriggerTime;
        if (DBG) {
            log("set: add event " + event + " scheduled on "
                    + showTime(triggerTime) + " at " + showTime(now)
                    + ", #events=" + mEventQueue.size());
            printQueue();
        }
    
private java.lang.StringshowTime(long time)

        int ms = (int) (time % 1000);
        int s = (int) (time / 1000);
        int m = s / 60;
        s %= 60;
        return String.format("%d.%d.%d", m, s, ms);
    
public synchronized voidstop()
Stops the timer. No event can be scheduled after this method is called.

        mContext.unregisterReceiver(this);
        if (mPendingIntent != null) {
            mAlarmManager.cancel(mPendingIntent);
            mPendingIntent = null;
        }
        mEventQueue.clear();
        mEventQueue = null;
    
private booleanstopped()

        if (mEventQueue == null) {
            if (DBG) log("Timer stopped");
            return true;
        } else {
            return false;
        }