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; 269329db04f13480ccdff013dcc00cdb96f12a921cWink Savilleimport android.telephony.Rlog; 279329db04f13480ccdff013dcc00cdb96f12a921cWink Saville 284cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.Comparator; 294cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.Iterator; 304cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.TreeSet; 314cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.concurrent.Executor; 324cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 334cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan/** 344cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * Timer that can schedule events to occur even when the device is in sleep. 354cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan */ 364cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanclass SipWakeupTimer extends BroadcastReceiver { 379329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private static final String TAG = "SipWakeupTimer"; 389329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private static final boolean DBG = SipService.DBG && true; // STOPSHIP if true 394cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private static final String TRIGGER_TIME = "TriggerTime"; 404cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 414cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private Context mContext; 424cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private AlarmManager mAlarmManager; 434cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 444cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan // runnable --> time to execute in SystemClock 454cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private TreeSet<MyEvent> mEventQueue = 464cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan new TreeSet<MyEvent>(new MyEventComparator()); 474cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 484cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private PendingIntent mPendingIntent; 494cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 504cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private Executor mExecutor; 514cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 524cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public SipWakeupTimer(Context context, Executor executor) { 534cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mContext = context; 544cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mAlarmManager = (AlarmManager) 554cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan context.getSystemService(Context.ALARM_SERVICE); 564cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 574cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan IntentFilter filter = new IntentFilter(getAction()); 584cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan context.registerReceiver(this, filter); 594cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mExecutor = executor; 604cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 614cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 624cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan /** 634cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * Stops the timer. No event can be scheduled after this method is called. 644cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan */ 654cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public synchronized void stop() { 664cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mContext.unregisterReceiver(this); 674cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mPendingIntent != null) { 684cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mAlarmManager.cancel(mPendingIntent); 694cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mPendingIntent = null; 704cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 714cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue.clear(); 724cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue = null; 734cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 744cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 7542cdc7a9d3f94260768f38de4f477ec4e418e19aHung-ying Tyan private boolean stopped() { 764cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mEventQueue == null) { 779329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("Timer stopped"); 784cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return true; 794cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } else { 804cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return false; 814cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 824cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 834cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 844cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private void cancelAlarm() { 854cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mAlarmManager.cancel(mPendingIntent); 864cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mPendingIntent = null; 874cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 884cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 894cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private void recalculatePeriods() { 904cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mEventQueue.isEmpty()) return; 914cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 924cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan MyEvent firstEvent = mEventQueue.first(); 934cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int minPeriod = firstEvent.mMaxPeriod; 944cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long minTriggerTime = firstEvent.mTriggerTime; 954cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan for (MyEvent e : mEventQueue) { 964cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan e.mPeriod = e.mMaxPeriod / minPeriod * minPeriod; 974cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int interval = (int) (e.mLastTriggerTime + e.mMaxPeriod 984cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan - minTriggerTime); 994cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan interval = interval / minPeriod * minPeriod; 1004cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan e.mTriggerTime = minTriggerTime + interval; 1014cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1024cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan TreeSet<MyEvent> newQueue = new TreeSet<MyEvent>( 1034cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue.comparator()); 1049329db04f13480ccdff013dcc00cdb96f12a921cWink Saville newQueue.addAll(mEventQueue); 1054cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue.clear(); 1064cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue = newQueue; 1079329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) { 1089329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log("queue re-calculated"); 1094cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan printQueue(); 1104cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1114cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1124cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1134cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan // Determines the period and the trigger time of the new event and insert it 1144cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan // to the queue. 1154cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private void insertEvent(MyEvent event) { 1164cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long now = SystemClock.elapsedRealtime(); 1174cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mEventQueue.isEmpty()) { 1184cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mTriggerTime = now + event.mPeriod; 1194cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue.add(event); 1204cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return; 1214cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1224cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan MyEvent firstEvent = mEventQueue.first(); 1234cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int minPeriod = firstEvent.mPeriod; 1244cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (minPeriod <= event.mMaxPeriod) { 1254cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mPeriod = event.mMaxPeriod / minPeriod * minPeriod; 1264cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int interval = event.mMaxPeriod; 1274cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan interval -= (int) (firstEvent.mTriggerTime - now); 1284cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan interval = interval / minPeriod * minPeriod; 1294cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mTriggerTime = firstEvent.mTriggerTime + interval; 1304cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue.add(event); 1314cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } else { 1324cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long triggerTime = now + event.mPeriod; 1334cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (firstEvent.mTriggerTime < triggerTime) { 1344cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mTriggerTime = firstEvent.mTriggerTime; 1354cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mLastTriggerTime -= event.mPeriod; 1364cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } else { 1374cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mTriggerTime = triggerTime; 1384cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1394cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mEventQueue.add(event); 1404cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan recalculatePeriods(); 1414cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1424cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1434cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1444cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan /** 1454cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * Sets a periodic timer. 1464cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * 1474cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * @param period the timer period; in milli-second 1484cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * @param callback is called back when the timer goes off; the same callback 1494cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * can be specified in multiple timer events 1504cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan */ 1514cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public synchronized void set(int period, Runnable callback) { 1524cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (stopped()) return; 1534cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1544cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long now = SystemClock.elapsedRealtime(); 1554cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan MyEvent event = new MyEvent(period, callback, now); 1564cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan insertEvent(event); 1574cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1584cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mEventQueue.first() == event) { 1594cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mEventQueue.size() > 1) cancelAlarm(); 1604cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan scheduleNext(); 1614cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1624cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1634cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long triggerTime = event.mTriggerTime; 1649329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) { 1659329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log("set: add event " + event + " scheduled on " 1664cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan + showTime(triggerTime) + " at " + showTime(now) 1674cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan + ", #events=" + mEventQueue.size()); 1684cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan printQueue(); 1694cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1704cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1714cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1724cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan /** 1734cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * Cancels all the timer events with the specified callback. 1744cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * 1754cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan * @param callback the callback 1764cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan */ 1774cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public synchronized void cancel(Runnable callback) { 1784cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (stopped() || mEventQueue.isEmpty()) return; 1799329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("cancel:" + callback); 1804cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 1814cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan MyEvent firstEvent = mEventQueue.first(); 1824cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan for (Iterator<MyEvent> iter = mEventQueue.iterator(); 1834cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan iter.hasNext();) { 1844cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan MyEvent event = iter.next(); 1854cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (event.mCallback == callback) { 1864cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan iter.remove(); 1879329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log(" cancel found:" + event); 1884cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1894cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 1904cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mEventQueue.isEmpty()) { 1914cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan cancelAlarm(); 1924cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } else if (mEventQueue.first() != firstEvent) { 1934cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan cancelAlarm(); 1944cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan firstEvent = mEventQueue.first(); 1954cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan firstEvent.mPeriod = firstEvent.mMaxPeriod; 1964cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan firstEvent.mTriggerTime = firstEvent.mLastTriggerTime 1974cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan + firstEvent.mPeriod; 1984cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan recalculatePeriods(); 1994cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan scheduleNext(); 2004cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2019329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) { 2029329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log("cancel: X"); 2034cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan printQueue(); 2044cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2054cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2064cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2074cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private void scheduleNext() { 2084cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (stopped() || mEventQueue.isEmpty()) return; 2094cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2104cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mPendingIntent != null) { 2114cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan throw new RuntimeException("pendingIntent is not null!"); 2124cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2134cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2144cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan MyEvent event = mEventQueue.first(); 2154cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan Intent intent = new Intent(getAction()); 2164cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan intent.putExtra(TRIGGER_TIME, event.mTriggerTime); 2174cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan PendingIntent pendingIntent = mPendingIntent = 2184cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan PendingIntent.getBroadcast(mContext, 0, intent, 2194cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan PendingIntent.FLAG_UPDATE_CURRENT); 2204cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 2214cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mTriggerTime, pendingIntent); 2224cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2234cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2244cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan @Override 22542cdc7a9d3f94260768f38de4f477ec4e418e19aHung-ying Tyan public synchronized void onReceive(Context context, Intent intent) { 2264cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan // This callback is already protected by AlarmManager's wake lock. 2274cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan String action = intent.getAction(); 2284cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (getAction().equals(action) 2294cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan && intent.getExtras().containsKey(TRIGGER_TIME)) { 2304cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mPendingIntent = null; 2314cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long triggerTime = intent.getLongExtra(TRIGGER_TIME, -1L); 2324cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan execute(triggerTime); 2334cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } else { 2349329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log("onReceive: unrecognized intent: " + intent); 2354cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2364cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2374cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2384cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private void printQueue() { 2394cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int count = 0; 2404cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan for (MyEvent event : mEventQueue) { 2419329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log(" " + event + ": scheduled at " 2424cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan + showTime(event.mTriggerTime) + ": last at " 2434cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan + showTime(event.mLastTriggerTime)); 2444cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (++count >= 5) break; 2454cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2464cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (mEventQueue.size() > count) { 2479329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log(" ....."); 2484cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } else if (count == 0) { 2499329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log(" <empty>"); 2504cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2514cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2524cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 25342cdc7a9d3f94260768f38de4f477ec4e418e19aHung-ying Tyan private void execute(long triggerTime) { 2549329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("time's up, triggerTime = " 2554cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan + showTime(triggerTime) + ": " + mEventQueue.size()); 2564cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (stopped() || mEventQueue.isEmpty()) return; 2574cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2584cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan for (MyEvent event : mEventQueue) { 259f22d0eb0b438a8354144e3abe087f8b13e62cd55Hung-ying Tyan if (event.mTriggerTime != triggerTime) continue; 2609329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("execute " + event); 2614cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 262f22d0eb0b438a8354144e3abe087f8b13e62cd55Hung-ying Tyan event.mLastTriggerTime = triggerTime; 2634cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan event.mTriggerTime += event.mPeriod; 2644cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2654cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan // run the callback in the handler thread to prevent deadlock 2664cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mExecutor.execute(event.mCallback); 2674cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2689329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) { 2699329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log("after timeout execution"); 2704cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan printQueue(); 2714cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2724cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan scheduleNext(); 2734cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2744cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2754cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private String getAction() { 2764cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return toString(); 2774cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2784cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2794cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private String showTime(long time) { 2804cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int ms = (int) (time % 1000); 2814cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int s = (int) (time / 1000); 2824cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int m = s / 60; 2834cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan s %= 60; 2844cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return String.format("%d.%d.%d", m, s, ms); 2854cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2864cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2874cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private static class MyEvent { 2884cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int mPeriod; 2894cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int mMaxPeriod; 2904cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long mTriggerTime; 2914cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan long mLastTriggerTime; 2924cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan Runnable mCallback; 2934cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 2944cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan MyEvent(int period, Runnable callback, long now) { 2954cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mPeriod = mMaxPeriod = period; 2964cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mCallback = callback; 2974cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mLastTriggerTime = now; 2984cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 2994cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 3004cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan @Override 3014cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public String toString() { 3024cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan String s = super.toString(); 3034cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan s = s.substring(s.indexOf("@")); 3044cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return s + ":" + (mPeriod / 1000) + ":" + (mMaxPeriod / 1000) + ":" 3054cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan + toString(mCallback); 3064cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 3074cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 3084cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private String toString(Object o) { 3094cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan String s = o.toString(); 3104cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int index = s.indexOf("$"); 3114cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (index > 0) s = s.substring(index + 1); 3124cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return s; 3134cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 3144cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 3154cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 316f22d0eb0b438a8354144e3abe087f8b13e62cd55Hung-ying Tyan // Sort the events by mMaxPeriod so that the first event can be used to 317f22d0eb0b438a8354144e3abe087f8b13e62cd55Hung-ying Tyan // align events with larger periods 3184cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private static class MyEventComparator implements Comparator<MyEvent> { 3199329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 3204cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public int compare(MyEvent e1, MyEvent e2) { 3214cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (e1 == e2) return 0; 3224cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan int diff = e1.mMaxPeriod - e2.mMaxPeriod; 3234cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan if (diff == 0) diff = -1; 3244cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return diff; 3254cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 3264cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan 3279329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 3284cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public boolean equals(Object that) { 3294cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan return (this == that); 3304cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 3314cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan } 3329329db04f13480ccdff013dcc00cdb96f12a921cWink Saville 3339329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private void log(String s) { 3349329db04f13480ccdff013dcc00cdb96f12a921cWink Saville Rlog.d(TAG, s); 3359329db04f13480ccdff013dcc00cdb96f12a921cWink Saville } 3364cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan} 337