/* * Copyright (C) 2012, Katy Hilgenberg * * This file is part of the SDCFramework (Sensor Data Collection Framework) project. * * The SDCFramework is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The SDCFramework is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the SDCFramework. If not, see <http://www.gnu.org/licenses/>. */ package de.unikassel.android.sdcframework.util; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import de.unikassel.android.sdcframework.util.facade.EventObserver; import de.unikassel.android.sdcframework.util.facade.LifeCycleObject; import de.unikassel.android.sdcframework.util.facade.ObservableEventSource; /** * An observable alarm. Use the {@link AlarmBuilder} class to create alarm * instances. * * @author Katy Hilgenberg * */ public class ObservableAlarm extends BroadcastReceiver implements ObservableEventSource< AlarmEvent >, LifeCycleObject { /** * The identifier key name */ private static final String ID = "id"; /** * The intent action */ private final String ACTION = "de.unikassel.android.sdcframework.util.AlarmEvent"; /** * The observable event source to delegate to */ private final ObservableEventSource< AlarmEvent > eventSource; /** * The alarm manager to wake up device */ private final AlarmManager alarmManager; /** * The context */ private final Context context; /** * The last pending intent */ private PendingIntent pendingIntent; /** * The unique action identifier. */ private final String action; /** * The unique alarm identifier. */ private final int id; /** * Constructor * * @param context * @param id * the unique alarm identifier */ public ObservableAlarm( Context context, int id ) { this.eventSource = new ObservableEventSourceImpl< AlarmEvent >(); this.context = context; this.alarmManager = (AlarmManager) context.getSystemService( Context.ALARM_SERVICE ); this.id = id; this.action = ACTION + id; } /** * Method to cancel the current alarm */ public synchronized void cancelAlarm() { if ( pendingIntent != null ) { alarmManager.cancel( pendingIntent ); Logger.getInstance().debug( this, String.format( "Alarm %d canceled", getId() ) ); } pendingIntent = null; } /** * Method to add an alarm * * @param timeOffset * the time offset in milliseconds */ public synchronized void setAlarm( long timeOffset ) { cancelAlarm(); Intent intent = new Intent( action ); intent.putExtra( ID, this.hashCode() ); pendingIntent = PendingIntent.getBroadcast( context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT ); long triggerAtTime = System.currentTimeMillis() + timeOffset; alarmManager.set( AlarmManager.RTC_WAKEUP, triggerAtTime, pendingIntent ); triggerAtTime -= TimeProvider.getInstance().getOffset(); Logger.getInstance().debug( this, String.format( "Alarm %d set to: %s", getId(), TimeProvider.toUTCString( triggerAtTime ) ) ); } /** * Getter for the id * @return the id */ public int getId() { return id; } /* * (non-Javadoc) * * @see android.content.BroadcastReceiver#onReceive(android.content.Context, * android.content.Intent) */ @Override public void onReceive( Context context, Intent intent ) { if ( action.equals( intent.getAction() ) ) { int hashCode = intent.getIntExtra( ID, -1 ); if ( hashCode == this.hashCode() ) { Logger.getInstance().debug( this, String.format( "Alarm %d event received!", getId() ) ); notify( new AlarmEvent( this ) ); } } } /* * (non-Javadoc) * * @see de.unikassel.android.sdcframework.util.facade.ObserverRegistration# * registerEventObserver * (de.unikassel.android.sdcframework.util.facade.EventObserver) */ @Override public synchronized void registerEventObserver( EventObserver< ? extends AlarmEvent > observer ) { eventSource.registerEventObserver( observer ); } /* * (non-Javadoc) * * @see de.unikassel.android.sdcframework.util.facade.ObserverRegistration# * unregisterEventObserver * (de.unikassel.android.sdcframework.util.facade.EventObserver) */ @Override public synchronized void unregisterEventObserver( EventObserver< ? extends AlarmEvent > observer ) { eventSource.unregisterEventObserver( observer ); } /* * (non-Javadoc) * * @see de.unikassel.android.sdcframework.util.facade.ObserverRegistration# * removeAllObservers() */ @Override public synchronized void removeAllObservers() { eventSource.removeAllObservers(); } /* * (non-Javadoc) * * @see * de.unikassel.android.sdcframework.util.facade.ObservableEventSource#notify * (de.unikassel.android.sdcframework.util.facade.ObservableEvent) */ @Override public void notify( AlarmEvent data ) { eventSource.notify( data ); } /* * (non-Javadoc) * * @see * de.unikassel.android.sdcframework.util.facade.LifeCycleObject#onResume( * android.content.Context) */ @Override public void onResume( Context applicationContext ) { context.registerReceiver( this, new IntentFilter( action ) ); } /* * (non-Javadoc) * * @see * de.unikassel.android.sdcframework.util.facade.LifeCycleObject#onPause(android * .content.Context) */ @Override public void onPause( Context applicationContext ) { cancelAlarm(); try { context.unregisterReceiver( this ); } catch ( IllegalArgumentException e ) {} } /* * (non-Javadoc) * * @see * de.unikassel.android.sdcframework.util.facade.LifeCycleObject#onCreate( * android.content.Context) */ @Override public void onCreate( Context applicationContext ) {} /* * (non-Javadoc) * * @see * de.unikassel.android.sdcframework.util.facade.LifeCycleObject#onDestroy * (android.content.Context) */ @Override public void onDestroy( Context applicationContext ) {} /* * (non-Javadoc) * * @see de.unikassel.android.sdcframework.util.facade.ObservableEventSource# * hasObservers() */ @Override public boolean hasObservers() { return eventSource.hasObservers(); } }