diff --git a/DroidFinder/.classpath b/DroidFinder/.classpath index a7552ca..b8dae0a 100644 --- a/DroidFinder/.classpath +++ b/DroidFinder/.classpath @@ -3,5 +3,7 @@ + + diff --git a/DroidFinder/AndroidManifest.xml b/DroidFinder/AndroidManifest.xml index ed674fe..1f02307 100644 --- a/DroidFinder/AndroidManifest.xml +++ b/DroidFinder/AndroidManifest.xml @@ -1,43 +1,50 @@ - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + - - - - - - + + - - - - - - - + + + - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/DroidFinder/assets/exceptionhandler.properties b/DroidFinder/assets/exceptionhandler.properties new file mode 100644 index 0000000..9f1c60a --- /dev/null +++ b/DroidFinder/assets/exceptionhandler.properties @@ -0,0 +1,22 @@ +# exceptionhandler.properties +# @author ricky barrette +# @author twenty codes + +# This file is used to tell the Exception Handler LIbrary how to file +# new exception reports +# HTTP ONLY +# +# Place this file in you project's assets folder and edit as needed +# +# server is the physical web address for your server +# file is the path to your filing script +# get is the path to your json retrieval script +# app is the redmine project name +# tracker is the redmine tracker +server = http://rickbarrette.dyndns.org:8080/redmine/exceptionhandler +app = test +tracker = Development Bug + +# uncomment the following if you want your application to use email to file reports. +# if this is uncommented, email will always be used. +#email = twentycodes@gmail.com \ No newline at end of file diff --git a/DroidFinder/project.properties b/DroidFinder/project.properties index 9aa0dfa..ed7c222 100644 --- a/DroidFinder/project.properties +++ b/DroidFinder/project.properties @@ -9,3 +9,5 @@ # Project target. target=Google Inc.:Google APIs:15 +android.library.reference.1=../../exception_handler_library/ExceptionHandlerLib +android.library.reference.2=../../location_library/LocationLib diff --git a/DroidFinder/res/layout/tabs.xml b/DroidFinder/res/layout/tabs.xml index 1d0e21b..3999bde 100644 --- a/DroidFinder/res/layout/tabs.xml +++ b/DroidFinder/res/layout/tabs.xml @@ -2,20 +2,30 @@ + android:layout_height="fill_parent" > + + android:orientation="vertical" + android:padding="5dp" > + + + android:padding="5dp" > + + + + \ No newline at end of file diff --git a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/DroidFinder.java b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/DroidFinder.java index 8c4c1de..6052330 100644 --- a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/DroidFinder.java +++ b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/DroidFinder.java @@ -1,11 +1,13 @@ package com.TwentyCodes.android.DroidFinderFull; -import android.app.TabActivity; -import android.content.Intent; import android.os.Bundle; -import android.util.Log; +import android.support.v4.app.FragmentActivity; +import android.support.v4.view.ViewPager; import android.widget.TabHost; +import com.TwentyCodes.android.exception.ExceptionHandler; +import com.TwentyCodes.android.location.UserOverlayMapFragment; + /** * this is the main class for the application, it is responsible for displaying the main tab layout that will display the map and the settings * pages. @@ -14,40 +16,38 @@ import android.widget.TabHost; * dim the phones display to minimum, and/or ring for a preset period of time based on a designated string received by SMS * @author ricky barrette */ -public class DroidFinder extends TabActivity{ - - private PostMortemReportExceptionHandler mExceptionReport = new PostMortemReportExceptionHandler(this);; +public class DroidFinder extends FragmentActivity{ + private TabHost mTabHost; + private ViewPager mViewPager; + private TabsAdapter mTabsAdapter; + /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { - mExceptionReport.run(); - Thread.setDefaultUncaughtExceptionHandler(mExceptionReport); - + Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this)); + super.onCreate(savedInstanceState); setContentView(R.layout.tabs); - TabHost tabHost = getTabHost(); // The activity TabHost - TabHost.TabSpec spec; // Resusable TabSpec for each tab - Intent intent; // Reusable Intent for each tab + mTabHost = (TabHost)findViewById(android.R.id.tabhost); + mTabHost.setup(); - // Create an Intent to launch an Activity for the tab (to be reused) - intent = new Intent().setClass(this, MyMapActivity.class); + mViewPager = (ViewPager)findViewById(R.id.pager); -// Initialize a TabSpec for each tab and add it to the TabHost - spec = tabHost.newTabSpec("map").setIndicator("Map").setContent(intent); -// res.getDrawable(R.drawable.ic_tab_artists)) - tabHost.addTab(spec); + mTabsAdapter = new TabsAdapter(this, mTabHost, mViewPager); + + mTabsAdapter.addTab(mTabHost.newTabSpec("map").setIndicator("Map"), UserOverlayMapFragment.class, null); +// mTabsAdapter.addTab(mTabHost.newTabSpec("settings").setIndicator("Settings"), SettingsFragment.class, null); - intent = new Intent().setClass(this, SettingsActivity.class); - spec = tabHost.newTabSpec("settings").setIndicator("Settings").setContent(intent); - tabHost.addTab(spec); + if (savedInstanceState != null) { + mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); + } } - + @Override - public void onPause(){ - MyMapActivity.mMyLocationOverlay.disableCompass(); - MyMapActivity.mMyLocationOverlay.disableMyLocation(); - super.onPause(); + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString("tab", mTabHost.getCurrentTabTag()); } } \ No newline at end of file diff --git a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/GeoUtils.java b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/GeoUtils.java deleted file mode 100644 index 9bd18f2..0000000 --- a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/GeoUtils.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2008 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Twenty Codes - * @author ricky barrette - * @author Google Inc. - */ -package com.TwentyCodes.android.DroidFinderFull; - -import java.util.ArrayList; -import java.util.List; - -import android.graphics.Point; - -import com.google.android.maps.GeoPoint; - -/** - * This class contains common tools for computing common geological problems - * @author ricky barrette - * @author Google Inc. - */ -public class GeoUtils { - - private static int EARTH_RADIUS_KM = 6371; - public static double MILLION = 1000000; - - public static int minLatitude; - public static int maxLatitude; - public static int minLongitude; - public static int maxLongitude; - - /** - * computes the bearing of lat2/lon2 in relationship from lat1/lon1 in degrees East - * @param lat1 source lat - * @param lon1 source lon - * @param lat2 destination lat - * @param lon2 destination lon - * @return the bearing of lat2/lon2 in relationship from lat1/lon1 in degrees East - * @author Google Inc. - */ - public static double bearing(double lat1, double lon1, double lat2, double lon2) { - double lat1Rad = Math.toRadians(lat1); - double lat2Rad = Math.toRadians(lat2); - double deltaLonRad = Math.toRadians(lon2 - lon1); - - double y = Math.sin(deltaLonRad) * Math.cos(lat2Rad); - double x = Math.cos(lat1Rad) * Math.sin(lat2Rad) - Math.sin(lat1Rad) * Math.cos(lat2Rad) - * Math.cos(deltaLonRad); - return radToBearing(Math.atan2(y, x)); - } - - /** - * computes the bearing of lat2/lon2 in relationship from lat1/lon1 in degrees East - * @param p1 source geopoint - * @param p2 destination geopoint - * @return the bearing of p2 in relationship from p1 in degrees East - * @author Google Inc. - */ - public static double bearing(GeoPoint p1, GeoPoint p2) { - double lat1 = p1.getLatitudeE6() / MILLION; - double lon1 = p1.getLongitudeE6() / MILLION; - double lat2 = p2.getLatitudeE6() / MILLION; - double lon2 = p2.getLongitudeE6() / MILLION; - - return bearing(lat1, lon1, lat2, lon2); - } - - /** - * Calculates a geopoint x meters away of the geopoint supplied. The new geopoint - * shares the same latitude as geopoint point, this way they are on the same latitude arc. - * - * @param point central geopoint - * @param distance in meters from the geopoint - * @return geopoint that is x meters away from the geopoint supplied - * @author ricky barrette - */ - public static GeoPoint distanceFrom(GeoPoint point, double distance){ - //convert meters into kilometers - distance = distance / 1000; - - // convert lat and lon of geopoint to radians - double lat1Rad = Math.toRadians((point.getLatitudeE6() / 1e6)); - double lon1Rad = Math.toRadians((point.getLongitudeE6() / 1e6)); -// double lat2Rad = lat1Rad; - - /* - * kilometers = acos(sin(lat1Rad)sin(lat2Rad)+cos(lat1Rad)cos(lat2Rad)cos(lon2Rad-lon1Rad)6371 - * - * we are solving this equation for lon2Rad - * - * lon2Rad = lon1Rad+acos(cos(meters/6371)sec(lat1Rad)sec(lat2Rad)-tan(lat1Rad)tan(lat2Rad)) - * - * NOTE: sec(x) = 1/cos(x) - * - * NOTE: that lat2Rad is = lat1Rad because we want to keep the new geopoint on the same lat arc - * therefore i saw no need to create a new variable for lat2Rad, - * and simply inputed lat1Rad in place of lat2Rad in the equation - * - * NOTE: this equation has be tested in the field against another gps device, and the distanceKm() from google - * and has been proven to be damn close - */ - double lon2Rad = lon1Rad + Math.acos( Math.cos((distance/6371)) * (1 / Math.cos(lat1Rad)) - * (1 / Math.cos(lat1Rad)) - Math.tan(lat1Rad) * Math.tan(lat1Rad)); - - /* - * test... this equation is curtisy of Raytheon - * - * KM / 6371*cos(lat1Rad - lat2Rad) + lon1Rad = lon2Rad - * - * NOTE: i ricky, don't think that is is very accurate at all - */ -// double lon2Rad = distance / ( 6371 * Math.cos( (lat1Rad - lat1Rad) ) + lon1Rad); - -// Log.d(tag,"lon2Rad = "+ lon2Rad); -// Log.d(tag,"lon2Deg = "+ Math.toDegrees(lon2Rad)); -// -// Log.d(tag,"distance between the 2 = "+ -// distanceKm(point.getLatitudeE6() / 1e6, point.getLongitudeE6() / 1e6, -// point.getLatitudeE6() / 1e6, Math.toDegrees(lon2Rad))); - - //return a geopoint that is x meters away from the geopoint supplied - return new GeoPoint(point.getLatitudeE6(), (int) (Math.toDegrees(lon2Rad) * 1e6)); - } - - /** - * computes the distance between to lat1/lon1 and lat2/lon2 based on the curve of the earth - * @param lat1 source lat - * @param lon1 source lon - * @param lat2 destination lat - * @param lon2 destination lon - * @return the distance between to lat1/lon1 and lat2/lon2 - * @author Google Inc. - */ - public static double distanceKm(double lat1, double lon1, double lat2, double lon2) { - double lat1Rad = Math.toRadians(lat1); - double lat2Rad = Math.toRadians(lat2); - double deltaLonRad = Math.toRadians(lon2 - lon1); - - return Math.acos(Math.sin(lat1Rad) * Math.sin(lat2Rad) + Math.cos(lat1Rad) * Math.cos(lat2Rad) - * Math.cos(deltaLonRad)) - * EARTH_RADIUS_KM; - } - - /** - * computes the distance between to p1 and p2 based on the curve of the earth - * @param p1 - * @param p2 - * @return the distance between to p1 and p2 - * @author Google Inc. - */ - public static double distanceKm(GeoPoint p1, GeoPoint p2) { - double lat1 = p1.getLatitudeE6() / MILLION; - double lon1 = p1.getLongitudeE6() / MILLION; - double lat2 = p2.getLatitudeE6() / MILLION; - double lon2 = p2.getLongitudeE6() / MILLION; - - return distanceKm(lat1, lon1, lat2, lon2); - } - - /** - * computes a geopoint the is the central geopoint between p1 and p1 - * @param p1 first geopoint - * @param p2 second geopoint - * @return the central geopoint - * @author ricky barrette - */ - public static GeoPoint midPoint(GeoPoint p1, GeoPoint p2) { - minLatitude = (int)(+81 * 1E6); - maxLatitude = (int)(-81 * 1E6); - minLongitude = (int)(+181 * 1E6); - maxLongitude = (int)(-181 * 1E6); - List mPoints = new ArrayList(); - int latitude = p1.getLatitudeE6(); - int longitude = p1.getLongitudeE6(); - if (latitude != 0 && longitude !=0) { - minLatitude = (minLatitude > latitude) ? latitude : minLatitude; - maxLatitude = (maxLatitude < latitude) ? latitude : maxLatitude; - minLongitude = (minLongitude > longitude) ? longitude : minLongitude; - maxLongitude = (maxLongitude < longitude) ? longitude : maxLongitude; - mPoints.add(new Point(latitude, longitude)); - } - - latitude = p2.getLatitudeE6(); - longitude = p2.getLongitudeE6(); - if (latitude != 0 && longitude !=0) { - minLatitude = (minLatitude > latitude) ? latitude : minLatitude; - maxLatitude = (maxLatitude < latitude) ? latitude : maxLatitude; - minLongitude = (minLongitude > longitude) ? longitude : minLongitude; - maxLongitude = (maxLongitude < longitude) ? longitude : maxLongitude; - mPoints.add(new Point(latitude, longitude)); - } - System.gc(); - return new GeoPoint((maxLatitude + minLatitude)/2, (maxLongitude + minLongitude)/2 ); - } - - /** - * converts radians to bearing - * @param rad - * @return bearing - * @author Google Inc. - */ - public static double radToBearing(double rad) { - return (Math.toDegrees(rad) + 360) % 360; - } -} \ No newline at end of file diff --git a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/MyCustomLocationOverlay.java b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/MyCustomLocationOverlay.java deleted file mode 100644 index 4c42cc8..0000000 --- a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/MyCustomLocationOverlay.java +++ /dev/null @@ -1,333 +0,0 @@ -/** -* @author Twenty Codes -* @author ricky barrette -*/ - -/** - * - */ -package com.TwentyCodes.android.DroidFinderFull; - -import java.text.DecimalFormat; - -import android.app.Activity; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.SharedPreferences; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Point; -import android.graphics.Paint.Style; -import android.location.Location; -import android.location.LocationProvider; -import android.os.Bundle; -import android.util.Log; -import android.widget.TextView; - -import com.google.android.maps.GeoPoint; -import com.google.android.maps.MapView; -import com.google.android.maps.Projection; - -/** - * @author ricky barrette - */ -public class MyCustomLocationOverlay extends com.google.android.maps.MyLocationOverlay { - - protected static boolean blUnit; - protected static GeoPoint gpCar, gpUser; - private static Context mContext; - protected static TextView tvDistance; - private MapView mMapView; - private TextView tvAccuracy; - private SharedPreferences settings; - private ProgressDialog mGPSprogress; - protected static final String STAY_AWAKE = "stay_awake"; - protected static final String MEASUREMENT_UNIT = "measurement_unit"; - protected static final String LAYERS = "layers"; - - /** - * an overlay class that displays the compass of what you want really badly - * AKA your car and a user arrow that points north on the map that automatically updates - * also initializes the textviews used to update user about the location status - * @param context - context to work in - * @param mapView - mapView to post overlay to - * @author ricky barrette - */ - protected MyCustomLocationOverlay(Context context, MapView mapView) { - super(context, mapView); - mContext = context; - tvDistance = (TextView) ((Activity) context).findViewById(R.id.tvDistance2); - tvAccuracy = (TextView) ((Activity) context).findViewById(R.id.tvAccuracy2); - settings = context.getSharedPreferences(SettingsActivity.SETTINGS, 0); - blUnit = settings.getBoolean(MEASUREMENT_UNIT, false); - } - - /** - * setter method for car values. sets geopoint, and location of user respective to car values - * @param car - lat and lon of car - * @author ricky - */ - protected static void setCar(GeoPoint car) { - gpCar = car; - } - - /** - * sets the measurement unit of the distance text field at the top of the activity - * @param unit - true is metric, false is standard - */ - protected static void setUnit(boolean unit) { - blUnit = unit; - Log.i(mContext.getClass().getName(),"unit = "+unit); - } - - /** - * returns a string distance that is based on the users measurement unit preference - * @param distance in kilometers - * @return string distance - * @author ricky barrette - */ - private String distance(double distance) { - DecimalFormat threeDForm = new DecimalFormat("#.###"); - DecimalFormat twoDForm = new DecimalFormat("#.##"); - - /* - * if blnUnit is true, the distance computed will be in metric units, - * else, standard units are used - * meters are used until 1 kilometer is reached, then kilometers are used - * feet are used until 1 mile is reached, then miles are used - */ - if(blUnit){ - if (distance < 1){ - distance = distance * 1000; - return twoDForm.format(distance) +" m"; - } - return threeDForm.format(distance) +" Km"; - } - distance = distance / 1.609344; - if (distance < 1){ - distance = distance * 5280; - return twoDForm.format(distance) +" ft"; - } - return twoDForm.format(distance) +" mi"; - } - - /** - * computes bearing to geopoint based on device oriantaion and draws the compass of what you want really really badly on screen - * @param - canvas - the canvas to draw on - * @param - bearing - bearing of user based on magnetic compass - * @author ricky barrette - */ - @Override - protected void drawCompass(Canvas canvas, float bearing){ - /* - * we moved drawUser() call from drawMyLocation() to here to so draw user - * is updated more often to smooth out the rotation of the arrow in relationship with compass - * @author ricky barrette - * - * we found that the user arrow would only be re-drawn if the map was animating, or if the user was scrolling it, - * so we call mMapView.invalidate() to force the map to be re-dawn, including it's overlays - * @author ricky barrette - * - * if the MapView is not null, then draw the user arrow - */ - if (mMapView != null) { - drawUser(canvas, mMapView, bearing); - mMapView.invalidate(); - } - - /* - * if the car and user geopoint are not null, then draw the compass point to the car geopoint - * - * else draw the compass to point north - */ - if (gpCar != null && gpUser != null){ - Double d = GeoUtils.bearing(gpUser, gpCar); - bearing = bearing - d.floatValue(); - } else if (bearing != 0){ - bearing = 360 - bearing; - } - super.drawCompass(canvas, bearing); - } - - /** - * updates location stats, and the accuracy circle. also saves data needed to draw the user arrow - * @author ricky barrette - * @param - canvas - the canvas to draw on - * @param - mapView - the map which to draw the layout - * @param - lastFix - location object of last fix of gps location - * @param - myLocation - current location of user - * @param - when - Ricky is unsure of this value. please kick him in the balls - */ - @Override - protected void drawMyLocation(Canvas canvas, MapView mapView, Location lastFix, GeoPoint myLocation, long when) { - gpUser = myLocation; - mMapView = mapView; - - tvAccuracy.setText( distance( (lastFix.getAccuracy() / 1000) ) ); - drawAccuracyCircle(myLocation, lastFix, canvas, mapView); - - if (gpCar != null && gpUser != null){ - double distance = GeoUtils.distanceKm(gpUser, gpCar); - //value is set in KM. if user has gone 30 feet from car app is set to check for arrival - if (distance > 0.009144){ -// blnHasLeftCar = true; - } -// //if user has gone back into 30 foot radius and has not found the car and has left the car then notify user of finding of car -// if (distance <= 0.009144 && blnIsCarFound == false && blnHasLeftCar == true){ -// blnIsCarFound = true; -// Vibrator vib = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); -// AlertDialog.Builder builder = new AlertDialog.Builder(mContext); -// builder.setTitle(mContext.getText(R.string.yay)); -// builder.setMessage(mContext.getText(R.string.found_car)).setCancelable(false) -// .setPositiveButton(mContext.getText(R.string.ok), new DialogInterface.OnClickListener() { -// public void onClick(DialogInterface dialog, int id) { -// -// } -// }); -// vib.vibrate(100); -// builder.show(); -// } - - tvDistance.setText(distance(distance)); - } else { - tvDistance.setText("0"); - } - - } - - /** - * draws an accuracy circle based on current location and lastFix onto the canvas supplied - * @param myLocation - current location of user - * @param lastFix - last gps fix of user - * @param canvas - canvas to draw on - * @param mapView the mapview to draw an overlay for - * @author ricky barrette - */ - private void drawAccuracyCircle(GeoPoint myLocation, Location lastFix, Canvas canvas, MapView mapView) { - Paint paint = new Paint(); - Point center = new Point(); - Point left = new Point(); - Projection projection = mapView.getProjection(); - - /* - * Calculate a geopoint that is "radius" meters away from geopoint point - */ - GeoPoint leftGeo = GeoUtils.distanceFrom(myLocation, lastFix.getAccuracy()); - - /* - * Original method - * - double latitude = lastFix.getLatitude(); - double longitude = lastFix.getLongitude(); - float accuracy = lastFix.getAccuracy(); - - float[] result = new float[1]; - - Location.distanceBetween(latitude, longitude, latitude, longitude + 1, result); - float longitudeLineDistance = result[0]; - - GeoPoint leftGeo = new GeoPoint((int)(latitude * 1e6), (int)((longitude - accuracy / longitudeLineDistance) * 1e6)); - */ - - /* - * Convert the given GeoPoint and leftGeo to onscreen pixel coordinates, - * relative to the top-left of the MapView that provided this Projection. - */ - projection.toPixels(leftGeo, left); - projection.toPixels(myLocation, center); - - /* - * get radius of the circle being drawn by - */ - int circleRadius = center.x - left.x; - if(circleRadius <= 0){ - circleRadius = left.x - center.x; - } - - /* - * paint a blue circle on the map - */ - paint.setAntiAlias(true); - paint.setStrokeWidth(2.0f); - paint.setColor(Color.BLUE); - paint.setStyle(Style.STROKE); - canvas.drawCircle(center.x, center.y, circleRadius, paint); - - /* - * draw a dot over the geopoint - * not really need with this as the user arrow will be the center of the circle - */ -// RectF oval = new RectF(center.x - 1, center.y - 1, center.x + 1, center.y + 1); -// canvas.drawOval(oval, paint); - - /* - * fill the radius with a alpha blue - */ - paint.setAlpha(30); - paint.setStyle(Style.FILL); - canvas.drawCircle(center.x, center.y, circleRadius, paint); - } - - /** - * draws user arrow that points north based on device oriantataion onto the supplied canvas - * @param Canvas - canvas to draw on - * @param mapView the mapview to draw an overlay for - * @param bearing of then compass in degrees East - * @author ricky barrette - */ - private void drawUser(Canvas canvas, MapView mapView, float bearing){ - Point screenPts = mapView.getProjection().toPixels(gpUser, null); - - Bitmap arrowBitmap = BitmapFactory.decodeResource( mContext.getResources(), R.drawable.user); - Matrix matrix = new Matrix(); - matrix.postRotate(bearing); - Bitmap rotatedBmp = Bitmap.createBitmap( - arrowBitmap, - 0, 0, - arrowBitmap.getWidth(), - arrowBitmap.getHeight(), - matrix, - true - ); - - canvas.drawBitmap( - rotatedBmp, - screenPts.x - (rotatedBmp.getWidth() / 2), - screenPts.y - (rotatedBmp.getHeight() / 2), - null - ); - } - - /** - * Called when location provider status is changed. - * this method will be used to display a GPS progress dialog - * when the provider is unavailable, and dismisses the progress dialog is available - * @param provider name of the provider who's status has changed - * @param status of the provider - * @param extras - * @author ricky barrette - */ - @Override - public void onStatusChanged(String provider, int status, Bundle extras) { - switch(status){ - case LocationProvider.AVAILABLE: - mGPSprogress.dismiss(); - break; - - case LocationProvider.OUT_OF_SERVICE: - mGPSprogress = ProgressDialog.show(mContext, "", "Acquiring GPS Fix", true); - mGPSprogress.setCancelable(true); - break; - - case LocationProvider.TEMPORARILY_UNAVAILABLE: - mGPSprogress = ProgressDialog.show(mContext, "", "Acquiring GPS Fix", true); - mGPSprogress.setCancelable(true); - break; - } - } - -} diff --git a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/MyMapActivity.java b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/MyMapActivity.java deleted file mode 100644 index 400dd5a..0000000 --- a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/MyMapActivity.java +++ /dev/null @@ -1,240 +0,0 @@ -/** -* @author Twenty Codes -* @author ricky barrette -*/ - -package com.TwentyCodes.android.DroidFinderFull; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.location.LocationManager; -import android.os.Bundle; -import android.util.Log; -import android.widget.Toast; - -import com.google.android.maps.GeoPoint; -import com.google.android.maps.MapActivity; -import com.google.android.maps.MapController; -import com.google.android.maps.MapView; - -/** - * this class handles the map and map functions - * @author ricky barrette - */ -public class MyMapActivity extends MapActivity { - - private MapController mMapController; - public static MyCustomLocationOverlay mMyLocationOverlay; - private MapView mMapView; -// protected PowerManager.WakeLock mWakeLock; -// private List mMapOverlays; - private final String tag = "DroidFinder - MyMapActivity"; - - /** - * displays a dialog to inform that the gps is disabled and provides them with a shortcut to the settings page - * if they select no, then finish() is called. - * @author ricky barrette - */ - private void enableGPSdialog() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage("GPS is disbaled, Do You Want To Enable it?").setCancelable(false) - .setPositiveButton("Yes", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - Intent callGPSSettingIntent = new Intent( android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS); - startActivity(callGPSSettingIntent); - dialog.cancel(); - } - }) - .setNegativeButton("No", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - finish(); - dialog.cancel(); - } - }); - builder.show(); - } - - /** - * initializes the mapview, it's controller, zoom controls - * @author ricky barrette 3-31-2010 - */ - private void initMap() { - mMapView = (MapView) findViewById(R.id.mapview); - mMapView.setBuiltInZoomControls(true); - mMapController = mMapView.getController(); -// mMapOverlays = mMapView.getOverlays(); - - /* - * add MyCustomLocationOverlay to the map and enable the user icon and the compass - */ - mMyLocationOverlay = new MyCustomLocationOverlay(this, mMapView); - mMapView.getOverlays().add(mMyLocationOverlay); - - /* - * on first fix - * remove the GPS progress dialog, animate map the the users location, - * and then zoom in to zoom level 20 - */ -// mMyLocationOverlay.runOnFirstFix(new Runnable() { -// public void run() { -//// mGPSprogress.dismiss(); -// GeoPoint gpUser = null; -// //try to pan to initial user location, if you fail try, try, try again -// do{ -// gpUser = mMyLocationOverlay.getMyLocation(); -// } while(! panToGeoPoint(gpUser, true)); -// } -// }); - - } - - /** - * loads saved settings from files - * @author ricky barrette - */ - private void loadSettings(){ - //TODO load setting from shared_prefs - } - - @Override - protected void onCreate (Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.map); - initMap(); - - // if the location manager services are not available, then ask user if they want to enable it - if ((LocationManager) getSystemService(Context.LOCATION_SERVICE) == null) - enableGPSdialog(); - } - - @Override - protected void onDestroy() { - mMapController = null; - mMyLocationOverlay = null; - mMapView = null; - System.gc(); - super.onDestroy(); - } - - /** - * pans maps to where the a geopoint is, and if zoomIn is true, zooms in to level 20 - * @param GeoPoint point - lat and lon of point to pan to - * @param boolean zoomIn - true if map needs to be zoomed in - * @return boolean true if panning was successful - * @author ricky barrette - */ - private boolean panToGeoPoint(GeoPoint point, boolean zoomIn) { - if (point != null) { - Log.e(tag,"panToGeoPoint() point was null"); - return false; - } - if (mMapController != null){ - Log.e(tag,"panToGeoPoint() mapControler was null"); - return false; - } - - try { - /** - * We have found that if the map is animating and is then told to animate again it will crash. - * the stopAnimation call should prevent this - */ - mMapController.stopAnimation(false); - mMapController.animateTo(point); - - if(zoomIn){ - mMapController.setZoom(20); - } - } catch (NullPointerException e) { - Log.e(tag,"panToGeoPoint() Nullpointer exceptoin"); - e.printStackTrace(); - return false; - } - - return true; - } - - /** - * displays a quit dialog - * @since 0.0.2 - * @author ricky barrette 3-30-2010 - */ - public void quitDialog(){ - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage("Are you sure you want to quit").setCancelable(false) - .setPositiveButton("Yes", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - finish(); - } - }) - .setNegativeButton("No", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); - builder.show(); - } - - /** - * computes a geopoint the is the central geopoint between the user and the car. - * also it zooms so both marks are visible on the map - * @author ricky barrette - */ - private void showBoth(){ - panToGeoPoint(GeoUtils.midPoint(MyCustomLocationOverlay.gpCar, MyCustomLocationOverlay.gpUser), false); - mMapController.stopAnimation(true); - mMapController.zoomToSpan((GeoUtils.maxLatitude - GeoUtils.minLatitude), (GeoUtils.maxLongitude - GeoUtils.minLongitude)); - } - - /** - * displays toast message with a long duration - * @param msg - * @author ricky barrette - */ - public void toastLong(CharSequence msg) { - Toast toast = Toast.makeText(this, msg, Toast.LENGTH_LONG); - toast.show(); - } - - /** - * displays toast message with a short duration - * @since 0.0.3 - * @param msg - * @author ricky barrette 3-31-2010 - */ - public void toastShort(CharSequence msg) { - Toast toast = Toast.makeText(this, msg, Toast.LENGTH_SHORT); - toast.show(); - } - - /** - * when called this will prevent the screen from sleeping (turning off) - * call this.mWakeLock.release(); to allow screen to sleep again - * @author ricky barrette - * @since 0.0.9 - */ -// private void wakeLock(){ -// if(!mWakeLock.isHeld()){ -// mWakeLock.acquire(); -// } - - @Override - protected boolean isRouteDisplayed() { - return false; - } - - @Override - protected void onPause(){ - mMyLocationOverlay.disableCompass(); - mMyLocationOverlay.disableMyLocation(); - super.onPause(); - } - - @Override - protected void onResume(){ - mMyLocationOverlay.enableCompass(); - mMyLocationOverlay.enableMyLocation(); - super.onResume(); - } -} \ No newline at end of file diff --git a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/PostMortemReportExceptionHandler.java b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/PostMortemReportExceptionHandler.java deleted file mode 100644 index 75d19da..0000000 --- a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/PostMortemReportExceptionHandler.java +++ /dev/null @@ -1,211 +0,0 @@ -package com.TwentyCodes.android.DroidFinderFull; - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.lang.Thread.UncaughtExceptionHandler; -import java.lang.reflect.Field; -import java.text.SimpleDateFormat; -import java.util.Date; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Build; - -/** - * dont forget the manifest tag - * - * @author ricky - */ -public class PostMortemReportExceptionHandler implements UncaughtExceptionHandler, Runnable { - public static final String ExceptionReportFilename = "postmortem.trace"; - - private static final String MSG_SUBJECT_TAG = "Exception Report"; //"app title + this tag" = email subject - private static final String MSG_SENDTO = "twentycodes@gmail.com"; //email will be sent to this account - //the following may be something you wish to consider localizing - private static final String MSG_BODY = "Just click send to help make this application better. "+ - "No personal information is being sent (you can check by reading the rest of the email)."; - - private Thread.UncaughtExceptionHandler mDefaultUEH; - private Activity mApp = null; - - public PostMortemReportExceptionHandler(Activity aApp) { - mDefaultUEH = Thread.getDefaultUncaughtExceptionHandler(); - mApp = aApp; - } - - public String getDebugReport(Throwable aException) { - -// NumberFormat theFormatter = new DecimalFormat("#0."); - //stack trace - StackTraceElement[] theStackTrace = aException.getStackTrace(); - - StringBuffer report = new StringBuffer(); - - report.append("--------- Application ---------\n\n"); - - report.append(mApp.getPackageName()+" generated the following exception:\n\n"); - - report.append(aException.toString() + "\n\n"); - - report.append("-------------------------------\n\n"); - - report.append("--------- Stack trace ---------\n\n"); - for (int i = 0; i < theStackTrace.length; i++) { - report.append(" " + theStackTrace[i].toString() + "\n"); - } - report.append("-------------------------------\n\n"); - - //app environment - PackageManager pm = mApp.getPackageManager(); - PackageInfo pi; - try { - pi = pm.getPackageInfo(mApp.getPackageName(), 0); - } catch (NameNotFoundException eNnf) { - //doubt this will ever run since we want info about our own package - pi = new PackageInfo(); - pi.versionName = "unknown"; - pi.versionCode = 69; - } - - Date theDate = new Date(); - SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss_zzz"); - report.append("-------- Environment --------\n"); - report.append("Time\t="+sdf.format(theDate)+"\n"); - report.append("Device\t="+Build.FINGERPRINT+"\n"); - try { - Field theMfrField = Build.class.getField("MANUFACTURER"); - report.append("Make\t="+theMfrField.get(null)+"\n"); - } catch (SecurityException e) { - } catch (NoSuchFieldException e) { - } catch (IllegalArgumentException e) { - } catch (IllegalAccessException e) { - } - report.append("Device: " + Build.DEVICE + "\n"); - report.append("Brand: " + Build.BRAND + "\n"); - report.append("Model: "+Build.MODEL+"\n"); - report.append("Product: "+Build.PRODUCT+"\n"); - report.append("App:\t "+mApp.getPackageName()+", version "+pi.versionName+" (build "+pi.versionCode+")\n"); - report.append("Locale: "+mApp.getResources().getConfiguration().locale.getDisplayName()+"\n"); - report.append("-----------------------------\n\n"); - - report.append("--------- Firmware ---------\n\n"); - report.append("SDK: " + Build.VERSION.SDK + "\n"); - report.append("Release: " + Build.VERSION.RELEASE + "\n"); - report.append("Incremental: " + Build.VERSION.INCREMENTAL + "\n"); - report.append("Build Id: " + Build.ID + "\n"); - report.append("-------------------------------\n\n"); - - // If the exception was thrown in a background thread inside - // AsyncTask, then the actual exception can be found with getCause - report.append("--------- Cause ---------\n\n"); - Throwable cause = aException.getCause(); - if (cause != null) { - report.append(cause.toString() + "\n\n"); - theStackTrace = cause.getStackTrace(); - for (int i = 0; i < theStackTrace.length; i++) { - report.append(" " + theStackTrace[i].toString() + "\n"); - } - } - report.append("-------------------------------\n\n"); - - report.append("--------- Complete Logcat ---------\n\n"); - report.append(getLog().toString()); - report.append("-------------------------------\n\n"); - - report.append("END REPORT"); - - return report.toString(); - } - - protected StringBuilder getLog(){ - final StringBuilder log = new StringBuilder(); - try{ - Process process = Runtime.getRuntime().exec("logcat -d"); - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); - - String line; - while ((line = bufferedReader.readLine()) != null){ - log.append(line); - log.append("\n"); - } - } - catch (IOException e){ - } - return log; - } - - public void run() { - sendDebugReportToAuthor(); - } - - protected void saveDebugReport(String aReport) { - //save report to file - try { - FileOutputStream theFile = mApp.openFileOutput(ExceptionReportFilename, Context.MODE_PRIVATE); - theFile.write(aReport.getBytes()); - theFile.close(); - } catch(IOException ioe) { - //error during error report needs to be ignored, do not wish to start infinite loop - } - } - - public void sendDebugReportToAuthor() { - String theLine = ""; - StringBuffer theTrace = new StringBuffer(); - try { - BufferedReader theReader = new BufferedReader( - new InputStreamReader(mApp.openFileInput(ExceptionReportFilename))); - while ((theLine = theReader.readLine())!=null) { - theTrace.append(theLine+"\n"); - } - if (sendDebugReportToAuthor(theTrace.toString())) { - mApp.deleteFile(ExceptionReportFilename); - } - } catch (FileNotFoundException eFnf) { - // nothing to do - } catch(IOException eIo) { - // not going to report - } - } - - public Boolean sendDebugReportToAuthor(String aReport) { - if (aReport!=null) { - Intent theIntent = new Intent(Intent.ACTION_SEND); - String theSubject = mApp.getTitle()+" "+MSG_SUBJECT_TAG; - String theBody = "\n"+MSG_BODY+"\n\n"+aReport+"\n\n"; - theIntent.putExtra(Intent.EXTRA_EMAIL,new String[] {MSG_SENDTO}); - theIntent.putExtra(Intent.EXTRA_TEXT, theBody); - theIntent.putExtra(Intent.EXTRA_SUBJECT, theSubject); - theIntent.setType("message/rfc822"); - Boolean hasSendRecipients = (mApp.getPackageManager().queryIntentActivities(theIntent,0).size()>0); - if (hasSendRecipients) { - mApp.startActivity(theIntent); - return true; - } else { - return false; - } - } else { - return true; - } - } - - public void submit(Throwable e) { - String theErrReport = getDebugReport(e); - saveDebugReport(theErrReport); - //try to send file contents via email (need to do so via the UI thread) - mApp.runOnUiThread(this); - } - - public void uncaughtException(Thread t, Throwable e) { - submit(e); - //do not forget to pass this exception through up the chain - mDefaultUEH.uncaughtException(t,e); - } -} \ No newline at end of file diff --git a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SMS.java b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SMS.java index 8dd0054..334aa3e 100644 --- a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SMS.java +++ b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SMS.java @@ -59,7 +59,7 @@ public class SMS extends BroadcastReceiver{ public void onReceive(Context context, Intent intent) { Log.i(tag,"onRecive()"); - settings = context.getSharedPreferences(SettingsActivity.SETTINGS, 0); + settings = context.getSharedPreferences(SettingsFragment.SETTINGS, 0); numbers = context.getSharedPreferences(NUMBERS, 0); //get the SMS message @@ -87,8 +87,8 @@ public class SMS extends BroadcastReceiver{ * if the SMS message matches a specified string (ignoring case) * then do something */ - if (msg.equalsIgnoreCase(settings.getString(SettingsActivity.LOCATE_PASS, null)) && - settings.getBoolean(SettingsActivity.LOCATE_ENABLED, false)){ + if (msg.equalsIgnoreCase(settings.getString(SettingsFragment.LOCATE_PASS, null)) && + settings.getBoolean(SettingsFragment.LOCATE_ENABLED, false)){ if (phoneNumber.toString().length() > 0 && storeNumber(phoneNumber.toString())){ Log.i(tag, "saved number successfuly!"); @@ -165,8 +165,8 @@ public class SMS extends BroadcastReceiver{ * if the SMS message matches a specified string (ignoring case) * then do something */ - if (msg.equalsIgnoreCase(settings.getString(SettingsActivity.LOCK_PATTERN_PASS, null))&& - settings.getBoolean(SettingsActivity.LOCK_PATTERN_ENABLED, false)){ + if (msg.equalsIgnoreCase(settings.getString(SettingsFragment.LOCK_PATTERN_PASS, null))&& + settings.getBoolean(SettingsFragment.LOCK_PATTERN_ENABLED, false)){ Log.i(tag,"locking phone and dimming screen to save battery"); SettingsManager sm = new SettingsManager(context); diff --git a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SettingsActivity.java b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SettingsFragment.java similarity index 92% rename from DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SettingsActivity.java rename to DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SettingsFragment.java index 008d9a2..9eb6a90 100644 --- a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SettingsActivity.java +++ b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SettingsFragment.java @@ -6,14 +6,13 @@ package com.TwentyCodes.android.DroidFinderFull; import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.os.Bundle; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; -import android.preference.PreferenceActivity; +import android.preference.PreferenceFragment; -public class SettingsActivity extends PreferenceActivity implements OnPreferenceClickListener, OnPreferenceChangeListener{ +public class SettingsFragment extends PreferenceFragment implements OnPreferenceClickListener, OnPreferenceChangeListener{ /* * the following strings are for the shared_prefs passwords.xml */ @@ -52,7 +51,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference } @Override - protected void onResume() { + public void onResume() { super.onResume(); SharedPreferences shared_prefs = getPreferenceManager().getSharedPreferences(); @@ -76,12 +75,12 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference @Override public boolean onPreferenceClick(Preference preference) { if(preference.getKey().equals(BACKUP)){ - new SettingsManager(this).backupSystemSettings(); + new SettingsManager(this.getActivity()).backupSystemSettings(); return true; } if(preference.getKey().equals(RESTORE)){ - new SettingsManager(this).restoreSystemSettings(); + new SettingsManager(this.getActivity()).restoreSystemSettings(); return true; } return false; diff --git a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/TabsAdapter.java b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/TabsAdapter.java new file mode 100644 index 0000000..eacfb29 --- /dev/null +++ b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/TabsAdapter.java @@ -0,0 +1,127 @@ +/** + * TabAdapter.java + * @date Mar 2, 2012 + * @author ricky barrette + * @author Twenty Codes, LLC + */ +package com.TwentyCodes.android.DroidFinderFull; + +import java.util.ArrayList; + +import android.content.Context; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TabHost; +import android.widget.TabWidget; + +/** + * This is a helper class that implements the management of tabs and all + * details of connecting a ViewPager with associated TabHost. It relies on a + * trick. Normally a tab host has a simple API for supplying a View or + * Intent that each tab will show. This is not sufficient for switching + * between pages. So instead we make the content part of the tab host + * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy + * view to show as the tab content. It listens to changes in tabs, and takes + * care of switch to the correct paged in the ViewPager whenever the selected + * tab changes. + * @author google + */ +public class TabsAdapter extends FragmentPagerAdapter implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener { + private final Context mContext; + private final TabHost mTabHost; + private final ViewPager mViewPager; + private final ArrayList mTabs = new ArrayList(); + + static final class TabInfo { + @SuppressWarnings("unused") + private final String tag; + private final Class clss; + private final Bundle args; + + TabInfo(String _tag, Class _class, Bundle _args) { + tag = _tag; + clss = _class; + args = _args; + } + } + + static class DummyTabFactory implements TabHost.TabContentFactory { + private final Context mContext; + + public DummyTabFactory(Context context) { + mContext = context; + } + + @Override + public View createTabContent(String tag) { + View v = new View(mContext); + v.setMinimumWidth(0); + v.setMinimumHeight(0); + return v; + } + } + + public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager) { + super(activity.getSupportFragmentManager()); + mContext = activity; + mTabHost = tabHost; + mViewPager = pager; + mTabHost.setOnTabChangedListener(this); + mViewPager.setAdapter(this); + mViewPager.setOnPageChangeListener(this); + } + + public void addTab(TabHost.TabSpec tabSpec, Class clss, Bundle args) { + tabSpec.setContent(new DummyTabFactory(mContext)); + String tag = tabSpec.getTag(); + + TabInfo info = new TabInfo(tag, clss, args); + mTabs.add(info); + mTabHost.addTab(tabSpec); + notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mTabs.size(); + } + + @Override + public Fragment getItem(int position) { + TabInfo info = mTabs.get(position); + return Fragment.instantiate(mContext, info.clss.getName(), info.args); + } + + @Override + public void onTabChanged(String tabId) { + int position = mTabHost.getCurrentTab(); + mViewPager.setCurrentItem(position); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + } + + @Override + public void onPageSelected(int position) { + // Unfortunately when TabHost changes the current tab, it kindly + // also takes care of putting focus on it when not in touch mode. + // The jerk. + // This hack tries to prevent this from pulling focus out of our + // ViewPager. + TabWidget widget = mTabHost.getTabWidget(); + int oldFocusability = widget.getDescendantFocusability(); + widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); + mTabHost.setCurrentTab(position); + widget.setDescendantFocusability(oldFocusability); + } + + @Override + public void onPageScrollStateChanged(int state) { + } +} \ No newline at end of file