diff --git a/TravelPost/AndroidManifest.xml b/TravelPost/AndroidManifest.xml index 1a3538c..1bc5440 100644 --- a/TravelPost/AndroidManifest.xml +++ b/TravelPost/AndroidManifest.xml @@ -1,12 +1,36 @@ - + package="com.TwentyCodes.android.TravelPost" android:versionCode="0" android:versionName="0.0.0"> + - - + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TravelPost/gen/com/TwentyCodes/android/TravelPost/R.java b/TravelPost/gen/com/TwentyCodes/android/TravelPost/R.java index d1fac70..84f27f2 100644 --- a/TravelPost/gen/com/TwentyCodes/android/TravelPost/R.java +++ b/TravelPost/gen/com/TwentyCodes/android/TravelPost/R.java @@ -21,6 +21,7 @@ public final class R { public static final int hello=0x7f050000; } public static final class xml { - public static final int travelpostwidgetinfo=0x7f040000; + public static final int settings=0x7f040000; + public static final int travelpostwidgetinfo=0x7f040001; } } diff --git a/TravelPost/res/xml/settings.xml b/TravelPost/res/xml/settings.xml new file mode 100644 index 0000000..f32953d --- /dev/null +++ b/TravelPost/res/xml/settings.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/TravelPost/src/com/TwentyCodes/android/TravelPost/LocationReceiver.java b/TravelPost/src/com/TwentyCodes/android/TravelPost/LocationReceiver.java new file mode 100644 index 0000000..f6ecc4b --- /dev/null +++ b/TravelPost/src/com/TwentyCodes/android/TravelPost/LocationReceiver.java @@ -0,0 +1,71 @@ +/** + * LocationReceiver.java + * @date Jan 21, 2011 + * @author ricky barrette + * @author Twenty Codes, LLC + */ +package com.TwentyCodes.android.TravelPost; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.location.Location; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; + +/** + * The broadcast receiver that works with LocationService.java + * @author ricky barrette + */ +public class LocationReceiver extends BroadcastReceiver { + + public static final String ACTION_UPDATE = "TwentyCodes.TravelPost.intent.action.LocationUpdate"; + public static final String LOCATION_PARCEL = "location_parcel"; + private static final String TAG = "LocationReceiver"; + private WakeLock mWakeLock; + + /** + * acquires a wakelock to prevent the device's cpu from sleeping + * @param context + * @author ricky barrette + */ + private void acquireWakeLock(Context context) { + PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + mWakeLock.acquire(); + } + + /** + * called when this receiver receives a location update + * @param location + * @author ricky barrette + */ + private void onLocationUpdate(Location location) { + //TODO something with the location i.e. report location to social services like twitter, ect... + removeWakeLock(); + } + + /** + * Called when there is a location update from the location service. + * @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent) + * @author ricky barrette + */ + @Override + public void onReceive(Context context, Intent intent) { + acquireWakeLock(context); + if(intent.getParcelableExtra(LOCATION_PARCEL) != null){ + Location location = intent.getParcelableExtra(LOCATION_PARCEL); + onLocationUpdate(location); + } + } + + /** + * removes the wake lock if there is one held + * @author ricky barrette + */ + private void removeWakeLock() { + if(mWakeLock.isHeld()) + mWakeLock.release(); + } + +} diff --git a/TravelPost/src/com/TwentyCodes/android/TravelPost/LocationService.java b/TravelPost/src/com/TwentyCodes/android/TravelPost/LocationService.java new file mode 100644 index 0000000..9fd021f --- /dev/null +++ b/TravelPost/src/com/TwentyCodes/android/TravelPost/LocationService.java @@ -0,0 +1,227 @@ +/** + * LocationService.java + * @date Jan 21, 2011 + * @author ricky barrette + * @author Twenty Codes, LLC + */ +package com.TwentyCodes.android.TravelPost; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; +import android.util.Log; + +/** + * A service that will gather the user's location in the background, and report it via Broadcast once the location gathered has reached the + * @author ricky barrette + */ +public class LocationService extends Service implements LocationListener { + + /** + * The desired accuracy in meters + */ + private static final float DESIRED_ACCURACY = 6.0f; + + /** + * Maximum running time in milliseconds + */ + private final long MAX_RUN_TIME = 180000L; + public static final String TAG = "LocationService"; + private LocationManager mLocationManager; + private WakeLock mWakeLock; + private Location mLocation; + private int mStartId; + + /** + * this runnable will be qued when the service is created. this will be used as a fail safe + * @author ricky barrette + */ + private Runnable mFailSafe = new Runnable() { + @Override + public void run(){ + broadcastLocation(); + } + }; + + /** + * a convince method for starting the service + * @param context + * @return a runnable that will start the service + * @author ricky barrette + */ + public static Runnable startService(final Context context){ + return new Runnable(){ + @Override + public void run(){ + Intent service = new Intent(context, LocationService.class); + context.startService(service); + } + }; + } + + /** + * a convince method for stopping the service + * @param context + * @return a runnable that will stop the service + * @author ricky barrette + */ + public static Runnable stopService(final Context context){ + return new Runnable(){ + @Override + public void run(){ + context.stopService(new Intent(context, LocationService.class)); + } + }; + } + + /** + * broadcasts location to anything listening for updates, + * since this is the last function of the service, we call finish()u + * @author ricky barrette + */ + private void broadcastLocation() { + if (mLocation != null) { + Intent locationUpdate = new Intent(); + locationUpdate.setAction(LocationReceiver.ACTION_UPDATE); + locationUpdate.putExtra(LocationReceiver.LOCATION_PARCEL, mLocation); + sendBroadcast(locationUpdate); + stopSelf(mStartId); + } + } + + /** + * (non-Javadoc) + * @see android.app.Service#onBind(android.content.Intent) + * @param arg0 + * @return + * @author ricky barrette + */ + @Override + public IBinder onBind(Intent arg0) { + // UNUSED + return null; + } + + /** + * called when the service is created. this will initialize the location manager, and acquire a wakelock + * (non-Javadoc) + * @see android.app.Service#onCreate() + * @author ricky barrette + */ + @Override + public void onCreate(){ + mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + mWakeLock.acquire(); + + /* + * que the fail safe runnable to kill the report location and kill it self after the MAX_RUN_TIME has been meet + */ + new Handler().postDelayed(mFailSafe, MAX_RUN_TIME); + } + + /** + * called when the service is destroyed. + * this will remove any wakelock or location service running, and register to be waken back up + * (non-Javadoc) + * @see android.app.Service#onDestroy() + * @author ricky barrette + */ + @Override + public void onDestroy(){ + mLocationManager.removeUpdates(this); + if(mWakeLock.isHeld()) + mWakeLock.release(); + } + + /** + * (non-Javadoc) + * @see android.location.LocationListener#onLocationChanged(android.location.Location) + * @param location + * @author ricky barrette + */ + @Override + public void onLocationChanged(Location location) { +// Log.d(TAG, "got location +- "+ location.getAccuracy() +"m"); + mLocation = location; + if(location.getAccuracy() <= DESIRED_ACCURACY){ + broadcastLocation(); + } + } + + /** + * (non-Javadoc) + * @see android.location.LocationListener#onProviderDisabled(java.lang.String) + * @param arg0 + * @author ricky barrette + */ + @Override + public void onProviderDisabled(String arg0) { + // UNUSED + } + + /** + * (non-Javadoc) + * @see android.location.LocationListener#onProviderEnabled(java.lang.String) + * @param arg0 + * @author ricky barrette + */ + @Override + public void onProviderEnabled(String arg0) { + // UNUSED + } + + /** + * To keep backwards compatibility we override onStart which is the equivalent of onStartCommand in pre android 2.x + * @author ricky barrette + */ + @Override + public void onStart(Intent intent, int startId) { + Log.i(TAG, "onStart.Service started with start id of: " + startId); + mStartId = startId; + startLocationService(); + } + + /** + * This method is called when startService is called. only used in 2.x android. + * @author ricky barrette + */ + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.i(TAG , "onStartCommand.Service started with start id of: " + startId); + mStartId = startId; + startLocationService(); + return START_STICKY; + } + + + /** + * (non-Javadoc) + * @see android.location.LocationListener#onStatusChanged(java.lang.String, int, android.os.Bundle) + * @author ricky barrette + */ + @Override + public void onStatusChanged(String arg0, int arg1, Bundle arg2) { + // UNUSED + } + + /** + * request periodic location updates from androids location services + * @author ricky barrette + */ + private void startLocationService() { + mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); + mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this); + mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0, this); + } + +} diff --git a/TravelPost/src/com/TwentyCodes/android/TravelPost/PostMortemReportExceptionHandler.java b/TravelPost/src/com/TwentyCodes/android/TravelPost/PostMortemReportExceptionHandler.java index e1b8335..be15c1d 100644 --- a/TravelPost/src/com/TwentyCodes/android/TravelPost/PostMortemReportExceptionHandler.java +++ b/TravelPost/src/com/TwentyCodes/android/TravelPost/PostMortemReportExceptionHandler.java @@ -24,9 +24,13 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.os.Build; /** - * dont forget the manifest tag - * - * @author ricky + * The Twenty Codes, LLC Exception handler.
+ * This exception handler will generate an email with the stacktrace, cause, device & eviroment, and complete logcat

+ * to use create a field variable, and add the following lines to your onCreate() + * mExceptionReport.run(); + Thread.setDefaultUncaughtExceptionHandler(mExceptionReport);

+ * Don't forget the manifest tag android.permission.READ_LOGS + * @author ricky barette */ public class PostMortemReportExceptionHandler implements UncaughtExceptionHandler, Runnable { public static final String ExceptionReportFilename = "postmortem.trace"; diff --git a/TravelPost/src/com/TwentyCodes/android/TravelPost/TravelPost.java b/TravelPost/src/com/TwentyCodes/android/TravelPost/TravelPost.java index f674deb..3988959 100644 --- a/TravelPost/src/com/TwentyCodes/android/TravelPost/TravelPost.java +++ b/TravelPost/src/com/TwentyCodes/android/TravelPost/TravelPost.java @@ -1,5 +1,42 @@ +/** + * TravelPost.java + * @date Jan 21, 2011 + * @author ricky barrette + * @author Twenty Codes, LLC + */ package com.TwentyCodes.android.TravelPost; -public class TravelPost { +import android.os.Bundle; +import android.preference.PreferenceActivity; -} +/** + * Main activity for the Travel Post widget. + * This activity will be used to gather and store the users settings for the widget using shared_prefs + * @author ricky barrette + */ +public class TravelPost extends PreferenceActivity { + + private PostMortemReportExceptionHandler mExceptionReport = new PostMortemReportExceptionHandler(this); + private static final String SETTINGS = "settings"; + + /** + * called when the activity is first created + * (non-Javadoc) + * @see android.preference.PreferenceActivity#onCreate(android.os.Bundle) + * @author ricky barrette + */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + //start the exception handler + mExceptionReport.run(); + Thread.setDefaultUncaughtExceptionHandler(mExceptionReport); + + // set shared_prefs name + getPreferenceManager().setSharedPreferencesName(SETTINGS); + + // load preferences xml + this.addPreferencesFromResource(R.xml.settings); + } + +} \ No newline at end of file