package com.android.server.wifi.hotspot2; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; public class Chronograph extends Thread { private final Map<Long, Set<AlarmEntry>> mAlarmEntryMap = new TreeMap<Long, Set<AlarmEntry>>(); private boolean mRecalculate; private static class AlarmEntry { private final long mAt; private final AlarmHandler mAlarmHandler; private final Object mToken; private AlarmEntry(long at, AlarmHandler alarmHandler, Object token) { mAt = at; mAlarmHandler = alarmHandler; mToken = token; } private void callout() { mAlarmHandler.wake(mToken); } } public Chronograph() { setName("Chronograph"); setDaemon(true); } public Object addAlarm(long interval, AlarmHandler handler, Object token) { long at = System.currentTimeMillis() + interval; synchronized (mAlarmEntryMap) { AlarmEntry alarmEntry = new AlarmEntry(at, handler, token); Set<AlarmEntry> entries = mAlarmEntryMap.get(at); if (entries == null) { entries = new HashSet<AlarmEntry>(1); mAlarmEntryMap.put(at, entries); } entries.add(alarmEntry); mRecalculate = true; mAlarmEntryMap.notifyAll(); return alarmEntry; } } public boolean cancelAlarm(Object key) { if (key == null || key.getClass() != AlarmEntry.class) { throw new IllegalArgumentException("Not an alarm key"); } AlarmEntry alarmEntry = (AlarmEntry)key; synchronized (mAlarmEntryMap) { Set<AlarmEntry> entries = mAlarmEntryMap.get(alarmEntry.mAt); if (entries == null) { return false; } if (entries.remove(alarmEntry)) { mRecalculate = true; mAlarmEntryMap.notifyAll(); return true; } return false; } } @Override public void run() { for(;;) { long now = System.currentTimeMillis(); List<Set<AlarmEntry>> pending = new ArrayList<Set<AlarmEntry>>(); long nextExpiration = 0; synchronized (mAlarmEntryMap) { Iterator<Map.Entry<Long,Set<AlarmEntry>>> entries = mAlarmEntryMap.entrySet().iterator(); while (entries.hasNext()) { Map.Entry<Long,Set<AlarmEntry>> entry = entries.next(); if (entry.getKey() <= now) { pending.add(entry.getValue()); entries.remove(); } else { nextExpiration = entry.getKey(); break; } } } for (Set<AlarmEntry> alarmEntries : pending) { for (AlarmEntry alarmEntry : alarmEntries) { alarmEntry.callout(); } } now = System.currentTimeMillis(); synchronized (mAlarmEntryMap) { long sleep = nextExpiration - now; while (sleep > 0 && !mRecalculate) { try { mAlarmEntryMap.wait(sleep); } catch (InterruptedException ie) { /**/ } sleep = nextExpiration - System.currentTimeMillis(); } } } } public static void main(String[] args) throws InterruptedException{ Chronograph chronograph = new Chronograph(); chronograph.start(); chronograph.addAlarm(3000L, new AlarmHandler() { @Override public void wake(Object token) { System.out.println("3: " + token); } }, "3s" ); Object key = chronograph.addAlarm(7500L, new AlarmHandler() { @Override public void wake(Object token) { System.out.println("7: " + token); } }, "7.5s" ); chronograph.addAlarm(10000L, new AlarmHandler() { @Override public void wake(Object token) { System.out.println("10: " + token); } }, "10.00s" ); System.out.println(chronograph.cancelAlarm(key)); chronograph.join(); } }