Started to preform a major update

I Removed all needed class that are replaced by lib classes

I updated the manifest

I updated from a tabactivity to a fragment activity, implmenting a tab
host controlling fragments

Change-Id: I2ab2eb548c122f3fe1afbce1fdd6e5bad448a724
Signed-off-by: Ricky Barrette <rickbarrette@gmail.com>
This commit is contained in:
2012-03-02 09:32:08 -05:00
parent 51f497ccf7
commit 47400460d7
13 changed files with 243 additions and 1077 deletions

View File

@@ -3,5 +3,7 @@
<classpathentry kind="src" path="src"/> <classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/> <classpathentry kind="src" path="gen"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="lib" path="/LocationLib/lib/android-support-v4-r6-googlemaps.jar"/>
<classpathentry kind="output" path="bin/classes"/> <classpathentry kind="output" path="bin/classes"/>
</classpath> </classpath>

View File

@@ -1,43 +1,50 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest package="com.TwentyCodes.android.DroidFinderFull" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="0.0.4" android:versionCode="6"> package="com.TwentyCodes.android.DroidFinderFull"
<application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar"> android:versionCode="6"
android:versionName="0.0.4" >
<uses-library android:name="com.google.android.maps"/> <uses-sdk android:minSdkVersion="3" />
<activity android:label="@string/app_name" android:name="DroidFinder"> <uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar" >
<uses-library android:name="com.google.android.maps" />
<activity
android:name="DroidFinder"
android:label="@string/app_name" >
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<receiver
<receiver android:process=":remote" android:name="SMS"> android:name="SMS"
android:process=":remote" >
<intent-filter> <intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" /> <action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- activities for tab activity --> <!-- activities for tab activity -->
<activity android:name=".MyMapActivity"/> <activity android:name="com.TwentyCodes.android.exception.ExceptionReportActivity" />
<activity android:name=".SettingsActivity"/>
</application>
<uses-sdk android:minSdkVersion="3" /> <service android:name="com.TwentyCodes.android.exception.ReportPostingService" />
<service android:name="com.TwentyCodes.android.location.LocationService" />
</application>
<uses-permission android:name="android.permission.SEND_SMS"></uses-permission>
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<uses-permission android:name="android.permission.WRITE_SETTINGS"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
</manifest> </manifest>

View File

@@ -0,0 +1,22 @@
# exceptionhandler.properties
# @author ricky barrette <rickbarrette@gmail.com>
# @author twenty codes <twentycodes@gmail.com>
# 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

View File

@@ -9,3 +9,5 @@
# Project target. # Project target.
target=Google Inc.:Google APIs:15 target=Google Inc.:Google APIs:15
android.library.reference.1=../../exception_handler_library/ExceptionHandlerLib
android.library.reference.2=../../location_library/LocationLib

View File

@@ -2,20 +2,30 @@
<TabHost xmlns:android="http://schemas.android.com/apk/res/android" <TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost" android:id="@android:id/tabhost"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent"> android:layout_height="fill_parent" >
<LinearLayout <LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:padding="5dp"> android:orientation="vertical"
android:padding="5dp" >
<TabWidget <TabWidget
android:id="@android:id/tabs" android:id="@android:id/tabs"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<FrameLayout <FrameLayout
android:id="@android:id/tabcontent" android:id="@android:id/tabcontent"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:padding="5dp" /> android:padding="5dp" >
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
</LinearLayout> </LinearLayout>
</TabHost> </TabHost>

View File

@@ -1,11 +1,13 @@
package com.TwentyCodes.android.DroidFinderFull; package com.TwentyCodes.android.DroidFinderFull;
import android.app.TabActivity;
import android.content.Intent;
import android.os.Bundle; 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 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 * 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. * 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 * 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 * @author ricky barrette
*/ */
public class DroidFinder extends TabActivity{ public class DroidFinder extends FragmentActivity{
private PostMortemReportExceptionHandler mExceptionReport = new PostMortemReportExceptionHandler(this);; private TabHost mTabHost;
private ViewPager mViewPager;
private TabsAdapter mTabsAdapter;
/** Called when the activity is first created. */ /** Called when the activity is first created. */
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
mExceptionReport.run(); Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this));
Thread.setDefaultUncaughtExceptionHandler(mExceptionReport);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.tabs); setContentView(R.layout.tabs);
TabHost tabHost = getTabHost(); // The activity TabHost mTabHost = (TabHost)findViewById(android.R.id.tabhost);
TabHost.TabSpec spec; // Resusable TabSpec for each tab mTabHost.setup();
Intent intent; // Reusable Intent for each tab
// Create an Intent to launch an Activity for the tab (to be reused) mViewPager = (ViewPager)findViewById(R.id.pager);
intent = new Intent().setClass(this, MyMapActivity.class);
// Initialize a TabSpec for each tab and add it to the TabHost mTabsAdapter = new TabsAdapter(this, mTabHost, mViewPager);
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); mTabsAdapter.addTab(mTabHost.newTabSpec("map").setIndicator("Map"), UserOverlayMapFragment.class, null);
spec = tabHost.newTabSpec("settings").setIndicator("Settings").setContent(intent); // mTabsAdapter.addTab(mTabHost.newTabSpec("settings").setIndicator("Settings"), SettingsFragment.class, null);
tabHost.addTab(spec);
if (savedInstanceState != null) {
mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
}
} }
@Override @Override
public void onPause(){ protected void onSaveInstanceState(Bundle outState) {
MyMapActivity.mMyLocationOverlay.disableCompass(); super.onSaveInstanceState(outState);
MyMapActivity.mMyLocationOverlay.disableMyLocation(); outState.putString("tab", mTabHost.getCurrentTabTag());
super.onPause();
} }
} }

View File

@@ -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<Point> mPoints = new ArrayList<Point>();
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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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<Overlay> 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();
}
}

View File

@@ -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
* <uses-permission android:name="android.permission.READ_LOGS" />
* @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);
}
}

View File

@@ -59,7 +59,7 @@ public class SMS extends BroadcastReceiver{
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
Log.i(tag,"onRecive()"); Log.i(tag,"onRecive()");
settings = context.getSharedPreferences(SettingsActivity.SETTINGS, 0); settings = context.getSharedPreferences(SettingsFragment.SETTINGS, 0);
numbers = context.getSharedPreferences(NUMBERS, 0); numbers = context.getSharedPreferences(NUMBERS, 0);
//get the SMS message //get the SMS message
@@ -87,8 +87,8 @@ public class SMS extends BroadcastReceiver{
* if the SMS message matches a specified string (ignoring case) * if the SMS message matches a specified string (ignoring case)
* then do something * then do something
*/ */
if (msg.equalsIgnoreCase(settings.getString(SettingsActivity.LOCATE_PASS, null)) && if (msg.equalsIgnoreCase(settings.getString(SettingsFragment.LOCATE_PASS, null)) &&
settings.getBoolean(SettingsActivity.LOCATE_ENABLED, false)){ settings.getBoolean(SettingsFragment.LOCATE_ENABLED, false)){
if (phoneNumber.toString().length() > 0 && storeNumber(phoneNumber.toString())){ if (phoneNumber.toString().length() > 0 && storeNumber(phoneNumber.toString())){
Log.i(tag, "saved number successfuly!"); 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) * if the SMS message matches a specified string (ignoring case)
* then do something * then do something
*/ */
if (msg.equalsIgnoreCase(settings.getString(SettingsActivity.LOCK_PATTERN_PASS, null))&& if (msg.equalsIgnoreCase(settings.getString(SettingsFragment.LOCK_PATTERN_PASS, null))&&
settings.getBoolean(SettingsActivity.LOCK_PATTERN_ENABLED, false)){ settings.getBoolean(SettingsFragment.LOCK_PATTERN_ENABLED, false)){
Log.i(tag,"locking phone and dimming screen to save battery"); Log.i(tag,"locking phone and dimming screen to save battery");
SettingsManager sm = new SettingsManager(context); SettingsManager sm = new SettingsManager(context);

View File

@@ -6,14 +6,13 @@
package com.TwentyCodes.android.DroidFinderFull; package com.TwentyCodes.android.DroidFinderFull;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle; import android.os.Bundle;
import android.preference.Preference; import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener; 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 * the following strings are for the shared_prefs passwords.xml
*/ */
@@ -52,7 +51,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
} }
@Override @Override
protected void onResume() { public void onResume() {
super.onResume(); super.onResume();
SharedPreferences shared_prefs = getPreferenceManager().getSharedPreferences(); SharedPreferences shared_prefs = getPreferenceManager().getSharedPreferences();
@@ -76,12 +75,12 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
@Override @Override
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
if(preference.getKey().equals(BACKUP)){ if(preference.getKey().equals(BACKUP)){
new SettingsManager(this).backupSystemSettings(); new SettingsManager(this.getActivity()).backupSystemSettings();
return true; return true;
} }
if(preference.getKey().equals(RESTORE)){ if(preference.getKey().equals(RESTORE)){
new SettingsManager(this).restoreSystemSettings(); new SettingsManager(this.getActivity()).restoreSystemSettings();
return true; return true;
} }
return false; return false;

View File

@@ -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<TabInfo> mTabs = new ArrayList<TabInfo>();
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) {
}
}