SipWakeupTimer.java revision f22d0eb0b438a8354144e3abe087f8b13e62cd55
14cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan/* 24cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * Copyright (C) 2011, The Android Open Source Project 34cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * 44cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * Licensed under the Apache License, Version 2.0 (the "License"); 54cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * you may not use this file except in compliance with the License. 64cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * You may obtain a copy of the License at 74cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * 84cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * http://www.apache.org/licenses/LICENSE-2.0 94cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * 104cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * Unless required by applicable law or agreed to in writing, software 114cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * distributed under the License is distributed on an "AS IS" BASIS, 124cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * See the License for the specific language governing permissions and 144cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * limitations under the License. 154cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan */ 164cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 174cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanpackage com.android.server.sip; 184cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 194cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport android.app.AlarmManager; 204cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport android.app.PendingIntent; 214cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport android.content.BroadcastReceiver; 224cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport android.content.Context; 234cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport android.content.Intent; 244cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport android.content.IntentFilter; 254cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport android.os.SystemClock; 264cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport android.util.Log; 274cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 284cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.io.IOException; 294cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.net.DatagramSocket; 304cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.net.InetAddress; 314cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.net.UnknownHostException; 324cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.ArrayList; 334cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.Collection; 344cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.Comparator; 354cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.HashMap; 364cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.Iterator; 374cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.Map; 384cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.Timer; 394cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.TimerTask; 404cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.TreeSet; 414cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.concurrent.Executor; 424cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport javax.sip.SipException; 434cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 444cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan/** 454cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * Timer that can schedule events to occur even when the device is in sleep. 464cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan */ 474cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanclass SipWakeupTimer extends BroadcastReceiver { 484cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private static final String TAG = "_SIP.WkTimer_"; 494cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private static final String TRIGGER_TIME = "TriggerTime"; 504cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private static final boolean DEBUG_TIMER = SipService.DEBUG && false; 514cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 524cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private Context mContext; 534cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private AlarmManager mAlarmManager; 544cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 554cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan // runnable --> time to execute in SystemClock 564cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private TreeSet<MyEvent> mEventQueue = 574cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan new TreeSet<MyEvent>(new MyEventComparator()); 584cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 594cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private PendingIntent mPendingIntent; 604cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 614cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private Executor mExecutor; 624cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 634cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public SipWakeupTimer(Context context, Executor executor) { 644cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mContext = context; 654cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mAlarmManager = (AlarmManager) 664cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan context.getSystemService(Context.ALARM_SERVICE); 674cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 684cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan IntentFilter filter = new IntentFilter(getAction()); 694cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan context.registerReceiver(this, filter); 704cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mExecutor = executor; 714cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 724cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 734cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan /** 744cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * Stops the timer. No event can be scheduled after this method is called. 754cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan */ 764cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public synchronized void stop() { 774cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mContext.unregisterReceiver(this); 784cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mPendingIntent != null) { 794cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mAlarmManager.cancel(mPendingIntent); 804cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mPendingIntent = null; 814cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 824cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue.clear(); 834cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue = null; 844cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 854cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 864cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private synchronized boolean stopped() { 874cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mEventQueue == null) { 884cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan Log.w(TAG, "Timer stopped"); 894cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return true; 904cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } else { 914cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return false; 924cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 934cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 944cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 954cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private void cancelAlarm() { 964cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mAlarmManager.cancel(mPendingIntent); 974cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mPendingIntent = null; 984cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 994cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1004cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private void recalculatePeriods() { 1014cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mEventQueue.isEmpty()) return; 1024cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1034cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan MyEvent firstEvent = mEventQueue.first(); 1044cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int minPeriod = firstEvent.mMaxPeriod; 1054cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long minTriggerTime = firstEvent.mTriggerTime; 1064cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan for (MyEvent e : mEventQueue) { 1074cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan e.mPeriod = e.mMaxPeriod / minPeriod * minPeriod; 1084cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int interval = (int) (e.mLastTriggerTime + e.mMaxPeriod 1094cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan - minTriggerTime); 1104cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan interval = interval / minPeriod * minPeriod; 1114cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan e.mTriggerTime = minTriggerTime + interval; 1124cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1134cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan TreeSet<MyEvent> newQueue = new TreeSet<MyEvent>( 1144cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue.comparator()); 1154cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan newQueue.addAll((Collection<MyEvent>) mEventQueue); 1164cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue.clear(); 1174cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue = newQueue; 1184cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (DEBUG_TIMER) { 1194cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan Log.d(TAG, "queue re-calculated"); 1204cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan printQueue(); 1214cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1224cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1234cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1244cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan // Determines the period and the trigger time of the new event and insert it 1254cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan // to the queue. 1264cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private void insertEvent(MyEvent event) { 1274cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long now = SystemClock.elapsedRealtime(); 1284cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mEventQueue.isEmpty()) { 1294cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mTriggerTime = now + event.mPeriod; 1304cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue.add(event); 1314cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return; 1324cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1334cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan MyEvent firstEvent = mEventQueue.first(); 1344cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int minPeriod = firstEvent.mPeriod; 1354cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (minPeriod <= event.mMaxPeriod) { 1364cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mPeriod = event.mMaxPeriod / minPeriod * minPeriod; 1374cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int interval = event.mMaxPeriod; 1384cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan interval -= (int) (firstEvent.mTriggerTime - now); 1394cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan interval = interval / minPeriod * minPeriod; 1404cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mTriggerTime = firstEvent.mTriggerTime + interval; 1414cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue.add(event); 1424cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } else { 1434cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long triggerTime = now + event.mPeriod; 1444cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (firstEvent.mTriggerTime < triggerTime) { 1454cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mTriggerTime = firstEvent.mTriggerTime; 1464cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mLastTriggerTime -= event.mPeriod; 1474cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } else { 1484cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mTriggerTime = triggerTime; 1494cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1504cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue.add(event); 1514cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan recalculatePeriods(); 1524cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1534cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1544cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1554cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan /** 1564cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * Sets a periodic timer. 1574cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * 1584cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * @param period the timer period; in milli-second 1594cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * @param callback is called back when the timer goes off; the same callback 1604cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * can be specified in multiple timer events 1614cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan */ 1624cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public synchronized void set(int period, Runnable callback) { 1634cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (stopped()) return; 1644cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1654cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long now = SystemClock.elapsedRealtime(); 1664cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan MyEvent event = new MyEvent(period, callback, now); 1674cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan insertEvent(event); 1684cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1694cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mEventQueue.first() == event) { 1704cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mEventQueue.size() > 1) cancelAlarm(); 1714cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan scheduleNext(); 1724cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1734cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1744cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long triggerTime = event.mTriggerTime; 1754cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (DEBUG_TIMER) { 176f22d0eb0b438a8354144e3abe087f8b13e62cd55Hung-ying Tyan Log.d(TAG, " add event " + event + " scheduled on " 1774cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan + showTime(triggerTime) + " at " + showTime(now) 1784cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan + ", #events=" + mEventQueue.size()); 1794cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan printQueue(); 1804cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1814cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1824cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1834cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan /** 1844cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * Cancels all the timer events with the specified callback. 1854cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * 1864cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * @param callback the callback 1874cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan */ 1884cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public synchronized void cancel(Runnable callback) { 1894cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (stopped() || mEventQueue.isEmpty()) return; 1904cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (DEBUG_TIMER) Log.d(TAG, "cancel:" + callback); 1914cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1924cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan MyEvent firstEvent = mEventQueue.first(); 1934cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan for (Iterator<MyEvent> iter = mEventQueue.iterator(); 1944cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan iter.hasNext();) { 1954cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan MyEvent event = iter.next(); 1964cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (event.mCallback == callback) { 1974cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan iter.remove(); 1984cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (DEBUG_TIMER) Log.d(TAG, " cancel found:" + event); 1994cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2004cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2014cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mEventQueue.isEmpty()) { 2024cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan cancelAlarm(); 2034cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } else if (mEventQueue.first() != firstEvent) { 2044cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan cancelAlarm(); 2054cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan firstEvent = mEventQueue.first(); 2064cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan firstEvent.mPeriod = firstEvent.mMaxPeriod; 2074cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan firstEvent.mTriggerTime = firstEvent.mLastTriggerTime 2084cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan + firstEvent.mPeriod; 2094cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan recalculatePeriods(); 2104cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan scheduleNext(); 2114cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2124cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (DEBUG_TIMER) { 2134cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan Log.d(TAG, "after cancel:"); 2144cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan printQueue(); 2154cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2164cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2174cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2184cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private void scheduleNext() { 2194cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (stopped() || mEventQueue.isEmpty()) return; 2204cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2214cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mPendingIntent != null) { 2224cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan throw new RuntimeException("pendingIntent is not null!"); 2234cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2244cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2254cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan MyEvent event = mEventQueue.first(); 2264cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan Intent intent = new Intent(getAction()); 2274cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan intent.putExtra(TRIGGER_TIME, event.mTriggerTime); 2284cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan PendingIntent pendingIntent = mPendingIntent = 2294cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan PendingIntent.getBroadcast(mContext, 0, intent, 2304cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan PendingIntent.FLAG_UPDATE_CURRENT); 2314cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 2324cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mTriggerTime, pendingIntent); 2334cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2344cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2354cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan @Override 2364cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public void onReceive(Context context, Intent intent) { 2374cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan // This callback is already protected by AlarmManager's wake lock. 2384cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan String action = intent.getAction(); 2394cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (getAction().equals(action) 2404cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan && intent.getExtras().containsKey(TRIGGER_TIME)) { 2414cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mPendingIntent = null; 2424cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long triggerTime = intent.getLongExtra(TRIGGER_TIME, -1L); 2434cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan execute(triggerTime); 2444cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } else { 2454cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan Log.d(TAG, "unrecognized intent: " + intent); 2464cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2474cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2484cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2494cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private void printQueue() { 2504cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int count = 0; 2514cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan for (MyEvent event : mEventQueue) { 2524cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan Log.d(TAG, " " + event + ": scheduled at " 2534cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan + showTime(event.mTriggerTime) + ": last at " 2544cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan + showTime(event.mLastTriggerTime)); 2554cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (++count >= 5) break; 2564cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2574cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mEventQueue.size() > count) { 2584cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan Log.d(TAG, " ....."); 2594cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } else if (count == 0) { 2604cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan Log.d(TAG, " <empty>"); 2614cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2624cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2634cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2644cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private synchronized void execute(long triggerTime) { 2654cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (DEBUG_TIMER) Log.d(TAG, "time's up, triggerTime = " 2664cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan + showTime(triggerTime) + ": " + mEventQueue.size()); 2674cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (stopped() || mEventQueue.isEmpty()) return; 2684cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2694cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan for (MyEvent event : mEventQueue) { 270f22d0eb0b438a8354144e3abe087f8b13e62cd55Hung-ying Tyan if (event.mTriggerTime != triggerTime) continue; 2714cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (DEBUG_TIMER) Log.d(TAG, "execute " + event); 2724cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 273f22d0eb0b438a8354144e3abe087f8b13e62cd55Hung-ying Tyan event.mLastTriggerTime = triggerTime; 2744cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mTriggerTime += event.mPeriod; 2754cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2764cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan // run the callback in the handler thread to prevent deadlock 2774cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mExecutor.execute(event.mCallback); 2784cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2794cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (DEBUG_TIMER) { 2804cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan Log.d(TAG, "after timeout execution"); 2814cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan printQueue(); 2824cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2834cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan scheduleNext(); 2844cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2854cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2864cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private String getAction() { 2874cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return toString(); 2884cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2894cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2904cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private String showTime(long time) { 2914cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int ms = (int) (time % 1000); 2924cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int s = (int) (time / 1000); 2934cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int m = s / 60; 2944cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan s %= 60; 2954cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return String.format("%d.%d.%d", m, s, ms); 2964cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2974cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2984cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private static class MyEvent { 2994cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int mPeriod; 3004cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int mMaxPeriod; 3014cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long mTriggerTime; 3024cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long mLastTriggerTime; 3034cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan Runnable mCallback; 3044cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 3054cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan MyEvent(int period, Runnable callback, long now) { 3064cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mPeriod = mMaxPeriod = period; 3074cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mCallback = callback; 3084cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mLastTriggerTime = now; 3094cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 3104cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 3114cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan @Override 3124cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public String toString() { 3134cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan String s = super.toString(); 3144cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan s = s.substring(s.indexOf("@")); 3154cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return s + ":" + (mPeriod / 1000) + ":" + (mMaxPeriod / 1000) + ":" 3164cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan + toString(mCallback); 3174cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 3184cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 3194cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private String toString(Object o) { 3204cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan String s = o.toString(); 3214cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int index = s.indexOf("$"); 3224cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (index > 0) s = s.substring(index + 1); 3234cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return s; 3244cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 3254cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 3264cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 327f22d0eb0b438a8354144e3abe087f8b13e62cd55Hung-ying Tyan // Sort the events by mMaxPeriod so that the first event can be used to 328f22d0eb0b438a8354144e3abe087f8b13e62cd55Hung-ying Tyan // align events with larger periods 3294cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private static class MyEventComparator implements Comparator<MyEvent> { 3304cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public int compare(MyEvent e1, MyEvent e2) { 3314cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (e1 == e2) return 0; 3324cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int diff = e1.mMaxPeriod - e2.mMaxPeriod; 3334cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (diff == 0) diff = -1; 3344cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return diff; 3354cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 3364cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 3374cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public boolean equals(Object that) { 3384cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return (this == that); 3394cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 3404cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 3414cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan} 342