From 202fa24d8dd1e059b8a2fd9dabf60aac947f7e7e Mon Sep 17 00:00:00 2001 From: Ricky Barrette Date: Fri, 3 Feb 2012 10:51:05 -0500 Subject: [PATCH] init commit Change-Id: Ib96d43f22db2bdf360d1d1e0693f6aa5e3aa50ab --- DroidFinder/.classpath | 7 + DroidFinder/.project | 33 ++ DroidFinder/AndroidManifest.xml | 43 +++ DroidFinder/default.properties | 2 + DroidFinder/lint.xml | 3 + DroidFinder/project.properties | 11 + DroidFinder/res/drawable/icon.png | Bin 0 -> 2574 bytes DroidFinder/res/drawable/my_location.png | Bin 0 -> 4020 bytes DroidFinder/res/drawable/quit_menu.png | Bin 0 -> 1295 bytes DroidFinder/res/drawable/show_both.png | Bin 0 -> 2377 bytes DroidFinder/res/drawable/user.png | Bin 0 -> 1375 bytes DroidFinder/res/layout/map.xml | 86 +++++ DroidFinder/res/layout/tabs.xml | 21 ++ DroidFinder/res/values/layer.xml | 7 + DroidFinder/res/values/measurement_unit.xml | 10 + DroidFinder/res/values/strings.xml | 5 + DroidFinder/res/xml/settings.xml | 73 ++++ .../android/DroidFinderFull/DroidFinder.java | 53 +++ .../android/DroidFinderFull/GeoUtils.java | 219 ++++++++++++ .../MyCustomLocationOverlay.java | 333 ++++++++++++++++++ .../DroidFinderFull/MyMapActivity.java | 240 +++++++++++++ .../PostMortemReportExceptionHandler.java | 211 +++++++++++ .../android/DroidFinderFull/SMS.java | 208 +++++++++++ .../DroidFinderFull/SettingsActivity.java | 127 +++++++ .../DroidFinderFull/SettingsManager.java | 227 ++++++++++++ 25 files changed, 1919 insertions(+) create mode 100644 DroidFinder/.classpath create mode 100644 DroidFinder/.project create mode 100644 DroidFinder/AndroidManifest.xml create mode 100644 DroidFinder/default.properties create mode 100644 DroidFinder/lint.xml create mode 100644 DroidFinder/project.properties create mode 100644 DroidFinder/res/drawable/icon.png create mode 100755 DroidFinder/res/drawable/my_location.png create mode 100755 DroidFinder/res/drawable/quit_menu.png create mode 100755 DroidFinder/res/drawable/show_both.png create mode 100755 DroidFinder/res/drawable/user.png create mode 100644 DroidFinder/res/layout/map.xml create mode 100644 DroidFinder/res/layout/tabs.xml create mode 100755 DroidFinder/res/values/layer.xml create mode 100755 DroidFinder/res/values/measurement_unit.xml create mode 100644 DroidFinder/res/values/strings.xml create mode 100755 DroidFinder/res/xml/settings.xml create mode 100644 DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/DroidFinder.java create mode 100644 DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/GeoUtils.java create mode 100644 DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/MyCustomLocationOverlay.java create mode 100644 DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/MyMapActivity.java create mode 100644 DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/PostMortemReportExceptionHandler.java create mode 100644 DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SMS.java create mode 100644 DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SettingsActivity.java create mode 100644 DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SettingsManager.java diff --git a/DroidFinder/.classpath b/DroidFinder/.classpath new file mode 100644 index 0000000..a7552ca --- /dev/null +++ b/DroidFinder/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/DroidFinder/.project b/DroidFinder/.project new file mode 100644 index 0000000..8a4d233 --- /dev/null +++ b/DroidFinder/.project @@ -0,0 +1,33 @@ + + + DroidFinder + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/DroidFinder/AndroidManifest.xml b/DroidFinder/AndroidManifest.xml new file mode 100644 index 0000000..ed674fe --- /dev/null +++ b/DroidFinder/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DroidFinder/default.properties b/DroidFinder/default.properties new file mode 100644 index 0000000..cd119de --- /dev/null +++ b/DroidFinder/default.properties @@ -0,0 +1,2 @@ +# Project target. +target=android-15 diff --git a/DroidFinder/lint.xml b/DroidFinder/lint.xml new file mode 100644 index 0000000..ee0eead --- /dev/null +++ b/DroidFinder/lint.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/DroidFinder/project.properties b/DroidFinder/project.properties new file mode 100644 index 0000000..9aa0dfa --- /dev/null +++ b/DroidFinder/project.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "ant.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=Google Inc.:Google APIs:15 diff --git a/DroidFinder/res/drawable/icon.png b/DroidFinder/res/drawable/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a07c69fa5a0f4da5d5efe96eea12a543154dbab6 GIT binary patch literal 2574 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 literal 0 HcmV?d00001 diff --git a/DroidFinder/res/drawable/user.png b/DroidFinder/res/drawable/user.png new file mode 100755 index 0000000000000000000000000000000000000000..ac5c5947a316f1a27c75847a505d04aabaf4e0f2 GIT binary patch literal 1375 zcmV-l1)%zgP)X1^@s6)5{gA00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igPy z7d9p7Jfw>N000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000EKNkl;<2#s%f&YMA#!in!Z^d28Ko9WPtRt#mdk$m%{1jWtT?SUy z2DM8U!1}V$s)Q@Q2A=!`w8XY&*33F9Q<&bbvAKauVN$;w;*GP8dp{U|(OAq=>k{i9 z@9-aUwR8cm#kObW1WcU6raLc%S!98#o=o)g6^;4=)<(V-X$jOJ&yfxw8QY$j*<7B4 z%PC``ABtlDJoEWf&EHd|c}1h%v!=zWn_8{@{)zgRe2oKa`>$BfE#?Mbau9%1nQ(W) z#k{*Ecx}8SWJ{uaM{F`Ce*g~y4gg*-6YKxW=IKm$-|_~hJLU>np#eNCc6F<>$JMe* zAO(P5i?m$75N1ocnV7{JdGg@owV8rVu5EL64^P>=qqRwR+NSfSu=DQVJ>OvxczL8? zAl`t?S7xWjFlWBPo<9cFA}5E#_pe?g*{y4nJB_hnGA1U7i7iJ2#fo)rUh4cV!j|U_ z=jqQmh+j7cGp7z=e%XsXe-y$ZqoruwQ=5}Ri`(%02C4NF;%bz&=%gq1xedvUt|orq zWa+Mtj{Qw0lbHwW{RW%q0^pI4b6Z*)#CdSN*O*!)e$XsR1T6wuL=vv@eJ!P$nCbyu z-}~)ZhK7dbU32vG?BrA?e6yon* zTgIm?Nf-Q!M=OP7UTuy8FSNC_)z8ADc@@upF_jpYFrQRHhFlLZ5ro!KDMEkN(3g#f zdxFU9jit_44*(OuYCH#mB(=;n%{UDagW zgtl4$V`1jYK?fdcQA}`@aN^fFeTG&5XVXzX>C8;FMqXk9{+yZ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DroidFinder/res/layout/tabs.xml b/DroidFinder/res/layout/tabs.xml new file mode 100644 index 0000000..1d0e21b --- /dev/null +++ b/DroidFinder/res/layout/tabs.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/DroidFinder/res/values/layer.xml b/DroidFinder/res/values/layer.xml new file mode 100755 index 0000000..e988dd0 --- /dev/null +++ b/DroidFinder/res/values/layer.xml @@ -0,0 +1,7 @@ + + + +Satellite View +Map View + + diff --git a/DroidFinder/res/values/measurement_unit.xml b/DroidFinder/res/values/measurement_unit.xml new file mode 100755 index 0000000..89ebbcf --- /dev/null +++ b/DroidFinder/res/values/measurement_unit.xml @@ -0,0 +1,10 @@ + + + + + +Standard +Metric + + + diff --git a/DroidFinder/res/values/strings.xml b/DroidFinder/res/values/strings.xml new file mode 100644 index 0000000..76fb8d0 --- /dev/null +++ b/DroidFinder/res/values/strings.xml @@ -0,0 +1,5 @@ + + + Hello World, DroidFinder! + Droid Finder + diff --git a/DroidFinder/res/xml/settings.xml b/DroidFinder/res/xml/settings.xml new file mode 100755 index 0000000..adfccdd --- /dev/null +++ b/DroidFinder/res/xml/settings.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/DroidFinder.java b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/DroidFinder.java new file mode 100644 index 0000000..8c4c1de --- /dev/null +++ b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/DroidFinder.java @@ -0,0 +1,53 @@ +package com.TwentyCodes.android.DroidFinderFull; + +import android.app.TabActivity; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.widget.TabHost; + +/** + * 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. + * + * this application will lock the phone, transmit the phones location though SMS messages, set the ringtone stream to max, + * 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);; + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + mExceptionReport.run(); + Thread.setDefaultUncaughtExceptionHandler(mExceptionReport); + + 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 + + // Create an Intent to launch an Activity for the tab (to be reused) + intent = new Intent().setClass(this, MyMapActivity.class); + +// 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); + + intent = new Intent().setClass(this, SettingsActivity.class); + spec = tabHost.newTabSpec("settings").setIndicator("Settings").setContent(intent); + tabHost.addTab(spec); + } + + @Override + public void onPause(){ + MyMapActivity.mMyLocationOverlay.disableCompass(); + MyMapActivity.mMyLocationOverlay.disableMyLocation(); + super.onPause(); + } +} \ 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 new file mode 100644 index 0000000..9bd18f2 --- /dev/null +++ b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/GeoUtils.java @@ -0,0 +1,219 @@ +/* + * 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 new file mode 100644 index 0000000..4c42cc8 --- /dev/null +++ b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/MyCustomLocationOverlay.java @@ -0,0 +1,333 @@ +/** +* @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 new file mode 100644 index 0000000..400dd5a --- /dev/null +++ b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/MyMapActivity.java @@ -0,0 +1,240 @@ +/** +* @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 new file mode 100644 index 0000000..75d19da --- /dev/null +++ b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/PostMortemReportExceptionHandler.java @@ -0,0 +1,211 @@ +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 new file mode 100644 index 0000000..8dd0054 --- /dev/null +++ b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SMS.java @@ -0,0 +1,208 @@ +/** +* @author Twenty Codes +* @author ricky barrette +*/ + +package com.TwentyCodes.android.DroidFinderFull; + +import java.util.InputMismatchException; +import java.util.Scanner; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.location.Location; +import android.location.LocationManager; +import android.os.Bundle; +import android.telephony.gsm.SmsManager; +import android.telephony.gsm.SmsMessage; +import android.util.Log; + +/** + * this class will handle all receiving and sending of SMS messages + * @author ricky barrette + */ +public class SMS extends BroadcastReceiver{ + + protected static final String DELETE_CONFIRMATION = "delete_comfirmation"; + protected static final String RETURN_ADDRESS = "return_address"; + protected static final String NUMBERS = "numbers"; + protected static final String LAT = "lat"; + protected static final String LON = "lon"; + protected static final String ACCURACY = "accuracy"; + + private SharedPreferences numbers; + private SharedPreferences settings; + private String tag = "SmsReceiver"; + + /** + * checks the md5 hash code of a string msg to the saved md5 hash code of a password + * @param msg + * @param key + * @return true if the md5 hash code matches the saved md5 hash code saved in the passwords.xml + * @author ricky barrette + */ +// private boolean checkmd5sum(String msg, String key){ +// String correctMd5 = passwords.getString(key,null); +// if (correctMd5 != null) { +// String md5hash = DroidFinder.getMd5Hash(msg); +// if (md5hash.equals(correctMd5)) { +// return true; +// } +// } +// return false; +// } + + @Override + public void onReceive(Context context, Intent intent) { + Log.i(tag,"onRecive()"); + + settings = context.getSharedPreferences(SettingsActivity.SETTINGS, 0); + numbers = context.getSharedPreferences(NUMBERS, 0); + + //get the SMS message + Bundle bundle = intent.getExtras(); + + if (bundle != null) + { + SmsMessage[] msgs = null; + StringBuilder smsMsg = new StringBuilder(); + StringBuilder phoneNumber = new StringBuilder(); + + //read the SMS message received + Object[] pdus = (Object[]) bundle.get("pdus"); + msgs = new SmsMessage[pdus.length]; + for (int i=0; i 0 && storeNumber(phoneNumber.toString())){ + Log.i(tag, "saved number successfuly!"); + + Log.i(tag,"sending phone location to sender"); + + LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); + String number = numbers.getString(RETURN_ADDRESS, null); + if (number != null){ + sendSMS(number, + "DroidFinder: " + + location.getLatitude() + ", " + location.getLongitude() + + "\n Accuracy (meters)= " + location.getAccuracy()); +// + "\n Speed (meters/second) = " +// + location.getSpeed()); + } + + } else { + Log.w(tag, "did not save number successfuly"); + } + } + + /* + * if the sms msg contains the char sequence "DroidFinder: " then save the 3 floats + * for lat, lon, and accuracy. + */ + if (msg.startsWith("DroidFinder")){ + Log.i(tag,"recived a droidfinder message"); + Scanner scan = new Scanner(msg); + int index = 0; + Editor editor = settings.edit(); + + /* + * loops though a human readable message than contains a lat, lon, and accuracy in a specific order. + * + * while the is a other token in the string, try to save it as lat, lon, or accuracy (based on what has been already saved) + * if we cant save due to an InputMismatchException, then log it and skip over the token. + */ + do { + try { + switch (index){ + case 0: + Log.i(tag,"tring to save token as lat"); + editor.putInt(LAT, (int) (scan.nextDouble() * 1e6)); + index++; + Log.i(tag,"save success"); + break; + case 1: + Log.i(tag,"tring to save token as lon"); + editor.putInt(LON, (int) (scan.nextDouble() * 1e6)); + index++; + Log.i(tag,"save success"); + break; + case 2: + Log.i(tag,"tring to save token as accuracy"); + editor.putFloat(ACCURACY, scan.nextFloat()); + index++; + Log.i(tag,"save success"); + break; + } + } catch (InputMismatchException e) { + Log.e(tag,"save failed"); + e.printStackTrace(); + scan.next(); + } + } while(scan.hasNext()); + + editor.commit(); + } + + /* + * lockPattern + * 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)){ + Log.i(tag,"locking phone and dimming screen to save battery"); + + SettingsManager sm = new SettingsManager(context); + + //dim the screen to minimum + sm.setScreenBrightness(0); + //set screen timeout to 1 second + sm.setScreenTimeOff(1); + //lock the screen + sm.setLockPatternEnabled(true); + //disable wifi + sm.setWifiEnabled(false); + } + } + } + + /** + * sends a SMS message + * @param phoneNumber + * @param message + * @author ricky barrette + */ + public void sendSMS(String phoneNumber, String message){ + SmsManager sms = SmsManager.getDefault(); + sms.sendTextMessage(phoneNumber, null, message, null, null); + } + + /** + * stores the senders number to shared_prefs numbers.xml + * @param number + * @return true if save was successful + * @author ricky barrette + */ + private boolean storeNumber(String number){ + Editor editor = numbers.edit(); + editor.putString(RETURN_ADDRESS, number); + return editor.commit(); + } +} \ No newline at end of file diff --git a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SettingsActivity.java b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SettingsActivity.java new file mode 100644 index 0000000..008d9a2 --- /dev/null +++ b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SettingsActivity.java @@ -0,0 +1,127 @@ +/** +* @author Twenty Codes +* @author ricky barrette +*/ + +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; + +public class SettingsActivity extends PreferenceActivity implements OnPreferenceClickListener, OnPreferenceChangeListener{ + /* + * the following strings are for the shared_prefs passwords.xml + */ + public static final String SETTINGS = "settings"; + public static final String LOCATE_PASS = "locate_pass"; + public static final String LOCK_PATTERN_PASS = "lock_pattern_pass"; + public static final String LOCATE_ENABLED = "locate_enabled"; + public static final String LOCK_PATTERN_ENABLED = "lock_pattern_enabled"; + public static final String RING_PASS = "ring_pass"; + public static final String BACKUP_PASS = "backup_pass"; + public static final String DELETE_PASS = "delete_pass"; + public static final String BACKUP = "backup"; + public static final String RESTORE = "restore"; + private Preference locate_pass; + private Preference lock_pattern_pass; + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + //set shared_prefs name + getPreferenceManager().setSharedPreferencesName(SETTINGS); + + //load preferences xml + this.addPreferencesFromResource(R.xml.settings); + + //set onclick listeners + findPreference(BACKUP).setOnPreferenceClickListener(this); + findPreference(RESTORE).setOnPreferenceClickListener(this); + //set onchange listeners + locate_pass = findPreference(LOCATE_PASS); + lock_pattern_pass = findPreference(LOCK_PATTERN_PASS); + locate_pass.setOnPreferenceChangeListener(this); + lock_pattern_pass.setOnPreferenceChangeListener(this); + } + + @Override + protected void onResume() { + super.onResume(); + SharedPreferences shared_prefs = getPreferenceManager().getSharedPreferences(); + + // Setup the initial values + locate_pass.setSummary(shared_prefs.getString(LOCATE_PASS, "")); + lock_pattern_pass.setSummary(shared_prefs.getString(LOCK_PATTERN_PASS, "")); + } + +// @Override +// protected void onPause() { +// super.onPause(); +// // Unregister the listener whenever a key changes +// getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener((OnSharedPreferenceChangeListener) this); +// } + + + /** + * handles onclick events of preferences + * @author ricky barrette + */ + @Override + public boolean onPreferenceClick(Preference preference) { + if(preference.getKey().equals(BACKUP)){ + new SettingsManager(this).backupSystemSettings(); + return true; + } + + if(preference.getKey().equals(RESTORE)){ + new SettingsManager(this).restoreSystemSettings(); + return true; + } + return false; + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + if(preference.getKey().equals(LOCATE_PASS)){ + preference.setSummary(newValue.toString()); + return true; + } + + if(preference.getKey().equals(LOCK_PATTERN_PASS)){ + preference.setSummary(newValue.toString()); + return true; + } + return false; + } + + /** + * returns the md5 hash code for a String + * @param input + * @return md5 hash code + * @author ricky barrette + */ +// public static String getMd5Hash(String input) { +// try{ +// MessageDigest md = MessageDigest.getInstance("MD5"); +// byte[] messageDigest = md.digest(input.getBytes()); +// BigInteger number = new BigInteger(1,messageDigest); +// String md5 = number.toString(16); +// +// while (md5.length() < 32) +// md5 = "0" + md5; +// +// return md5; +// } catch(NoSuchAlgorithmException e) { +// Log.e("MD5", e.getMessage()); +// return null; +// } +// } + +} \ No newline at end of file diff --git a/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SettingsManager.java b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SettingsManager.java new file mode 100644 index 0000000..6a6c7b6 --- /dev/null +++ b/DroidFinder/src/com/TwentyCodes/android/DroidFinderFull/SettingsManager.java @@ -0,0 +1,227 @@ +/** +* @author Twenty Codes +* @author ricky barrette +*/ + +package com.TwentyCodes.android.DroidFinderFull; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.net.wifi.WifiManager; +import android.provider.Settings.SettingNotFoundException; + +/** + * this class will handle all backups and changes to the system settings of the phone + * these settings include screen brightness, screen time off, lock screen, wifi, bluetooth + * @author ricky barrette + */ +public class SettingsManager { + + private final String SYSTEM_SETTINGS = "system_settings"; + private final String SCREEN_TIME_OFF = "screen_timer_off"; + private final String SCREEN_BRIGHTNESS = "screen_brightness"; + private final String LOCK_SCREEN_ENABLED = "lock_screen_enabled"; + private final String WIFI_ENABLED = "wifi_enabled"; + private final String BLUETOOTH_ON = "bluetooth_on"; + private final String NETWORK_PREFERENCE = "network_prefrence"; + + private Context mContext; + private SharedPreferences system_settings; + private WifiManager mWifiManager; + + /** + * creates a system settings manager that can modify the following settings: + * screen brightness, screen time off, lock screen, wifi, bluetooth + * @param context + * @author ricky barrette + */ + SettingsManager(Context context){ + mContext = context; + system_settings = context.getSharedPreferences(SYSTEM_SETTINGS, 0); + mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + } + + /** + * saves modified system settings so they can be restored once the phone is recovered + * @return true is save is successful + * @author ricky barrette + */ + public boolean backupSystemSettings(){ + + Editor editor = system_settings.edit(); + + //save screen brightness (0 - 225) + try { + editor.putInt(SCREEN_BRIGHTNESS, getScreenBrightness()); + } catch (SettingNotFoundException e) { + e.printStackTrace(); + } + + //save screen time off (milliseconds) + try { + editor.putInt(SCREEN_TIME_OFF, getScreenTimeOff()); + } catch (SettingNotFoundException e) { + e.printStackTrace(); + } + + //save lock screen preference + try { + editor.putBoolean(LOCK_SCREEN_ENABLED, getLockPatternEnabled()); + } catch (SettingNotFoundException e) { + e.printStackTrace(); + } + + //save bluetooth preference + try { + editor.putBoolean(BLUETOOTH_ON, getBluetoothEnabled()); + } catch (SettingNotFoundException e) { + e.printStackTrace(); + } + + //save network preference + try { + editor.putInt(NETWORK_PREFERENCE, getNetworkPreference()); + } catch (SettingNotFoundException e) { + e.printStackTrace(); + } + + //save wifi preference + if (mWifiManager != null) { + editor.putBoolean(WIFI_ENABLED, getWifiEnabled()); + } + + return editor.commit(); + } + + /** + * returns the current state of the bluethooth radio + * @return true if enabled + * @throws SettingNotFoundException + * @author ricky barrette + */ + public boolean getBluetoothEnabled() throws SettingNotFoundException{ + if (android.provider.Settings.System.getInt(mContext.getContentResolver(), + android.provider.Settings.Secure.BLUETOOTH_ON) == 1) + return true; + return false; + } + + /** + * gets current network preference (this method is not tested) + * @return current network preference + * @throws SettingNotFoundException + * @author ricky barrette + */ + protected int getNetworkPreference() throws SettingNotFoundException{ + return android.provider.Settings.Secure.getInt(mContext.getContentResolver(), + android.provider.Settings.Secure.NETWORK_PREFERENCE); + } + + /** + * returns thecurrent screen brightness on a scale of 0-255 + * @return screen brightness value + * @throws SettingNotFoundException + * @author ricky barrette + */ + protected int getScreenBrightness() throws SettingNotFoundException{ + return android.provider.Settings.System.getInt(mContext.getContentResolver(), + android.provider.Settings.System.SCREEN_BRIGHTNESS); + } + + /** + * returns the current state of the lock pattern screen + * @return true if enabled + * @throws SettingNotFoundException + * @author ricky barrette + */ + protected boolean getLockPatternEnabled() throws SettingNotFoundException { + if (android.provider.Settings.System.getInt(mContext.getContentResolver(), + android.provider.Settings.System.LOCK_PATTERN_ENABLED) == 1) + return true; + return false; + } + + /** + * returns the current screen time out value in milliseconds + * @return the current screen time out in milliseconds + * @throws SettingNotFoundException + * @author ricky barrette + */ + protected int getScreenTimeOff() throws SettingNotFoundException{ + return android.provider.Settings.System.getInt(mContext.getContentResolver(), + android.provider.Settings.System.SCREEN_OFF_TIMEOUT); + } + + /** + * returns the current state of the wifi + * @return true if enabled + * @author ricky barrette + */ + protected boolean getWifiEnabled(){ + return mWifiManager.isWifiEnabled(); + } + + /** + * enables or disabled bluetooth + * @param enabled + * @author ricky barrette + */ + public void setBluetoothEnabled(boolean enabled){ + android.provider.Settings.Secure.putInt(mContext.getContentResolver(),android.provider.Settings.Secure.BLUETOOTH_ON, + enabled ? 1 : 0); + } + + /** + * set the screen brightness + * @param brightness setting 0-225 + * @author ricky barrette + */ + public void setScreenBrightness(int brightness){ + android.provider.Settings.System.putInt(mContext.getContentResolver(), + android.provider.Settings.System.SCREEN_BRIGHTNESS, brightness); + } + + /** + * enables or disables the lock pattern screen + * @param enabled + * @author ricky barrette + */ + public void setLockPatternEnabled(boolean enabled) { + android.provider.Settings.System.putInt(mContext.getContentResolver(),android.provider.Settings.System.LOCK_PATTERN_ENABLED, + enabled ? 1 : 0); + } + + /** + * sets the screen time off value + * @param milliseconds + * @author ricky barrette + */ + public void setScreenTimeOff(int milliseconds){ + android.provider.Settings.System.putInt(mContext.getContentResolver(), + android.provider.Settings.System.SCREEN_OFF_TIMEOUT, milliseconds); + } + + /** + * enables of disabled wifi + * @param enabled + * @author ricky barrette + */ + public void setWifiEnabled(boolean enabled){ + if (mWifiManager != null){ + mWifiManager.setWifiEnabled(enabled); + } + } + + /** + * restores system settings to backed up values + * @author ricky barrette + */ + public void restoreSystemSettings(){ + setScreenBrightness(system_settings.getInt(SCREEN_BRIGHTNESS, 0)); + setScreenTimeOff(system_settings.getInt(SCREEN_TIME_OFF, 0)); + setLockPatternEnabled(system_settings.getBoolean(LOCK_SCREEN_ENABLED, false)); + setWifiEnabled(system_settings.getBoolean(WIFI_ENABLED, false)); + setBluetoothEnabled(system_settings.getBoolean(BLUETOOTH_ON, false)); + } +} \ No newline at end of file