package org.kvj.vimtouch.plugins.ext.timer; import java.util.Date; import org.kvj.vimtouch.ext.IncomingTransfer; import org.kvj.vimtouch.ext.impl.event.EventRequest; import org.kvj.vimtouch.ext.impl.event.EventResponse; import org.kvj.vimtouch.ext.impl.read.NumberFieldReader; import org.kvj.vimtouch.ext.manager.IntegrationExtensionException; import org.kvj.vimtouch.ext.manager.impl.SimplePlugin; import org.kvj.vimtouch.plugins.ext.timer.TimerExtension.TimerInput; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; import android.util.Log; public class TimerExtension extends SimplePlugin<TimerInput, EventResponse> { private Context ctx = null; public TimerExtension(Context ctx) { super(ctx); this.ctx = ctx; } private PendingIntent createIntent(int subscription, Bundle extras) { Intent intent = new Intent(ctx, AlarmReceiver.class); if (null != extras) { intent.putExtras(extras); } intent.setData(Uri.fromParts("subscription", "code", String.format("%d", subscription))); return PendingIntent.getBroadcast(ctx, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } private void runAtTime(long when, long repeat, int subscription) { AlarmManager alarmManager = (AlarmManager) ctx .getSystemService(Context.ALARM_SERVICE); Bundle b = new Bundle(); b.putLong("repeat", repeat); b.putInt("subscription", subscription); PendingIntent intent = createIntent(subscription, b); Log.d(TAG, "Schedule timer: " + (new Date(when)) + ", " + subscription); alarmManager.set(AlarmManager.RTC_WAKEUP, when, intent); } private void cancelRunAtTime(int subscription) { AlarmManager alarmManager = (AlarmManager) ctx .getSystemService(Context.ALARM_SERVICE); alarmManager.cancel(createIntent(subscription, null)); } static class TimerInput extends EventRequest { int interval = 0; long time = 0; @Override public void readFrom(IncomingTransfer t) { super.readFrom(t); t.readAs("interval", new NumberFieldReader() { @Override public void set(Number value) { interval = value.intValue(); } }); t.readAs("time", new NumberFieldReader() { @Override public void set(Number value) { time = value.longValue(); } }); } } private static final String TYPE = "timer"; @Override public String getType() { return TYPE; } @Override public TimerInput newInput() { return new TimerInput(); } @Override public EventResponse process(TimerInput input) throws IntegrationExtensionException { Log.d(TAG, "Timer extension: " + input.interval + ", " + input.time); if (input.interval == 0 && input.time == 0) { // Cancel Log.d(TAG, "Removing subscription: " + input.getSubscription()); cancelRunAtTime(input.getSubscription()); return new EventResponse(0); } int subscription; try { subscription = getProvider().nextSubscription(); } catch (RemoteException e) { throw new IntegrationExtensionException( "Failed to create subscription"); } long time = input.time * 1000; if (0 == time) { time = System.currentTimeMillis() + input.interval * 1000; } runAtTime(time, input.interval * 1000, subscription); return new EventResponse(subscription); } public void onAlarm(Intent intent) { // When Alarm service call it int subscription = intent.getIntExtra("subscription", 0); long repeat = intent.getLongExtra("repeat", 0); Log.i(TAG, "Sending timer event back to vimtouch: " + subscription); sendEvent(subscription, new EventResponse(subscription)); if (repeat > 0) { runAtTime(System.currentTimeMillis() + repeat, repeat, subscription); } } }