inital commit

This commit is contained in:
2011-07-20 15:14:19 +00:00
parent d2a371bb2e
commit 87417dfc81
62 changed files with 151930 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
/**
* LocationRinger.java
* @date Apr 29, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger;
import android.os.Bundle;
import com.TwentyCodes.android.LocationRinger.ui.RingerListActivity;
import com.TwentyCodes.android.exception.ExceptionHandler;
/**
* This is the main Activity for Location Ringer
* @author ricky barrette
*/
public class LocationRinger extends RingerListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this));
super.onCreate(savedInstanceState);
}
}

View File

@@ -0,0 +1,18 @@
/**
* LocatoinSelectedListener.java
* @date May 9, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger;
import com.google.android.maps.GeoPoint;
/**
* This interface will be used to pass the selected location from the dialogs to the listening instance
* @author ricky barrette
*/
public interface LocationSelectedListener {
public void onLocationSelected(GeoPoint point);
}

View File

@@ -0,0 +1,23 @@
/**
* OnDatabaseUpgradeCompeteListener.java
* @date Jul 2, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.db;
/**
* This interface will be used to listen to see when the database events are complete
* @author ricky barrette
*/
public interface DatabaseListener {
public void onDatabaseUpgradeComplete();
public void onRingerDeletionComplete();
public void onRestoreComplete();
public void onDatabaseUpgrade();
}

View File

@@ -0,0 +1,596 @@
/**
* RingerDatabase.java
* @date Apr 29, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.db;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import com.TwentyCodes.android.LocationRinger.R;
import com.TwentyCodes.android.LocationRinger.debug.Debug;
/**
* This class will be the main interface between location ringer and it's database
* @author ricky barrette
*/
public class RingerDatabase {
private static final String TAG = "RingerDatabase";
private Context mContext;
private SQLiteDatabase mDb;
public boolean isUpgrading = false;
private static final String RINGER_INFO_TABLE = "ringer_info";
private DatabaseListener mListener;
/*
* database information values
*/
private final int DATABASE_VERSION = 3;
/*
* the following is for the table that holds the other table names
*/
private final String DATABASE_NAME = "ringers.db";
private final String RINGER_TABLE = "ringers";
/*
* Database keys
*/
public final static String KEY_RINGER_NAME = "ringer_name";
public final static String KEY_RINGTONE = "home_ringtone";
public final static String KEY_NOTIFICATION_RINGTONE = "notification_ringtone";
public final static String KEY_RINGTONE_IS_SILENT = "ringtone_is_silent";
public final static String KEY_NOTIFICATION_IS_SILENT = "notification_is_silent";
public final static String KEY_IS_ENABLED = "is_enabled";
public final static String KEY_RADIUS = "radius";
public final static String KEY_LOCATION_LAT = "location_lat";
public final static String KEY_LOCATION_LON = "location_lon";
public final static String KEY_RINGTONE_URI = "ringtone_uri";
public final static String KEY_NOTIFICATION_RINGTONE_URI = "away_notification_uri";
public final static String KEY_RINGTONE_VOLUME = "ringtone_volume";
public final static String KEY_NOTIFICATION_RINGTONE_VOLUME = "notification_ringtone_volume";
public final static String KEY_WIFI = "wifi";
public final static String KEY_BT = "bt";
public final static String KEY_MUSIC_VOLUME = "music_volume";
public final static String KEY_ALARM_VOLUME = "alarm_volume";
public static final String KEY_VALUE = "value";
public static final String KEY = "key";
public static final String KEY_UPDATE_INTERVAL = "update_interval";
public static final String KEY_PLUS_BUTTON_HINT = "plus_button_hint";
/**
* A helper class to manage database creation and version management.
* @author ricky barrette
*/
private class OpenHelper extends SQLiteOpenHelper {
/**
* Creates a new OpenHelper
* @param context
* @author ricky barrette
*/
public OpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
/**
* Converts the database from version 2 to 3
* @param db
* @author ricky barrette
*/
private void convert2to3(SQLiteDatabase db){
//get all the ringer information from the old table
Cursor cursor = db.query("two", new String[] { KEY_RINGER_NAME, KEY_RINGTONE,
KEY_NOTIFICATION_RINGTONE, KEY_RINGTONE_IS_SILENT,
KEY_NOTIFICATION_IS_SILENT, KEY_IS_ENABLED,
KEY_RADIUS, KEY_LOCATION_LAT, KEY_LOCATION_LON,
KEY_RINGTONE_URI, KEY_NOTIFICATION_RINGTONE_URI,
KEY_RINGTONE_VOLUME, KEY_NOTIFICATION_RINGTONE_VOLUME,
KEY_WIFI, KEY_BT, KEY_MUSIC_VOLUME, KEY_ALARM_VOLUME
}, null, null, null, null, null);
/*
* iterate through the database moving data over to the version 3 tables
*/
int count = cursor.getColumnCount();
if (cursor.moveToFirst()) {
do {
ContentValues ringer = new ContentValues();
if(Debug.DEBUG)
Log.v(TAG, "Converting: " + cursor.getString(0));
for(int i = 0; i < count; i++){
if(Debug.DEBUG)
Log.v(TAG, i + " = "+ cursor.getColumnName(i) +" ~ " + cursor.getString(i));
switch(i){
case 0: //ringer name
ringer.put(cursor.getColumnName(i), cursor.getString(0));
break;
case 5: //is enabled
ringer.put(KEY_IS_ENABLED, cursor.getString(i));
break;
case 6: //radius
ringer.put(KEY_RADIUS, cursor.getString(i));
break;
case 7: // lat
ringer.put(KEY_LOCATION_LAT, cursor.getString(i));
break;
case 8: // lon
ringer.put(KEY_LOCATION_LON, cursor.getString(i));
break;
default:
ContentValues values = new ContentValues();
values.put(KEY_RINGER_NAME, cursor.getString(0));
values.put(KEY, cursor.getColumnName(i));
values.put(KEY_VALUE, cursor.getString(i));
db.insert(RINGER_INFO_TABLE, null, values);
}
}
db.insert(RINGER_TABLE, null, ringer);
} while (cursor.moveToNext());
}
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
/**
* Creates the initial database structure
* @param db
* @author ricky barrette
*/
private void createDatabase(SQLiteDatabase db){
db.execSQL("CREATE TABLE " + RINGER_TABLE +
"(id INTEGER PRIMARY KEY, " +
KEY_RINGER_NAME+" TEXT, " +
KEY_IS_ENABLED+" TEXT, " +
KEY_RADIUS+" INTEGER, " +
KEY_LOCATION_LAT+" INTEGER, " +
KEY_LOCATION_LON+" INTEGER)");
db.execSQL("CREATE TABLE " + RINGER_INFO_TABLE +
"(id INTEGER PRIMARY KEY, " +
KEY_RINGER_NAME+" TEXT, " +
KEY+" TEXT, " +
KEY_VALUE+" TEXT)");
}
/**
* called when the database is created for the first time. this will create our Ringer database
* (non-Javadoc)
* @see android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite.SQLiteDatabase)
* @author ricky barrette
*/
@Override
public void onCreate(SQLiteDatabase db) {
if(Debug.DROP_TABLE_EVERY_TIME)
db.execSQL("DROP TABLE IF EXISTS " + RINGER_TABLE);
createDatabase(db);
//insert the default ringer into this table
db.execSQL("insert into " + RINGER_TABLE + "(" + KEY_RINGER_NAME + ") values ('"+RingerDatabase.this.mContext.getString(R.string.default_ringer)+"')");
}
/**
* called when the database needs to be updated
* (non-Javadoc)
* @see android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite.SQLiteDatabase, int, int)
* @author ricky barrette
*/
@Override
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version "+oldVersion+" to "+newVersion);
if(RingerDatabase.this.mListener != null)
RingerDatabase.this.mListener.onDatabaseUpgrade();
RingerDatabase.this.isUpgrading = true;
final Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(RingerDatabase.this.mListener != null)
RingerDatabase.this.mListener.onDatabaseUpgradeComplete();
}
};
//upgrade thread
new Thread( new Runnable(){
@Override
public void run(){
Looper.prepare();
switch(oldVersion){
case 1:
db.execSQL("ALTER TABLE " + RINGER_TABLE + " ADD "+ KEY_MUSIC_VOLUME+" INTEGER");
db.execSQL("ALTER TABLE " + RINGER_TABLE + " ADD "+ KEY_ALARM_VOLUME+" INTEGER");
case 2:
//rename the old ringer table
db.execSQL("ALTER TABLE " + RINGER_TABLE + " RENAME TO two");
//create a new ringer table
createDatabase(db);
//convert database to the new version
convert2to3(db);
//remove old tables
db.execSQL("DROP TABLE IF EXISTS two");
}
handler.sendEmptyMessage(0);
RingerDatabase.this.isUpgrading = false;
}
}).start();
}
}
/**
* Parses a string boolean from the database
* @param bool
* @return true or false
* @author ricky barrette
*/
public static boolean parseBoolean(String bool){
try {
return bool == null ? false : Integer.parseInt(bool) == 1 ? true : false;
} catch (NumberFormatException e) {
return false;
}
}
/**
* Creates a new RingerDatabase
* @param context
* @author ricky barrette
*/
public RingerDatabase(Context context){
this.mContext = context;
this.mDb = new OpenHelper(this.mContext).getWritableDatabase();
}
public RingerDatabase(Context context, DatabaseListener listener){
this.mListener = listener;
this.mContext = context;
this.mDb = new OpenHelper(this.mContext).getWritableDatabase();
}
/**
* Backs up the database
* @return true if successful
* @author ricky barrette
*/
public boolean backup(){
File dbFile = new File(Environment.getDataDirectory() + "/data/"+mContext.getPackageName()+"/databases/"+DATABASE_NAME);
File exportDir = new File(Environment.getExternalStorageDirectory(), "/"+this.mContext.getString(R.string.app_name));
if (!exportDir.exists()) {
exportDir.mkdirs();
}
File file = new File(exportDir, dbFile.getName());
try {
file.createNewFile();
this.copyFile(dbFile, file);
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* Checks to see if this ringer name is original, if not it renames it
* @param name
* @return
*/
private String checkRingerName(String name){
List<String> names = this.getAllRingerTitles();
String ringerName = name;
int count = 1;
for(int index = 0; index < names.size(); index++ ){
if(ringerName.equals(names.get(index))){
ringerName = name + count+++"";
index = 0;
}
}
return ringerName;
// return checkRingerName(name, 0);
}
/**
* Copies a file
* @param src file
* @param dst file
* @throws IOException
* @author ricky barrette
*/
private void copyFile(File src, File dst) throws IOException {
FileChannel inChannel = new FileInputStream(src).getChannel();
FileChannel outChannel = new FileOutputStream(dst).getChannel();
try {
inChannel.transferTo(0, inChannel.size(), outChannel);
} finally {
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
}
}
/**
* deletes a note by its row id
* @param id
* @author ricky barrette
*/
public void deleteRinger(final long id) {
final ProgressDialog progress = ProgressDialog.show(RingerDatabase.this.mContext, "", RingerDatabase.this.mContext.getText(R.string.deleteing), true, true);
final Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(RingerDatabase.this.mListener != null)
RingerDatabase.this.mListener.onRingerDeletionComplete();
}
};
//ringer deleting thread
new Thread( new Runnable(){
@Override
public void run(){
Looper.prepare();
/*
* get the ringer name from the id, and then delete all its information from the ringer information table
*/
RingerDatabase.this.mDb.delete(RINGER_INFO_TABLE, KEY_RINGER_NAME +" = "+ DatabaseUtils.sqlEscapeString(RingerDatabase.this.getRingerName(id)), null);
/*
* finally delete the ringer from the ringer table
*/
RingerDatabase.this.mDb.delete(RINGER_TABLE, "id = "+ id, null);
updateRowIds(id +1);
handler.sendEmptyMessage(0);
progress.dismiss();
}
}).start();
}
/**
* @return a cursor containing all ringers
* @author ricky barrette
*/
public Cursor getAllRingers(){
return this.mDb.query(RINGER_TABLE, new String[] { KEY_RINGER_NAME, KEY_IS_ENABLED, KEY_RADIUS, KEY_LOCATION_LAT, KEY_LOCATION_LON }, null, null, null, null, null);
}
/**
* returns all ringer names in the database, where or not if they are enabled
* @return list of all strings in the database table
* @author ricky barrette
*/
public List<String> getAllRingerTitles() {
List<String> list = new ArrayList<String>();
Cursor cursor = this.mDb.query(RINGER_TABLE, new String[] { KEY_RINGER_NAME }, null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
list.add(cursor.getString(0));
} while (cursor.moveToNext());
}
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
return list;
}
/**
* gets a ringer from a row id;
* @param id
* @return cursor containing the note
* @author ricky barrette
*/
public Cursor getRingerFromId(long id) {
return this.mDb.query(RINGER_TABLE, new String[]{ KEY_RINGER_NAME, KEY_IS_ENABLED, KEY_RADIUS, KEY_LOCATION_LAT, KEY_LOCATION_LON }, "id = "+id, null, null, null, null);
}
/**
* gets a ringer's info from the supplied ringer name
* @param ringerName
* @return
* @author ricky barrette
*/
public Cursor getRingerInfo(String ringerName){
return this.mDb.query(RINGER_INFO_TABLE,
new String[]{ KEY, KEY_VALUE }, KEY_RINGER_NAME +" = "+ DatabaseUtils.sqlEscapeString(ringerName), null, null, null, null);
}
/**
* Retrieves the ringer's name form the ringer table
* @param id
* @return ringer's name
* @author ricky barrette
*/
public String getRingerName(long id) {
String name = null;
Cursor cursor = this.mDb.query(RINGER_TABLE, new String[]{ KEY_RINGER_NAME }, "id = "+id, null, null, null, null);;
if (cursor.moveToFirst()) {
name = cursor.getString(0);
}
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
return name;
}
/**
* Inserts a new ringer into the database
* @param ringer values
* @param ringerInfo values
* @author ricky barrette
*/
public void insertRinger(ContentValues ringer, ContentValues ringerInfo){
ringer.put(RingerDatabase.KEY_RINGER_NAME, checkRingerName(ringer.getAsString(RingerDatabase.KEY_RINGER_NAME)));
mDb.insert(RINGER_TABLE, null, ringer);
String ringerName = ringer.getAsString(RingerDatabase.KEY_RINGER_NAME);
//insert the information values
for(Entry<String, Object> item : ringerInfo.valueSet()){
ContentValues values = new ContentValues();
values.put(KEY_RINGER_NAME, ringerName);
values.put(KEY, item.getKey());
/*
* Try get the value.
* If there is a class cast exception, try casting to the next object type.
*
* The following types are tried:
* String
* Integer
* Boolean
*/
try {
values.put(KEY_VALUE, (String) item.getValue());
} catch (ClassCastException e) {
try {
values.put(KEY_VALUE, (Boolean) item.getValue() ? 1 : 0);
} catch (ClassCastException e1) {
values.put(KEY_VALUE, (Integer) item.getValue());
}
}
mDb.insert(RINGER_INFO_TABLE, null, values);
}
}
/**
* Checks to see if a ringer is enabled
* @param row id
* @return true if the ringer is enabled
* @author ricky barrette
*/
public boolean isRingerEnabled(long id) {
Cursor cursor = this.mDb.query(RINGER_TABLE, new String[] { KEY_IS_ENABLED }, "id = "+id, null, null, null, null);
if (cursor.moveToFirst()) {
if(Debug.DEBUG)
Log.d(TAG, "isRingerEnabled("+id+") = "+ cursor.getString(0));
return parseBoolean(cursor.getString(0));
}
return false;
}
/**
* Restores the database from the sdcard
* @return true if successful
* @author ricky barrette
*/
public void restore(){
File dbFile = new File(Environment.getDataDirectory() + "/data/"+mContext.getPackageName()+"/databases/"+DATABASE_NAME);
File exportDir = new File(Environment.getExternalStorageDirectory(), "/"+this.mContext.getString(R.string.app_name));
if (!exportDir.exists()) {
exportDir.mkdirs();
}
File file = new File(exportDir, dbFile.getName());
try {
file.createNewFile();
this.copyFile(file, dbFile);
} catch (IOException e) {
e.printStackTrace();
}
/*
* close and reopen the database to upgrade it.
*/
this.mDb.close();
this.mDb = new OpenHelper(this.mContext).getWritableDatabase();
if(this.mDb.isOpen() && ! this.isUpgrading)
if(this.mListener != null)
this.mListener.onRestoreComplete();
}
public int setRingerEnabled(long id, boolean enabled) {
if(Debug.DEBUG)
Log.d(TAG, "setRingerEnabled("+id+") = "+ enabled);
ContentValues values = new ContentValues();
values.put(KEY_IS_ENABLED, enabled);
return mDb.update(RINGER_TABLE, values, "id" + "= "+ id, null);
}
/**
* updates a ringer by it's id
* @param id
* @param ringer values
* @param info values
* @author ricky barrette
*/
public void updateRinger(long id, ContentValues ringer, ContentValues info){
String ringer_name = getRingerName(id);
if(!ringer_name.equals(ringer.getAsString(RingerDatabase.KEY_RINGER_NAME)))
ringer.put(RingerDatabase.KEY_RINGER_NAME, checkRingerName(ringer.getAsString(RingerDatabase.KEY_RINGER_NAME)));
//update the information values in the info table
for(Entry<String, Object> item : info.valueSet()){
ContentValues values = new ContentValues();
values.put(KEY_RINGER_NAME, ringer.getAsString(KEY_RINGER_NAME));
values.put(KEY, item.getKey());
try {
values.put(KEY_VALUE, (String) item.getValue());
} catch (ClassCastException e) {
try {
values.put(KEY_VALUE, (Boolean) item.getValue() ? 1 : 0);
} catch (ClassCastException e1) {
values.put(KEY_VALUE, (Integer) item.getValue());
}
}
//try to update, if update fails insert
if(!(mDb.update(RINGER_INFO_TABLE, values, KEY_RINGER_NAME + "="+ DatabaseUtils.sqlEscapeString(ringer_name) +" AND " + KEY +"='"+ item.getKey()+"'", null) > 0))
mDb.insert(RINGER_INFO_TABLE, null, values);
}
//update the ringer table
mDb.update(RINGER_TABLE, ringer, "id" + "= "+ id, null);
}
/**
* Updates the row ids after a row is deleted
* @param id of the row to start with
* @author ricky barrette
*/
private void updateRowIds(long id) {
long currentRow;
ContentValues values = new ContentValues();
Cursor cursor = this.mDb.query(RINGER_TABLE, new String[] { "id" },null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
currentRow = cursor.getLong(0);
if(currentRow == id){
id++;
values.clear();
values.put("id", currentRow -1);
mDb.update(RINGER_TABLE, values, "id" + "= "+ currentRow, null);
}
} while (cursor.moveToNext());
}
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
}

View File

@@ -0,0 +1,34 @@
/**
* Debug.java
* @date Apr 29, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.debug;
/**
* A convince class containing debugging variables
* @author ricky barrette
*/
public class Debug {
/**
* Sets the logging output of this application
*/
public static final boolean DEBUG = true;
/**
* The amount of intersecting that is needed between a users accuracy radius and a ringers location radius
*/
public static final float FUDGE_FACTOR = .002f;
/**
* Drops the ringer database table every time the database is created
*/
public static boolean DROP_TABLE_EVERY_TIME = false;
/**
* Max radius that can be set by a ringer
*/
public static final int MAX_RADIUS_IN_METERS = 600;
}

View File

@@ -0,0 +1,107 @@
/**
* GetLocationWidget.java
* @date Jun 27, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.receivers;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
import com.TwentyCodes.android.LocationRinger.R;
import com.TwentyCodes.android.LocationRinger.debug.Debug;
import com.TwentyCodes.android.LocationRinger.services.LocationService;
import com.TwentyCodes.android.LocationRinger.ui.SettingsActivity;
/**
* This widget will be used to force a Location update from the users home screen
* @author ricky barrette
*/
public class GetLocationWidget extends AppWidgetProvider {
public final String TAG = "GetLocationWidget";
/**
* Called in response to the ACTION_APPWIDGET_UPDATE broadcast when this AppWidget provider is being asked to provide RemoteViews for a set of AppWidgets.
* Override this method to implement your own AppWidget functionality.
* @see android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[])
* @param context
* @param appWidgetManager
* @param appWidgetIds
* @author ricky barrette
*/
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
if (Debug.DEBUG)
Log.v(TAG, "onUpdate()");
final int N = appWidgetIds.length;
// Perform this loop procedure for each App Widget that belongs to this provider
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
Intent intent = new Intent(context, LocationService.class)
.putExtra(LocationService.INTENT_EXTRA_REQUIRED_ACCURACY, Integer.parseInt(context.getSharedPreferences(SettingsActivity.SETTINGS, Context.MODE_WORLD_READABLE).getString(SettingsActivity.ACCURACY , "50")))
.setAction(LocationReceiver.LR_ACTION_UPDATE);
//create a pending intent to start the post activity
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
// Get the layout for the App Widget and attach an on-click listener to the button
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.get_location_widget);
views.setOnClickPendingIntent(R.id.widget_get_location_button, pendingIntent);
// Tell the AppWidgetManager to perform an update on the current App Widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
/**
* Implements onReceive(Context, Intent) to dispatch calls to the various other methods on AppWidgetProvider.
* (non-Javadoc)
* @see android.appwidget.AppWidgetProvider#onReceive(android.content.Context, android.content.Intent)
* @param context
* @param intent received
* @author ricky barrette
*/
@Override
public void onReceive(Context context, Intent intent) {
if (Debug.DEBUG)
Log.v(TAG, "onReceive");
// v1.5 fix that doesn't call onDelete Action
final String action = intent.getAction();
if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
final int appWidgetId = intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
this.onDeleted(context, new int[] { appWidgetId });
}
} else {
super.onReceive(context, intent);
}
}
/**
* Called in response to the ACTION_APPWIDGET_DELETED broadcast when one or more AppWidget instances have been deleted.
* Override this method to implement your own AppWidget functionality.
* (non-Javadoc)
* @see android.appwidget.AppWidgetProvider#onDeleted(android.content.Context, int[])
* @param context
* @param appWidgetIds
* @author ricky barrette
*/
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
if (Debug.DEBUG)
Log.v(TAG, "onDelete()");
super.onDeleted(context, appWidgetIds);
}
}

View File

@@ -0,0 +1,39 @@
/**
* LocationReceiver.java
* @date Apr 29, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.receivers;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.util.Log;
import com.TwentyCodes.android.LocationRinger.debug.Debug;
import com.TwentyCodes.android.LocationRinger.services.RingerProcessingService;
import com.TwentyCodes.android.LocationRinger.ui.SettingsActivity;
/**
* This class will receive broadcast from the location service. it will wake the ringer processing service.
* @author ricky barrette
*/
public class LocationReceiver extends com.TwentyCodes.android.location.LocationReceiver {
public static final String LR_ACTION_UPDATE = "com.TwentyCodes.android.LocationRinger.action.LocationUpdate";
private static final String TAG = "LocationReceiver";
@Override
public void onLocationUpdate(Location location) {
if(location != null)
if(location.getAccuracy()<= Integer.parseInt(mContext.getSharedPreferences(SettingsActivity.SETTINGS, Context.MODE_PRIVATE).getString(SettingsActivity.IGNORE_LOCATION, "1000")))
mContext.startService(new Intent(mContext, RingerProcessingService.class).putExtra(INTENT_EXTRA_LOCATION_PARCEL, location));
else
if(Debug.DEBUG)
Log.d(TAG, "location accuracy = "+ location.getAccuracy()+" ignoring");
else
if(Debug.DEBUG)
Log.d(TAG, "location was null");
}
}

View File

@@ -0,0 +1,81 @@
/**
* SystemReceiver.java
* @date May 4, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.receivers;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Handler;
import android.util.Log;
import com.TwentyCodes.android.LocationRinger.debug.Debug;
import com.TwentyCodes.android.LocationRinger.services.LocationService;
import com.TwentyCodes.android.LocationRinger.ui.SettingsActivity;
/**
* This receiver will system events
* @author ricky barrette
*/
public class SystemReceiver extends BroadcastReceiver {
/*
* these constants are used for checking the shared_prefs
*/
private final String BATTERY_LOW = "battery_low";
private final String TAG = "SystemEventReciever";
/**
* (non-Javadoc)
* @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)
* @param context
* @param intent
* @author ricky barrette
*/
@Override
public void onReceive(Context context, Intent intent) {
if(Debug.DEBUG)
Log.d(TAG, "onReceive() ~"+intent.getAction());
SharedPreferences systemEventHistory = context.getSharedPreferences(TAG, 2);
Intent i = new Intent(context, LocationService.class)
// .putExtra(LocationService.INTENT_EXTRA_PERIOD_BETWEEN_UPDATES, (long) (60000 * Integer.parseInt(context.getSharedPreferences(SettingsActivity.SETTINGS, 2).getString(SettingsActivity.UPDATE_INTVERVAL , "10"))))
.putExtra(LocationService.INTENT_EXTRA_REQUIRED_ACCURACY, Integer.parseInt(context.getSharedPreferences(SettingsActivity.SETTINGS, 2).getString(SettingsActivity.ACCURACY , "50")))
.setAction(LocationReceiver.LR_ACTION_UPDATE);
/*
* if the phone finishes booting, then start the service if the user enabled it
*/
if(intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)){
if(context.getSharedPreferences(SettingsActivity.SETTINGS, Context.MODE_WORLD_READABLE).getBoolean(SettingsActivity.START_ON_BOOT, false))
context.startService(i);
}
/*
* if the battery is reported to be low then
* stop the service, and remove the pending alarm
* and finally record that the phone's battery was low in the shared_prefs
*/
if(intent.getAction().equals(Intent.ACTION_BATTERY_LOW)){
LocationService.stopService(context).run();
new Handler().postDelayed(LocationService.stopService(context), 30000L);
systemEventHistory.edit().putBoolean(BATTERY_LOW, true).commit();
}
/*
* if the phone is plugged in then
* check to see if the battery was reported low, if it was then
* restart the service, and remove shared_prefs entry
*/
if(intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)){
if (systemEventHistory.getBoolean(BATTERY_LOW, false)) {
systemEventHistory.edit().remove(BATTERY_LOW).commit();
context.startService(i);
}
}
}
}

View File

@@ -0,0 +1,78 @@
/**
* LocationService.java
* @date Jul 3, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.services;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import com.TwentyCodes.android.LocationRinger.LocationRinger;
import com.TwentyCodes.android.LocationRinger.R;
import com.TwentyCodes.android.LocationRinger.ui.SettingsActivity;
import com.TwentyCodes.android.SkyHook.SkyHookService;
import com.TwentyCodes.android.exception.ExceptionHandler;
/**
* We override the location service so we can attach the exception handler
* @author ricky barrette
*/
public class LocationService extends SkyHookService {
private final int GATHERING_LOCATION_ONGING_NOTIFICATION_ID = 232903877;
private SharedPreferences mSettings;
private NotificationManager mNotificationManager;
/* (non-Javadoc)
* @see com.TwentyCodes.android.SkyHook.SkyHookService#onStartCommand(android.content.Intent, int, int)
* @author ricky barrette
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
this.mPeriod = (long) (60000 * Integer.parseInt(this.mSettings.getString(SettingsActivity.UPDATE_INTVERVAL , "10")));
return super.onStartCommand(intent, flags, startId);
}
/* (non-Javadoc)
* @see com.TwentyCodes.android.SkyHook.SkyHookService#onDestroy()
* @author ricky barrette
*/
@Override
public void onDestroy() {
this.mSettings.edit().remove(SettingsActivity.IS_SERVICE_STARTED).commit();
this.mNotificationManager.cancel(this.GATHERING_LOCATION_ONGING_NOTIFICATION_ID);
super.onDestroy();
}
/* (non-Javadoc)
* @see com.TwentyCodes.android.SkyHook.SkyHookService#onCreate()
* @author ricky barrette
*/
@Override
public void onCreate() {
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this));
this.mSettings = this.getSharedPreferences(SettingsActivity.SETTINGS, Context.MODE_WORLD_WRITEABLE);
this.mSettings.edit().putBoolean(SettingsActivity.IS_SERVICE_STARTED, true).commit();
startOnGoingNotification();
super.onCreate();
}
/**
* starts a simple ongoing notification to inform the user that we are gathering location
* @author ricky barrette
*/
private void startOnGoingNotification() {
this.mNotificationManager = (NotificationManager) this.getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
Notification notifyDetails = new Notification(R.drawable.newstatusbar_icon, this.getString(R.string.app_name), System.currentTimeMillis());
PendingIntent intent = PendingIntent.getActivity(this, 0, new Intent(this, LocationRinger.class), android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
notifyDetails.setLatestEventInfo(this, this.getString(R.string.app_name), this.getString(R.string.gathering), intent);
notifyDetails.flags |= Notification.FLAG_ONGOING_EVENT;
this.mNotificationManager.notify(this.GATHERING_LOCATION_ONGING_NOTIFICATION_ID, notifyDetails);
}
}

View File

@@ -0,0 +1,425 @@
/**
* RingerProcessingService.java
* @date Apr 29, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.services;
import java.util.Calendar;
import java.util.Map.Entry;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.location.Location;
import android.media.AudioManager;
import android.media.RingtoneManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import android.widget.Toast;
import com.TwentyCodes.android.LocationRinger.db.RingerDatabase;
import com.TwentyCodes.android.LocationRinger.debug.Debug;
import com.TwentyCodes.android.LocationRinger.receivers.LocationReceiver;
import com.TwentyCodes.android.LocationRinger.ui.SettingsActivity;
import com.TwentyCodes.android.exception.ExceptionHandler;
import com.TwentyCodes.android.location.GeoUtils;
import com.google.android.maps.GeoPoint;
/**
* This service will handle processing the users location and the ringers
* @author ricky barrette
*/
public class RingerProcessingService extends Service {
private static final String TAG = "RingerProcessingService";
private int mStartId;
private Location mLocation;
private RingerDatabase mDb;
private WakeLock mWakeLock;
private AudioManager mAudioManager;
private SharedPreferences mSettings;
private WifiManager mWifiManager;
private BluetoothAdapter mBluetoothAdapter;
/**
* Applies a ringers options to the current system settings
* @param id
* @author ricky barrette
*/
private void applyRinger(ContentValues values) {
if(Debug.DEBUG)
Log.d(TAG, "applyRigner()");
String name = values.getAsString(RingerDatabase.KEY_RINGER_NAME);
/*
* Make it toasty if the user wants to be notified.
* This will display a toast msg "Applying <ringer name>"
*/
if(this.getSharedPreferences(SettingsActivity.SETTINGS, 2).getBoolean(SettingsActivity.TOASTY, false))
Toast.makeText(this.getApplicationContext(), "Applying "+ name, Toast.LENGTH_SHORT).show();
/*
* We need to null check all the value except ring/notification tone uri's and boolean values.
*/
/*
* ringtone & volume
* if the ringtone is set to silent we want to set the volume to 0
*/
if(values.containsKey(RingerDatabase.KEY_RINGTONE_IS_SILENT)){
Log.d(TAG, "Ringtone: "+ applyRingtone(RingtoneManager.TYPE_RINGTONE, RingerDatabase.parseBoolean(values.getAsString(RingerDatabase.KEY_RINGTONE_IS_SILENT)), values.getAsString(RingerDatabase.KEY_RINGTONE_URI)));
if(RingerDatabase.parseBoolean(values.getAsString(RingerDatabase.KEY_RINGTONE_IS_SILENT)))
setStreamVolume(0, AudioManager.STREAM_RING);
else
if(values.get(RingerDatabase.KEY_RINGTONE_VOLUME) != null)
setStreamVolume(values.getAsInteger(RingerDatabase.KEY_RINGTONE_VOLUME), AudioManager.STREAM_RING);
}
/*
* notification ringtone & volume
* if the notification ringtone is silent, we want to set the volume to 0
*/
if(values.containsKey(RingerDatabase.KEY_NOTIFICATION_IS_SILENT)){
Log.d(TAG, "Notification Ringtone: "+ applyRingtone(RingtoneManager.TYPE_NOTIFICATION, RingerDatabase.parseBoolean(values.getAsString(RingerDatabase.KEY_NOTIFICATION_IS_SILENT)), values.getAsString(RingerDatabase.KEY_NOTIFICATION_RINGTONE_URI)));
if(RingerDatabase.parseBoolean(values.getAsString(RingerDatabase.KEY_NOTIFICATION_IS_SILENT)))
setStreamVolume(0, AudioManager.STREAM_NOTIFICATION);
else
if(values.get(RingerDatabase.KEY_NOTIFICATION_RINGTONE_VOLUME) != null)
setStreamVolume(values.getAsInteger(RingerDatabase.KEY_NOTIFICATION_RINGTONE_VOLUME), AudioManager.STREAM_NOTIFICATION);
}
if(Debug.DEBUG){
Log.d(TAG, "Music "+ (mAudioManager.isMusicActive() ? "is playing " : "is not playing"));
Log.d(TAG, "Wired Headset "+ (mAudioManager.isWiredHeadsetOn() ? "is on " : "is off"));
}
/*
* music volume
* we will set the music volume only if music is not playing, and there is no wired head set
*/
if(values.containsKey(RingerDatabase.KEY_MUSIC_VOLUME))
if(values.get(RingerDatabase.KEY_MUSIC_VOLUME) != null)
if(! mAudioManager.isMusicActive())
if(! mAudioManager.isWiredHeadsetOn())
setStreamVolume(values.getAsInteger(RingerDatabase.KEY_MUSIC_VOLUME), AudioManager.STREAM_MUSIC);
/*
* alarm volume
* we will set the alarm volume only if music is not playing, and there is no wired head set
*/
if(values.containsKey(RingerDatabase.KEY_ALARM_VOLUME))
if(values.get(RingerDatabase.KEY_ALARM_VOLUME) != null)
if(! mAudioManager.isMusicActive())
if(! mAudioManager.isWiredHeadsetOn())
setStreamVolume(values.getAsInteger(RingerDatabase.KEY_ALARM_VOLUME), AudioManager.STREAM_ALARM);
/*
* wifi & bluetooth
*/
if(values.containsKey(RingerDatabase.KEY_WIFI))
if(mWifiManager != null)
mWifiManager.setWifiEnabled(RingerDatabase.parseBoolean(values.getAsString(RingerDatabase.KEY_WIFI)));
if(values.containsKey(RingerDatabase.KEY_BT))
if(mBluetoothAdapter != null)
if(RingerDatabase.parseBoolean(values.getAsString(RingerDatabase.KEY_BT)))
mBluetoothAdapter.enable();
else
mBluetoothAdapter.disable();
/*
* update interval
*/
if(values.containsKey(RingerDatabase.KEY_UPDATE_INTERVAL))
if (values.get(RingerDatabase.KEY_UPDATE_INTERVAL) != null){
Intent i = new Intent(this, LocationService.class)
.putExtra(LocationService.INTENT_EXTRA_REQUIRED_ACCURACY, Integer.parseInt(this.getSharedPreferences(SettingsActivity.SETTINGS, 2).getString(SettingsActivity.ACCURACY , "50")))
.setAction(LocationReceiver.LR_ACTION_UPDATE);
PendingIntent pi = PendingIntent.getService(this, LocationService.REQUEST_CODE, i, 0);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
/*
* cancel the existing schedule
*/
am.cancel(pi);
/*
* reschedule the location service
*/
am.set(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis() + (long) (60000 * Integer.parseInt(values.getAsString(RingerDatabase.KEY_UPDATE_INTERVAL))), pi);
}
}
/**
* Apply the ring tone
* @param stream audio stream to apply to
* @param isSilent true if silent
* @param uri of ringtone, if null silent will be applied
* @return string uri of applied ringtone, null if silent was applied
* @author ricky barrette
*/
private String applyRingtone(int type, boolean isSilent, String uri) {
String ringtoneURI = null;
if(isSilent){
if(Debug.DEBUG)
Log.d(TAG, "Ringtone was set to silent ");
} else
ringtoneURI = uri;
RingtoneManager.setActualDefaultRingtoneUri(this, type, ringtoneURI == null ? null : Uri.parse(ringtoneURI));
return uri;
}
// /**
// * Backs up the current settings into the database to be re applied as default
// * @author ricky barrette
// */
// private void backup() {
//
// if(Debug.DEBUG)
// Log.d(TAG, "backup()");
//
// ContentValues ringer = new ContentValues();
// ContentValues info = new ContentValues();
//
// /*
// * package the ringer table information
// */
// ringer.put(RingerDatabase.KEY_RINGER_NAME, DEFAULT_RINGER);
//
// /*
// * package the ringer_info table information
// */
// info.put(RingerDatabase.KEY_RINGTONE_IS_SILENT, mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT ? true : false);
// info.put(RingerDatabase.KEY_RINGTONE_URI, RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_RINGTONE).toString());
// info.put(RingerDatabase.KEY_NOTIFICATION_IS_SILENT, mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT ? true : false);
// info.put(RingerDatabase.KEY_NOTIFICATION_RINGTONE_URI, RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_NOTIFICATION).toString());
// info.put(RingerDatabase.KEY_RINGTONE_VOLUME, mAudioManager.getStreamVolume(AudioManager.STREAM_RING));
// info.put(RingerDatabase.KEY_NOTIFICATION_RINGTONE_VOLUME, mAudioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION));
// info.put(RingerDatabase.KEY_MUSIC_VOLUME, mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
// info.put(RingerDatabase.KEY_ALARM_VOLUME, mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM));
// info.put(RingerDatabase.KEY_UPDATE_INTERVAL, this.mSettings.getString(SettingsActivity.SETTINGS, "10"));
//
// if(this.mBluetoothAdapter != null)
// info.put(RingerDatabase.KEY_BT, this.mBluetoothAdapter.isEnabled());
//
// if(this.mWifiManager != null)
// info.put(RingerDatabase.KEY_WIFI, this.mWifiManager.isWifiEnabled());
//
// this.mDb.updateRinger(1, ringer, info);
// }
/* (non-Javadoc)
* @see android.app.Service#onBind(android.content.Intent)
* @author ricky barrette
*/
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
/**
* Called when the service is first created
* @author ricky barrette
*/
@Override
public void onCreate() {
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this));
if(Debug.DEBUG)
Log.d(TAG, "onCreate()");
super.onCreate();
this.mDb = new RingerDatabase(this);
this.mSettings = this.getSharedPreferences(SettingsActivity.SETTINGS, Context.MODE_WORLD_WRITEABLE);
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
this.mWakeLock = (WakeLock) pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
this.mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
this.mWifiManager = (WifiManager) this.getSystemService(WIFI_SERVICE);
this.mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
this.mWakeLock.acquire();
}
@Override
public void onDestroy() {
if(mWakeLock.isHeld())
mWakeLock.release();
System.gc();
super.onDestroy();
}
/**
* Called when the service is first started
* @param intent
* @param flags
* @param startId
* @author ricky barrette
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(Debug.DEBUG)
Log.d(TAG, "onStartCommand: "+startId);
this.mStartId = startId;
/*
* try to sleep so skyhook doesn't cock block us
*/
try {
Thread.sleep(1000l);
} catch (InterruptedException e) {
e.printStackTrace();
}
// //if this is the first time the service ever starts, then back up the current settings to create a back up
// if(this.mSettings.getBoolean(SettingsActivity.IS_FIRST_RINGER_PROCESSING, true)){
// backup();
// this.mSettings.edit().putBoolean(SettingsActivity.IS_FIRST_RINGER_PROCESSING, false).commit();
// }
//
// //if the default ringer is the currently applied ringer back up the current settings
// if(this.mSettings.getBoolean(SettingsActivity.IS_DEFAULT, false)){
// backup();
// }
if(intent.getParcelableExtra(LocationReceiver.INTENT_EXTRA_LOCATION_PARCEL) != null){
this.mLocation = intent.getParcelableExtra(LocationReceiver.INTENT_EXTRA_LOCATION_PARCEL);
processRingers();
}else if(Debug.DEBUG)
Log.d(TAG, "Location was null");
return super.onStartCommand(intent, flags, startId);
}
/**
* Processes the ringer database for applicable ringers
* @author ricky barrette
*/
private void processRingers() {
long index = 1;
boolean isDeafult = true;
/*
* get the default ringer information
*/
ContentValues ringer = getRinger(1);
GeoPoint point = new GeoPoint((int) (mLocation.getLatitude() * 1E6), (int) (mLocation.getLongitude()*1E6));
if(Debug.DEBUG){
Log.d(TAG, "Processing ringers");
Log.d(TAG, "Current location "+(int) (mLocation.getLatitude() * 1E6)+", "+(int) (mLocation.getLongitude() * 1E6)+" @ "+ new Float(mLocation.getAccuracy()) / 1000+"km");
}
Cursor c = mDb.getAllRingers();
c.moveToFirst();
if (c.moveToFirst()) {
do {
if(Debug.DEBUG)
Log.d(TAG, "Checking ringer "+c.getString(0)+" "+c.getInt(3)+", "+c.getInt(4)+" @ "+ c.getInt(2) +"m");
if(RingerDatabase.parseBoolean(c.getString(1)))
if(GeoUtils.isIntersecting(point, new Float(mLocation.getAccuracy()) / 1000, new GeoPoint(c.getInt(3), c.getInt(4)), new Float(c.getInt(2)) / 1000, Debug.FUDGE_FACTOR)){
c.close();
getRinger(ringer, index);
isDeafult = false;
//break loop, we will only apply the first applicable ringer
break;
}
index++;
} while (c.moveToNext());
}
c.close();
if(Debug.DEBUG)
for(Entry<String,Object> item : ringer.valueSet())
Log.d(TAG, item.getKey());
applyRinger(ringer);
if(Debug.DEBUG)
Log.d(TAG, "Finished processing ringers");
//store is default
this.mSettings.edit().putBoolean(SettingsActivity.IS_DEFAULT, isDeafult).commit();
this.stopSelf(mStartId);
}
/**
* appends the new ringer's information in content values
* @param id
* @return
*/
private ContentValues getRinger(ContentValues values, long id) {
String name = this.mDb.getRingerName(id);
values.put(RingerDatabase.KEY_RINGER_NAME, name);
/*
* get the ringer's info, and parse it into content values
*/
Cursor c = this.mDb.getRingerInfo(name);
if (c.moveToFirst()) {
do {
values.put(c.getString(0), c.getString(1));
} while (c.moveToNext());
}
if (c != null && !c.isClosed()) {
c.close();
}
return values;
}
/**
* returns all the ringers information as content values
* @param id
* @return
*/
private ContentValues getRinger(long id) {
return getRinger(new ContentValues(), id);
}
/**
* set the volume of a particular stream
* @param volume
* @param stream
* @author ricky barrette
*/
private void setStreamVolume(int volume, int stream) {
/*
* if the seek bar is set to a value that is higher than what the the stream value is set for
* then subtract the seek bar's value from the current volume of the stream, and then
* raise the stream by that many times
*/
if (volume > mAudioManager.getStreamVolume(stream)) {
int adjust = volume - mAudioManager.getStreamVolume(stream);
for (int i = 0; i < adjust; i++) {
mAudioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE, stream, 0);
}
}
/*
* if the seek bar is set to a value that is lower than what the the stream value is set for
* then subtract the current volume of the stream from the seek bar's value, and then
* lower the stream by that many times
*/
if (volume < mAudioManager.getStreamVolume(stream)) {
int adjust = mAudioManager.getStreamVolume(stream) - volume;
for (int i = 0; i < adjust; i++) {
mAudioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER, stream, 0);
}
}
}
}

View File

@@ -0,0 +1,78 @@
/**
* FirstBootDialog.java
* @date Jul 6, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.ui;
import com.TwentyCodes.android.LocationRinger.R;
import android.app.Dialog;
import android.content.Context;
import android.view.View;
import android.view.Window;
/**
* This class will be used to display the first boot dialog
* @author ricky barrette
*/
public class FirstBootDialog extends Dialog implements android.view.View.OnClickListener {
/**
* Creates a new FirstBootDialog
* @param context
* @author ricky barrette
*/
public FirstBootDialog(Context context) {
super(context);
build(context);
}
/**
* Creates a new FirstBootDialog
* @param context
* @param theme
* @author ricky barrette
*/
public FirstBootDialog(Context context, int theme) {
super(context, theme);
build(context);
}
/**
* Creates a new FirstBootDialog
* @param context
* @param cancelable
* @param cancelListener
* @author ricky barrette
*/
public FirstBootDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
build(context);
}
/**
* Builds the dialog
* @param context
* @author ricky barrette
*/
private void build(Context context) {
this.requestWindowFeature(Window.FEATURE_LEFT_ICON);
this.setContentView(R.layout.first_boot_dialog);
this.setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, R.drawable.icon);
this.setTitle(R.string.welcome);
this.findViewById(R.id.ok_button).setOnClickListener(this);
}
/**
* called when the ok button is clicked
*/
@Override
public void onClick(View arg0) {
this.getContext().getSharedPreferences(SettingsActivity.SETTINGS, Context.MODE_WORLD_WRITEABLE).edit().putBoolean(SettingsActivity.IS_FIRST_BOOT, false).commit();
this.dismiss();
}
}

View File

@@ -0,0 +1,150 @@
/**
* @author Twenty Codes
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.ui;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Point;
import android.graphics.RectF;
import com.TwentyCodes.android.location.GeoUtils;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
import com.google.android.maps.Projection;
/**
* This class will used to draw a radius of a specified size in a specified location, then inserted into
* an overlay list to be displayed a map
* @author ricky barrette
*/
public class RadiusOverlay extends Overlay{
public OverlayItem mOverlayItem;
private GeoPoint mPoint;
private float mRadius = 0;
private int mColor = Color.GREEN;
private GeoPoint mRadiusPoint;
/**
* Creates a new RadiusOverlay
* @author ricky barrette
*/
public RadiusOverlay(){
}
/**
* Creates a new RadiusOverlay object that can be inserted into an overlay list.
* @param point center of radius geopoint
* @param radius radius in meters
* @param color desired color of the radius from Color API
* @author ricky barrette
*/
public RadiusOverlay(GeoPoint point, float radius, int color) {
mPoint = point;
mRadius = radius;
mColor = color;
}
/**
* draws a specific radius on the mapview that is handed to it
* @param canvas canvas to be drawn on
* @param mapView
* @param shadow
* @param when
*/
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow){
if(mPoint != null){
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 and
* convert the given GeoPoint and leftGeo to onscreen pixel coordinates,
* relative to the top-left of the MapView that provided this Projection.
*/
mRadiusPoint = GeoUtils.distanceFrom(mPoint , mRadius);
projection.toPixels(mRadiusPoint, left);
projection.toPixels(mPoint, 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 circle on the map
*/
paint.setAntiAlias(true);
paint.setStrokeWidth(2.0f);
paint.setColor(mColor);
paint.setStyle(Style.STROKE);
canvas.drawCircle(center.x, center.y, circleRadius, paint);
//draw a dot over the geopoint
RectF oval = new RectF(center.x - 2, center.y - 2, center.x + 2, center.y + 2);
canvas.drawOval(oval, paint);
//fill the radius with a nice green
paint.setAlpha(25);
paint.setStyle(Style.FILL);
canvas.drawCircle(center.x, center.y, circleRadius, paint);
}
}
/**
* @return the selected location
* @author ricky barrette
*/
public GeoPoint getLocation(){
return mPoint;
}
@Override
public boolean onTap(GeoPoint p, MapView mapView) {
mPoint = p;
return super.onTap(p, mapView);
}
/**
* @param color
* @author ricky barrette
*/
public void setColor(int color){
mColor = color;
}
/**
* @param location
* @author ricky barrette
*/
public void setLocation(GeoPoint location){
mPoint = location;
}
/**
* @param radius in meters
* @author ricky barrette
* @param radius
*/
public void setRadius(int radius){
mRadius = radius;
}
public int getZoomLevel() {
// GeoUtils.GeoUtils.distanceFrom(mPoint , mRadius)
return 0;
}
}

View File

@@ -0,0 +1,700 @@
/**
* RingeInformationActivity.java
* @date Apr 29, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.ui;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Looper;
import android.util.Log;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Spinner;
import android.widget.Toast;
import android.widget.ToggleButton;
import com.TwentyCodes.android.LocationRinger.LocationSelectedListener;
import com.TwentyCodes.android.LocationRinger.R;
import com.TwentyCodes.android.LocationRinger.db.RingerDatabase;
import com.TwentyCodes.android.LocationRinger.debug.Debug;
import com.TwentyCodes.android.SkyHook.SkyHook;
import com.TwentyCodes.android.location.GeoPointLocationListener;
import com.TwentyCodes.android.location.MapView;
import com.google.android.maps.GeoPoint;
/**
* This activity will be used to display all the ringers information, and handle modification to that information
* @author ricky barrette
*/
public class RingerInformationActivity extends com.google.android.maps.MapActivity implements OnCheckedChangeListener, OnClickListener, OnSeekBarChangeListener, GeoPointLocationListener, LocationSelectedListener {
public static final String KEY_ROWID = "row_id";
private static final int SAVE_ID = 0;
private static final String TAG = "RingerInformationActivity";
private static final int ADD_ID = 1;
private SeekBar mRingtonVolume;
private SeekBar mRadius;
private SeekBar mNotificationRingtoneVolume;
private MapView mMapView;
private EditText mNotificationRingtone;
private EditText mRingerName;
private EditText mRingtone;
private ToggleButton mNotificationRingtoneToggle;
private ToggleButton mRingerToggle;
private ToggleButton mRingtoneToggle;
private ScrollView mScrollView;
private String mRingtoneURI;
private String mNotificationRingtoneURI;
private ToggleButton mMapEditToggle;
private RadiusOverlay mRadiusOverlay;
private long mRowID;
private ToggleButton mWifiToggle;
private ToggleButton mBTToggle;
private GeoPoint mPoint;
private SeekBar mAlarmVolume;
private ProgressBar mMusicVolume;
private SkyHook mSkyHook;
private ProgressDialog mGpsProgress;
private boolean isFirstFix;
private void addFeature(int item) {
String feature = this.getResources().getStringArray(R.array.features)[item];
if(feature.equals(this.getString(R.string.ringtone))){
findViewById(R.id.ringtone_info).setVisibility(View.VISIBLE);
}
if(feature.equals(this.getString(R.string.notification_ringtone))){
findViewById(R.id.notification_ringtone_info).setVisibility(View.VISIBLE);
}
if(feature.equals(this.getString(R.string.alarm_volume))){
findViewById(R.id.alarm_volume_info).setVisibility(View.VISIBLE);
}
if(feature.equals(this.getString(R.string.music_volume))){
findViewById(R.id.music_volume_info).setVisibility(View.VISIBLE);
}
if(feature.equals(this.getString(R.string.bluetooth))){
findViewById(R.id.bluetooth_toggle).setVisibility(View.VISIBLE);
}
if(feature.equals(this.getString(R.string.wifi))){
findViewById(R.id.wifi_toggle).setVisibility(View.VISIBLE);
}
if(feature.equals(this.getString(R.string.update_interval))){
findViewById(R.id.update_interval_info).setVisibility(View.VISIBLE);
}
if(this.mBTToggle.isShown() || this.mWifiToggle.isShown())
findViewById(R.id.data_label).setVisibility(View.VISIBLE);
}
/**
* Will display a prompt asking for what feature to add.
* @author ricky
*/
private void displayFeaturesDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(this.getText(R.string.add_feature));
builder.setItems(R.array.features, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
addFeature(item);
}
});
AlertDialog alert = builder.create();
alert.show();
}
/**
* starts the ringtone picker
* @param ringtoneCode RingtoneManager.TYPE_?
* @param uri of current tone
* @author ricky barrette
*/
private void getRingtoneURI(int ringtoneCode, String uri){
Intent intent = new Intent( RingtoneManager.ACTION_RINGTONE_PICKER);
intent.putExtra( RingtoneManager.EXTRA_RINGTONE_TYPE, ringtoneCode);
intent.putExtra( RingtoneManager.EXTRA_RINGTONE_TITLE, "Select Tone");
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false);
if( uri == null)
try {
uri = RingtoneManager.getActualDefaultRingtoneUri(this, ringtoneCode).toString();
} catch (NullPointerException e) {
e.printStackTrace();
}
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, uri == null ? null : Uri.parse(uri));
startActivityForResult( intent, ringtoneCode);
}
@Override
protected boolean isRouteDisplayed() {
//UNUSED
return false;
}
/**
* Called when the rintone picker activity returns it's result
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case RingtoneManager.TYPE_RINGTONE:
this.mRingtoneURI = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI).toString();
Ringtone ringtone = RingtoneManager.getRingtone(this, Uri.parse(this.mRingtoneURI));
this.mRingtone.setText(ringtone == null ? "Silent" : ringtone.getTitle(this));
break;
case RingtoneManager.TYPE_NOTIFICATION:
this.mNotificationRingtoneURI = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI).toString();
Ringtone notificationTone = RingtoneManager.getRingtone(this, Uri.parse(this.mNotificationRingtoneURI));
this.mNotificationRingtone.setText(notificationTone == null ? "Silent" : notificationTone.getTitle(this));
break;
}
}
}
/**
* Called when a toggle button's state is changed
* @author ricky barrette
*/
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
switch(buttonView.getId()){
case R.id.ringer_toggle:
this.mRadius.setEnabled(isChecked);
this.mRingtone.setEnabled(isChecked);
this.mRingtonVolume.setEnabled(isChecked);
this.mNotificationRingtone.setEnabled(isChecked);
this.mNotificationRingtoneVolume.setEnabled(isChecked);
this.mNotificationRingtoneToggle.setEnabled(isChecked);
this.mMapView.setEnabled(isChecked);
this.mNotificationRingtoneToggle.setEnabled(isChecked);
this.mRingtoneToggle.setEnabled(isChecked);
this.mMapEditToggle.setEnabled(isChecked);
break;
case R.id.notification_silent_toggle:
this.mNotificationRingtone.setEnabled(!isChecked);
this.mNotificationRingtoneVolume.setEnabled(!isChecked);
break;
case R.id.ringtone_silent_toggle:
this.mRingtone.setEnabled(!isChecked);
this.mRingtonVolume.setEnabled(!isChecked);
break;
case R.id.map_edit_toggle:
this.isFirstFix = isChecked;
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT,
isChecked
? (this.getResources().getDisplayMetrics().heightPixels - findViewById(R.id.map_controls).getHeight())
: (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 350, getResources().getDisplayMetrics())));
if(isChecked){
this.mSkyHook.getUpdates();
params.addRule(RelativeLayout.ALIGN_PARENT_TOP );
this.mGpsProgress = ProgressDialog.show(this, "", this.getText(R.string.gps_fix), true, true);
} else {
this.mSkyHook.removeUpdates();
params.addRule(RelativeLayout.BELOW, R.id.info);
params.addRule(RelativeLayout.ALIGN_BOTTOM );
if(this.mGpsProgress != null)
this.mGpsProgress.dismiss();
}
findViewById(R.id.map_info).setLayoutParams(params );
this.mMapView.setDoubleTapZoonEnabled(isChecked);
//views
findViewById(R.id.info).setVisibility(isChecked ? View.GONE : View.VISIBLE);
findViewById(R.id.ringer_options).setVisibility(isChecked ? View.GONE : View.VISIBLE);
//buttons
findViewById(R.id.mark_my_location).setVisibility(isChecked ? View.VISIBLE : View.GONE);
findViewById(R.id.my_location).setVisibility(isChecked ? View.VISIBLE : View.GONE);
findViewById(R.id.map_mode).setVisibility(isChecked ? View.VISIBLE : View.GONE);
findViewById(R.id.search).setVisibility(isChecked ? View.VISIBLE : View.GONE);
findViewById(R.id.add_feature_button).setVisibility(isChecked ? View.GONE : View.VISIBLE);
this.mScrollView.invalidate();
this.mScrollView.setScrollEnabled(! isChecked);
this.mMapView.setBuiltInZoomControls(isChecked);
this.mMapView.setClickable(isChecked);
this.mRadius.setEnabled(isChecked);
Toast.makeText(this, isChecked ? getString(R.string.map_editing_enabled) : getString(R.string.map_editiing_disabled), Toast.LENGTH_SHORT).show();
break;
}
}
/**
* Called when a view is clicked
* @author ricky barrette
*/
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.notification_ringtone_button:
getRingtoneURI(RingtoneManager.TYPE_NOTIFICATION, mNotificationRingtoneURI);
break;
case R.id.ringtone_button:
getRingtoneURI(RingtoneManager.TYPE_RINGTONE, mRingtoneURI);
break;
case R.id.save_ringer_button:
save();
break;
case R.id.mark_my_location:
if(this.mPoint != null){
this.mRadiusOverlay.setLocation(mPoint);
this.mMapView.getController().setCenter(mPoint);
}
break;
case R.id.my_location:
if(this.mPoint != null)
this.mMapView.getController().setCenter(mPoint);
break;
case R.id.map_mode:
this.mMapView.setSatellite(mMapView.isSatellite() ? false : true);
break;
case R.id.search:
new SearchDialog(this, this).show();
break;
case R.id.add_feature_button:
findViewById(R.id.add_a_feature_label).setVisibility(View.GONE);
displayFeaturesDialog();
break;
}
}
/**
* Called when the acivity is first created
* @author ricky barrette
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
/*
* TODO
* Check to see if wifi is available
* check to see if bluetooth is available,
* remove unavailable options
*/
super.onCreate(savedInstanceState);
this.setContentView(R.layout.ringer_info);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
AudioManager mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
this.mSkyHook = new SkyHook(this);
this.mSkyHook.setLocationListener(this);
this.mScrollView = (ScrollView) findViewById(R.id.scrollview);
this.mRingerName = (EditText) findViewById(R.id.ringer_name);
this.mRingerToggle = (ToggleButton) findViewById(R.id.ringer_toggle);
this.mRingerToggle.setChecked(true);
this.mRingerToggle.setOnCheckedChangeListener(this);
this.mMapView = (MapView) findViewById(R.id.mapview);
this.mRadius = (SeekBar) findViewById(R.id.radius);
this.mRadius.setMax(Debug.MAX_RADIUS_IN_METERS);
this.mMapView.setClickable(false);
this.mMapEditToggle = (ToggleButton) findViewById(R.id.map_edit_toggle);
this.mMapEditToggle.setChecked(false);
this.mMapEditToggle.setOnCheckedChangeListener(this);
this.mRadiusOverlay = new RadiusOverlay();
this.mRadius.setOnSeekBarChangeListener(this);
this.mMapView.getOverlays().add(mRadiusOverlay);
this.mRadius.setEnabled(false);
this.mRingtone = (EditText) findViewById(R.id.ringtone);
this.mRingtoneToggle = (ToggleButton) findViewById(R.id.ringtone_silent_toggle);
this.mRingtonVolume = (SeekBar) findViewById(R.id.ringtone_volume);
this.mRingtonVolume.setMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_RING));
this.mRingtonVolume.setProgress(mAudioManager.getStreamVolume(AudioManager.STREAM_RING));
this.mRingtoneToggle.setChecked(mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT ? true : false);
this.mRingtoneToggle.setOnCheckedChangeListener(this);
this.mRingtone.setEnabled(! mRingtoneToggle.isChecked());
this.mRingtonVolume.setEnabled(! mRingtoneToggle.isChecked());
this.mRingtone.setClickable(true);
this.mNotificationRingtone = (EditText) findViewById(R.id.notification_ringtone);
this.mNotificationRingtoneVolume = (SeekBar) findViewById(R.id.notification_ringtone_volume);
this.mNotificationRingtoneToggle = (ToggleButton) findViewById(R.id.notification_silent_toggle);
this.mNotificationRingtoneVolume.setMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION));
this.mNotificationRingtoneVolume.setProgress(mAudioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION));
this.mNotificationRingtoneToggle.setOnCheckedChangeListener(this);
this.mNotificationRingtoneToggle.setChecked(mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT ? true : false);
this.mNotificationRingtone.setEnabled(! mNotificationRingtoneToggle.isChecked());
this.mNotificationRingtoneVolume.setEnabled(! mNotificationRingtoneToggle.isChecked());
this.mNotificationRingtone.setClickable(true);
this.mMusicVolume = (SeekBar) findViewById(R.id.music_volume);
this.mMusicVolume.setMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC));
this.mMusicVolume.setProgress(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
this.mAlarmVolume = (SeekBar) findViewById(R.id.alarm_volume);
this.mAlarmVolume.setMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_ALARM));
this.mAlarmVolume.setProgress(mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM));
this.mWifiToggle = (ToggleButton) findViewById(R.id.wifi_toggle);
this.mBTToggle = (ToggleButton) findViewById(R.id.bluetooth_toggle);
findViewById(R.id.ringtone_button).setOnClickListener(this);
findViewById(R.id.notification_ringtone_button).setOnClickListener(this);
findViewById(R.id.save_ringer_button).setOnClickListener(this);
findViewById(R.id.mark_my_location).setOnClickListener(this);
findViewById(R.id.my_location).setOnClickListener(this);
findViewById(R.id.map_mode).setOnClickListener(this);
findViewById(R.id.search).setOnClickListener(this);
findViewById(R.id.add_feature_button).setOnClickListener(this);
try {
this.mRingtoneURI = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_RINGTONE).toString();
this.mRingtone.setText(RingtoneManager.getRingtone(this, Uri.parse(mRingtoneURI)).getTitle(this));
} catch (NullPointerException e) {
e.printStackTrace();
this.mRingtoneToggle.setChecked(true);
}
try {
this.mNotificationRingtoneURI = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_NOTIFICATION).toString();
this.mNotificationRingtone.setText(RingtoneManager.getRingtone(this, Uri.parse(mNotificationRingtoneURI)).getTitle(this));
} catch (NullPointerException e) {
e.printStackTrace();
this.mNotificationRingtoneToggle.setChecked(true);
}
Intent data = this.getIntent();
if(data.hasExtra(KEY_ROWID)){
this.mRowID = data.getLongExtra(KEY_ROWID, 0);
this.mRingerToggle.setChecked(data.getBooleanExtra(RingerDatabase.KEY_IS_ENABLED, true));
this.mRadiusOverlay.setLocation(new GeoPoint(data.getIntExtra(RingerDatabase.KEY_LOCATION_LAT, 0), data.getIntExtra(RingerDatabase.KEY_LOCATION_LON, 0)));
this.mRadius.setProgress(data.getIntExtra(RingerDatabase.KEY_RADIUS, 0));
this.mRingerName.setText(data.getStringExtra(RingerDatabase.KEY_RINGER_NAME));
this.setTitle(getString(R.string.editing)+" "+mRingerName.getText().toString());
/*
* We need to null check all the values
*/
ContentValues info = (ContentValues) data.getParcelableExtra(RingerListActivity.KEY_INFO);
if(RingerDatabase.parseBoolean(info.getAsString(RingerDatabase.KEY_PLUS_BUTTON_HINT)));
findViewById(R.id.add_a_feature_label).setVisibility(View.GONE);
if (info.get(RingerDatabase.KEY_NOTIFICATION_IS_SILENT) != null){
this.mNotificationRingtoneToggle.setChecked(RingerDatabase.parseBoolean(info.getAsString(RingerDatabase.KEY_NOTIFICATION_IS_SILENT)));
findViewById(R.id.notification_ringtone_info).setVisibility(View.VISIBLE);
}
if (info.get(RingerDatabase.KEY_NOTIFICATION_RINGTONE) != null){
this.mNotificationRingtone.setText(info.getAsString(RingerDatabase.KEY_NOTIFICATION_RINGTONE));
findViewById(R.id.notification_ringtone_info).setVisibility(View.VISIBLE);
}
if (info.get(RingerDatabase.KEY_NOTIFICATION_RINGTONE_URI) != null)
this.mNotificationRingtoneURI = info.getAsString(RingerDatabase.KEY_NOTIFICATION_RINGTONE_URI);
if (info.get(RingerDatabase.KEY_RINGTONE) != null){
findViewById(R.id.ringtone_info).setVisibility(View.VISIBLE);
this.mRingtone.setText(info.getAsString(RingerDatabase.KEY_RINGTONE));
}
if (info.get(RingerDatabase.KEY_RINGTONE_IS_SILENT) != null) {
this.mRingtoneToggle.setChecked(RingerDatabase.parseBoolean(info.getAsString(RingerDatabase.KEY_RINGTONE_IS_SILENT)));
findViewById(R.id.ringtone_info).setVisibility(View.VISIBLE);
}
if (info.get(RingerDatabase.KEY_RINGTONE_URI) != null)
this.mRingtoneURI = info.getAsString(RingerDatabase.KEY_RINGTONE_URI);
if (info.get(RingerDatabase.KEY_WIFI) != null){
this.mWifiToggle.setChecked(RingerDatabase.parseBoolean(info.getAsString(RingerDatabase.KEY_WIFI)));
findViewById(R.id.wifi_toggle).setVisibility(View.VISIBLE);
findViewById(R.id.data_label).setVisibility(View.VISIBLE);
}
if (info.get(RingerDatabase.KEY_BT) != null){
this.mBTToggle.setChecked(RingerDatabase.parseBoolean(info.getAsString(RingerDatabase.KEY_BT)));
findViewById(R.id.bluetooth_toggle).setVisibility(View.VISIBLE);
findViewById(R.id.data_label).setVisibility(View.VISIBLE);
}
if (info.get(RingerDatabase.KEY_NOTIFICATION_RINGTONE_VOLUME) != null)
this.mNotificationRingtoneVolume.setProgress(info.getAsInteger(RingerDatabase.KEY_NOTIFICATION_RINGTONE_VOLUME));
if (info.get(RingerDatabase.KEY_RINGTONE_VOLUME) != null)
this.mRingtonVolume.setProgress(info.getAsInteger(RingerDatabase.KEY_RINGTONE_VOLUME));
if (info.get(RingerDatabase.KEY_MUSIC_VOLUME) != null){
this.mMusicVolume.setProgress(info.getAsInteger(RingerDatabase.KEY_MUSIC_VOLUME));
findViewById(R.id.music_volume_info).setVisibility(View.VISIBLE);
}
if (info.get(RingerDatabase.KEY_ALARM_VOLUME) != null){
this.mAlarmVolume.setProgress(info.getAsInteger(RingerDatabase.KEY_ALARM_VOLUME));
findViewById(R.id.alarm_volume_info).setVisibility(View.VISIBLE);
}
if (info.get(RingerDatabase.KEY_UPDATE_INTERVAL) != null){
String ui = info.getAsString(RingerDatabase.KEY_UPDATE_INTERVAL);
findViewById(R.id.update_interval_info).setVisibility(View.VISIBLE);
String[] values = this.getResources().getStringArray(R.array.runtimes);
for(int i = 0; i < values.length; i++)
if(ui.equals(values[i])){
((Spinner) findViewById(R.id.update_interval)).setSelection(i);
break;
}
}
} else
this.setTitle(R.string.new_ringer);
if(this.mRadiusOverlay.getLocation() != null){
this.mMapView.getController().setCenter(this.mRadiusOverlay.getLocation());
this.mMapView.getController().setZoom(16);
}
if(this.mRingerName.getText().toString().equals(getString(R.string.default_ringer))){
this.mMapView.setEnabled(false);
this.mMapEditToggle.setEnabled(false);
this.mRingerName.setEnabled(false);
this.mRingerToggle.setEnabled(false);
findViewById(R.id.ringer_options).setVisibility(View.GONE);
findViewById(R.id.map_info).setVisibility(View.GONE);
findViewById(R.id.notification_ringtone_info).setVisibility(View.VISIBLE);
findViewById(R.id.ringtone_info).setVisibility(View.VISIBLE);
findViewById(R.id.wifi_toggle).setVisibility(View.VISIBLE);
findViewById(R.id.data_label).setVisibility(View.VISIBLE);
findViewById(R.id.bluetooth_toggle).setVisibility(View.VISIBLE);
findViewById(R.id.music_volume_info).setVisibility(View.VISIBLE);
findViewById(R.id.alarm_volume_info).setVisibility(View.VISIBLE);
findViewById(R.id.update_interval_info).setVisibility(View.VISIBLE);
}
this.mMapView.setDoubleTapZoonEnabled(false);
}
/**
* Creates the main menu that is displayed when the menu button is clicked
* @author ricky barrette
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, SAVE_ID, 0, getString(R.string.save_ringer)).setIcon(android.R.drawable.ic_menu_save);
menu.add(0, ADD_ID, 0, getString(R.string.add_feature)).setIcon(android.R.drawable.ic_menu_add);
return super.onCreateOptionsMenu(menu);
}
/* (non-Javadoc)
* @see com.google.android.maps.MapActivity#onDestroy()
* @author ricky barrette
*/
@Override
protected void onDestroy() {
this.mSkyHook.removeUpdates();
super.onDestroy();
}
/**
* Called when skyhook has a location to report
* @author ricky barrette
*/
@Override
public void onLocationChanged(GeoPoint point, int accuracy) {
this.mPoint = point;
if(point != null){
/*
* if this is the first fix and the radius overlay does not have a point specified
* then pan the map, and zoom in to the users current location
*/
if(this.isFirstFix)
if(this.mRadiusOverlay.getLocation() == null){
if(this.mMapView != null){
this.mMapView.getController().setCenter(point);
this.mMapView.getController().setZoom((this.mMapView.getMaxZoomLevel() - 5));
}
this.isFirstFix = false;
}
/*
* dismiss the acquiring gps dialog
*/
if(this.mGpsProgress != null)
this.mGpsProgress.dismiss();
}
}
/*
*/
@Override
public void onLocationSelected(GeoPoint point) {
if(point != null){
if(Debug.DEBUG)
Log.d(TAG, "onLocationSelected() "+ point.toString());
if(this.mRadiusOverlay != null)
this.mRadiusOverlay.setLocation(point);
if(this.mMapView != null){
this.mMapView.getController().setCenter(point);
this.mMapView.getController().setZoom((this.mMapView.getMaxZoomLevel() - 5));
}
} else if(Debug.DEBUG)
Log.d(TAG, "onLocationSelected() Location was null");
}
/* (non-Javadoc)
* @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
* @author ricky barrette
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case ADD_ID:
displayFeaturesDialog();
break;
case SAVE_ID:
save();
break;
}
return super.onOptionsItemSelected(item);
}
/**
* Called when a seekbar is has its progress changed
* @author ricky barrette
*/
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
switch (seekBar.getId()){
case R.id.radius:
this.mRadiusOverlay.setRadius(progress);
this.mMapView.invalidate();
break;
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
//UNUSED
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
//UNUSED
}
/**
* Prepares a bundle containing all the information that needs to be saved, and returns it to the starting activity
* @author ricky barrette
*/
private void save() {
final ProgressDialog progress = ProgressDialog.show(this, "", this.getText(R.string.saving), true, true);
//Generate the intent in a thread to prevent anr's and allow for progress dialog
new Thread( new Runnable(){
@Override
public void run(){
Looper.prepare();
Intent data = new Intent();
GeoPoint point = RingerInformationActivity.this.mRadiusOverlay.getLocation();
//to prevent null pointers
if(point == null)
point = new GeoPoint(0,0);
if(RingerInformationActivity.this.mRowID > 0)
data.putExtra(KEY_ROWID, mRowID);
ContentValues ringer = new ContentValues();
ContentValues info = new ContentValues();
/*
* package the ringer table information
*/
ringer.put(RingerDatabase.KEY_RINGER_NAME, RingerInformationActivity.this.mRingerName.getText().toString());
ringer.put(RingerDatabase.KEY_IS_ENABLED, RingerInformationActivity.this.mRingerToggle.isChecked());
ringer.put(RingerDatabase.KEY_LOCATION_LAT, point.getLatitudeE6());
ringer.put(RingerDatabase.KEY_LOCATION_LON, point.getLongitudeE6());
ringer.put(RingerDatabase.KEY_RADIUS, RingerInformationActivity.this.mRadius.getProgress());
/*
* package the ringer_info table information
*/
if(findViewById(R.id.notification_ringtone_info).isShown()){
info.put(RingerDatabase.KEY_NOTIFICATION_IS_SILENT, RingerInformationActivity.this.mNotificationRingtoneToggle.isChecked());
info.put(RingerDatabase.KEY_NOTIFICATION_RINGTONE, RingerInformationActivity.this.mNotificationRingtone.getText().toString());
info.put(RingerDatabase.KEY_NOTIFICATION_RINGTONE_URI, RingerInformationActivity.this.mNotificationRingtoneURI);
info.put(RingerDatabase.KEY_NOTIFICATION_RINGTONE_VOLUME, RingerInformationActivity.this.mNotificationRingtoneVolume.getProgress());
}
if(findViewById(R.id.ringtone_info).isShown()){
info.put(RingerDatabase.KEY_RINGTONE, RingerInformationActivity.this.mRingtone.getText().toString());
info.put(RingerDatabase.KEY_RINGTONE_IS_SILENT, RingerInformationActivity.this.mRingtoneToggle.isChecked());
info.put(RingerDatabase.KEY_RINGTONE_URI, RingerInformationActivity.this.mRingtoneURI);
info.put(RingerDatabase.KEY_RINGTONE_VOLUME, RingerInformationActivity.this.mRingtonVolume.getProgress());
}
if(findViewById(R.id.wifi_toggle).isShown())
info.put(RingerDatabase.KEY_WIFI, RingerInformationActivity.this.mWifiToggle.isChecked());
if(findViewById(R.id.bluetooth_toggle).isShown())
info.put(RingerDatabase.KEY_BT, RingerInformationActivity.this.mBTToggle.isChecked());
if(findViewById(R.id.music_volume_info).isShown())
info.put(RingerDatabase.KEY_MUSIC_VOLUME, RingerInformationActivity.this.mMusicVolume.getProgress());
if(findViewById(R.id.alarm_volume_info).isShown())
info.put(RingerDatabase.KEY_ALARM_VOLUME, RingerInformationActivity.this.mAlarmVolume.getProgress());
if(findViewById(R.id.update_interval_info).isShown())
info.put(RingerDatabase.KEY_UPDATE_INTERVAL,
RingerInformationActivity.this.getResources().getStringArray(R.array.runtimes)[((Spinner) findViewById(R.id.update_interval)).getSelectedItemPosition()]);
info.put(RingerDatabase.KEY_PLUS_BUTTON_HINT, true);
//package the intent
data.putExtra(RingerListActivity.KEY_RINGER, ringer).putExtra(RingerListActivity.KEY_INFO, info);
RingerInformationActivity.this.setResult(RESULT_OK, data);
progress.dismiss();
RingerInformationActivity.this.finish();
}
}).start();
}
}

View File

@@ -0,0 +1,343 @@
/**
* RingerListActivity.java
* @date Apr 29, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.ui;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Looper;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;
import com.TwentyCodes.android.LocationRinger.R;
import com.TwentyCodes.android.LocationRinger.db.DatabaseListener;
import com.TwentyCodes.android.LocationRinger.db.RingerDatabase;
import com.TwentyCodes.android.LocationRinger.receivers.LocationReceiver;
import com.TwentyCodes.android.LocationRinger.services.LocationService;
import com.TwentyCodes.android.SkyHook.SkyHookRegistration;
import com.TwentyCodes.android.SkyHook.Splash;
import com.skyhookwireless.wps.RegistrationCallback;
import com.skyhookwireless.wps.WPSContinuation;
import com.skyhookwireless.wps.WPSReturnCode;
public class RingerListActivity extends Activity implements OnItemClickListener, OnClickListener, DatabaseListener, RegistrationCallback {
private RingerDatabase mDb;
private ListView mListView;
private SharedPreferences mSettings;
private ProgressDialog mProgress;
public static final String KEY_RINGER = "key_ringer";
public static final String KEY_INFO = "key_info";
private static final int NEW_RINGER = 0;
private static final int DELETE_ID = 1;
private static final int ACTIVITY_CREATE = 3;
private static final int ACTIVITY_EDIT = 4;
private static final int SETTINGS = 7;
private static final int BACKUP = 8;
private static final int RESTORE = 9;
@Override
public void done() {
}
@Override
public WPSContinuation handleError(WPSReturnCode arg0) {
Toast.makeText(this, R.string.skyhook_error_registration, Toast.LENGTH_SHORT).show();
return WPSContinuation.WPS_CONTINUE;
}
@Override
public void handleSuccess() {
Toast.makeText(this, R.string.registered, Toast.LENGTH_SHORT).show();
this.mSettings.edit().putBoolean(SettingsActivity.IS_REGISTERED, true).commit();
}
/**
* called when the note edit activity finishes
* (non-Javadoc)
* @see android.app.Activity#onActivityResult(int, int, android.content.Intent)
* @author ricky barrette
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent){
super.onActivityResult(requestCode, resultCode, intent);
if(resultCode == RESULT_OK){
switch(requestCode) {
case ACTIVITY_CREATE:
ContentValues ringer = (ContentValues) intent.getParcelableExtra(KEY_RINGER);
mDb.insertRinger(ringer, (ContentValues) intent.getParcelableExtra(KEY_INFO));
populate();
break;
case ACTIVITY_EDIT:
mDb.updateRinger(intent.getLongExtra(RingerInformationActivity.KEY_ROWID, 0),
(ContentValues) intent.getParcelableExtra(KEY_RINGER), (ContentValues) intent.getParcelableExtra(KEY_INFO));
populate();
break;
}
}
}
@Override
public void onClick(View v) {
Intent i = new Intent(this, RingerInformationActivity.class);
startActivityForResult(i, ACTIVITY_CREATE );
}
/**
* called when the context menu item has been selected
* (non-Javadoc)
* @see android.app.Activity#onContextItemSelected(android.view.MenuItem)
* @author ricky barrette
*/
public boolean onContextItemSelected(MenuItem item) {
switch(item.getItemId()) {
case DELETE_ID:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
if(info.id == 0)
Toast.makeText(this, this.getString(R.string.cant_delete_default), Toast.LENGTH_SHORT).show();
else
mDb.deleteRinger(info.id +1);
return true;
}
return super.onContextItemSelected(item);
}
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ringer_list);
this.mDb = new RingerDatabase(this, this);
this.mListView = (ListView) findViewById(R.id.ringer_list);
this.mListView.setOnItemClickListener(this);
this.mListView.setOnCreateContextMenuListener(this);
this.mListView.setEmptyView(findViewById(android.R.id.empty));
findViewById(R.id.add_ringer_button).setOnClickListener(this);
populate();
this.mSettings = this.getSharedPreferences(SettingsActivity.SETTINGS, Context.MODE_WORLD_WRITEABLE);
if(this.mSettings.getBoolean(SettingsActivity.IS_FIRST_BOOT, true))
new FirstBootDialog(this).show();
if(! this.mSettings.getBoolean(SettingsActivity.IS_REGISTERED, false)){
new SkyHookRegistration(this).registerNewUser(this);
}
this.startActivity(new Intent(this, Splash.class));
}
/**
* called when the activity is first created, creates a context menu
* @param menu
* @param v
* @param menuInfo
* @return
* @author ricky barrette
*/
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, "Delete Ringer").setIcon(android.R.drawable.ic_menu_delete);
}
/**
* called when the activity is first created, creates options menu
* (non-Javadoc)
* @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
* @author ricky barrette
*/
@Override
public boolean onCreateOptionsMenu (Menu menu) {
menu.add(1, NEW_RINGER, 0, getString(R.string.new_ringer)).setIcon(android.R.drawable.ic_menu_add);
menu.add(1, BACKUP, 1, getString(R.string.backup)).setIcon(android.R.drawable.ic_menu_upload);
menu.add(1, RESTORE, 2, getString(R.string.restore)).setIcon(android.R.drawable.ic_menu_revert);
menu.add(1, SETTINGS, 5, getString(R.string.settings)).setIcon(android.R.drawable.ic_menu_preferences);
return super.onCreateOptionsMenu(menu);
}
/**
* Called when a database is being upgraded
* @author ricky barrette
*/
@Override
public void onDatabaseUpgrade() {
this.mProgress = ProgressDialog.show(this, "", this.getText(R.string.upgrading), true, true);
}
/**
* called when a database upgrade is finished
* @author ricky barrette
*/
@Override
public void onDatabaseUpgradeComplete() {
populate();
if(this.mProgress != null)
this.mProgress.dismiss();
}
/* (non-Javadoc)
* @see android.app.Activity#onDestroy()
* @author ricky barrette
*/
@Override
protected void onDestroy() {
restartService();
super.onDestroy();
}
/**
* called when an item in the list view has been clicked,
* this will open the note edit dialog for the selected note
* (non-Javadoc)
* @see android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget.AdapterView, android.view.View, int, long)
* @author ricky barrette
*/
@Override
public void onItemClick(AdapterView<?> arg0, View v, int postion, final long id) {
final ProgressDialog progress = ProgressDialog.show(this, "", this.getText(R.string.loading), true, true);
//post to social sites in a new thread to prevent ANRs
new Thread( new Runnable(){
@Override
public void run(){
Looper.prepare();
Intent i = new Intent(RingerListActivity.this, RingerInformationActivity.class);
/*
* get the ringer
*/
Cursor ringer = mDb.getRingerFromId(id+1);
if (ringer.moveToFirst()) {
i.putExtra(RingerInformationActivity.KEY_ROWID, id+1)
.putExtra(RingerDatabase.KEY_RINGER_NAME, ringer.getString(0))
.putExtra(RingerDatabase.KEY_IS_ENABLED, ringer.getString(1)== null ? true :(Integer.parseInt(ringer.getString(1)) == 1 ? true : false))//5
.putExtra(RingerDatabase.KEY_RADIUS, ringer.getInt(2))
.putExtra(RingerDatabase.KEY_LOCATION_LAT, ringer.getInt(3))
.putExtra(RingerDatabase.KEY_LOCATION_LON, ringer.getInt(4));
}
if (ringer != null && !ringer.isClosed()) {
ringer.close();
}
/*
* get the ringer's info, and parse it into content values
*/
ContentValues values = new ContentValues();
Cursor info = mDb.getRingerInfo(i.getStringExtra(RingerDatabase.KEY_RINGER_NAME));
if (info.moveToFirst()) {
do {
values.put(info.getString(0), info.getString(1));
} while (info.moveToNext());
}
if (info != null && !info.isClosed()) {
info.close();
}
i.putExtra(KEY_INFO, values);
progress.dismiss();
//start the ringer info activity in editor mode
startActivityForResult(i, ACTIVITY_EDIT);
}
}).start();
}
/**
* called when an option is selected form the menu
* (non-Javadoc)
* @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
* @author ricky barrette
*/
@Override
public boolean onOptionsItemSelected (MenuItem item) {
switch (item.getItemId()){
case NEW_RINGER:
Intent i = new Intent(this, RingerInformationActivity.class);
startActivityForResult(i, ACTIVITY_CREATE );
return true;
case SETTINGS:
startActivity(new Intent(this, SettingsActivity.class));
return true;
case BACKUP:
mDb.backup();
SettingsActivity.backup(this);
break;
case RESTORE:
mDb.restore();
SettingsActivity.restore(this);
break;
}
return super.onOptionsItemSelected(item);
}
/**
* Called when the database is restored
*/
@Override
public void onRestoreComplete() {
populate();
}
/**
* called when a ringer is deleted
*/
@Override
public void onRingerDeletionComplete() {
populate();
}
/**
* populates the list view from the data base
* @author ricky barrette
*/
private void populate() {
findViewById(R.id.add_ringer_button_hint).setVisibility(this.mDb.getAllRingerTitles().size() > 1 ? View.GONE : View.VISIBLE);
mListView.setAdapter(new RingerListAdapter(this, mDb));
}
/**
* Restarts the service if its not already running.
* @author ricky barrette
*/
private void restartService() {
if(! this.getSharedPreferences(SettingsActivity.SETTINGS, Context.MODE_WORLD_WRITEABLE).getBoolean(SettingsActivity.IS_SERVICE_STARTED, false)){
// cancel the previous service
LocationService.stopService(this).run();
//start the new service
Intent i = new Intent(this, LocationService.class)
.putExtra(LocationService.INTENT_EXTRA_REQUIRED_ACCURACY, Integer.parseInt(this.getSharedPreferences(SettingsActivity.SETTINGS, 2).getString(SettingsActivity.ACCURACY , "50")))
.setAction(LocationReceiver.LR_ACTION_UPDATE);
this.startService(i);
}
}
}

View File

@@ -0,0 +1,146 @@
/**
* RingerListAdaptor.java
* @date May 11, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.ui;
import java.util.List;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TextView;
import com.TwentyCodes.android.LocationRinger.R;
import com.TwentyCodes.android.LocationRinger.db.RingerDatabase;
import com.TwentyCodes.android.LocationRinger.debug.Debug;
/**
* This adapter will be used to populate the list view with all the ringers names, and manage enabling/disabling of ringers based on their check box.
* @author ricky barrette
*/
public class RingerListAdapter extends BaseAdapter {
private static final String TAG = "RingerListAdapter";
/* (non-Javadoc)
* @see android.widget.BaseAdapter#notifyDataSetChanged()
* @author ricky barrette
*/
@Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
private RingerDatabase mDb;
private List<String> mList;
private LayoutInflater mInflater;
/**
* Creates a new RingerListAdapter
* @param context
* @param listener
* @param db
* @author ricky barrette
*/
public RingerListAdapter(Context context, RingerDatabase db) {
super();
// Cache the LayoutInflate to avoid asking for a new one each time.
mInflater = LayoutInflater.from(context);
mDb = db;
mList = db.getAllRingerTitles();
}
@Override
public int getCount() {
return mList.size();
}
@Override
public String getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@SuppressWarnings("unused")
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid unnecessary calls to findViewById() on each row.
ViewHolder holder;
// When convertView is not null, we can reuse it directly, there is no need
// to reinflate it. We only inflate a new View when the convertView supplied
// by ListView is null.
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, null);
// Creates a ViewHolder and store references to the two children views
// we want to bind data to.
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(android.R.id.text1);
holder.checkbox = (CheckBox) convertView.findViewById(R.id.ringer_enabled_checkbox);
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
if(Debug.DEBUG){
Log.d(TAG, "postion = "+position);
if(convertView == null)
Log.e(TAG,"convertview is null!!!");
if(holder == null)
Log.e(TAG,"holder is null!!!");
if(holder.text == null)
Log.e(TAG,"holder.text is null!!!");
if(holder.checkbox == null)
Log.e(TAG,"holder.checkbox is null!!!");
}
/*
* Bind the data efficiently with the holder.
* Remember that you should always call setChecked() after calling setOnCheckedChangedListener.
* This will prevent the list from changing the values on you.
*/
holder.text.setText(getItem(position));
holder.checkbox.setOnCheckedChangeListener(new OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mDb.setRingerEnabled(position +1, isChecked);
}
});
holder.checkbox.setChecked(mDb.isRingerEnabled(position +1));
//Remove the checkbox for the default ringer
if(position == 0)
holder.checkbox.setVisibility(View.INVISIBLE);
else
holder.checkbox.setVisibility(View.VISIBLE);
return convertView;
}
class ViewHolder {
TextView text;
CheckBox checkbox;
}
}

View File

@@ -0,0 +1,68 @@
/**
* ScrollView.java
* @date May 3, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.ui;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
/**
* This is a simple scroll view that i have made to enable and disable scrolling
* @author ricky barrette
*/
public class ScrollView extends android.widget.ScrollView {
private boolean isEnabled = true;
/**
* @param context
* @param apiKey
* @author ricky barrette
*/
public ScrollView(Context context) {
super(context);
}
/**
* @param context
* @param attrs
* @author ricky barrette
*/
public ScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* @param context
* @param attrs
* @param defStyle
* @author ricky barrette
*/
public ScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Enables or disabled the scrollview's ability to scroll
* @param enabled
* @author ricky barrette
*/
public void setScrollEnabled(boolean enabled){
isEnabled = enabled;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return isEnabled ? super.onInterceptTouchEvent(ev) : false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return isEnabled ? super.onTouchEvent(ev) : false;
}
}

View File

@@ -0,0 +1,171 @@
/**
* SearchDialog.java
* @date May 9, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.ui;
import java.io.IOException;
import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONException;
import android.app.Dialog;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ProgressBar;
import com.TwentyCodes.android.LocationRinger.LocationSelectedListener;
import com.TwentyCodes.android.LocationRinger.R;
import com.TwentyCodes.android.LocationRinger.debug.Debug;
import com.TwentyCodes.android.location.ReverseGeocoder;
import com.google.android.maps.GeoPoint;
/**
* This dialog will be used to get users input for the address that they want to search for. A GeoPoint location will be returned via LocationSelectedListener
* @author ricky barrette
*/
public class SearchDialog extends Dialog implements android.view.View.OnClickListener, OnItemClickListener{
protected static final String TAG = "SearchDialog";
private ListView mAddressList;
private EditText mAddress;
private JSONArray mResults;
private ProgressBar mProgress;
private Handler mHandler;
private Context mContext;
private LocationSelectedListener mListener;
/**
* Creates a new search dialog
* @param context
* @author ricky barrette
*/
public SearchDialog(Context context, LocationSelectedListener listener) {
super(context);
this.setTitle(R.string.search);
this.setContentView(R.layout.address_dialog);
findViewById(R.id.ok).setOnClickListener(this);
mAddressList = (ListView) findViewById(R.id.address_list);
mAddressList.setOnItemClickListener(this);
mAddress = (EditText) findViewById(R.id.address);
mProgress = (ProgressBar) findViewById(R.id.search_progress);
mHandler = new Handler();
mContext = context;
mListener = listener;
}
/**
* Retrieves all the strings from the JSON Array
* @return list of addresses
* @author ricky barrette
*/
private ArrayList<String> getAddress() {
if(Debug.DEBUG)
Log.d(TAG,"getAddress()");
ArrayList<String> list = new ArrayList<String>();
try {
for(int i = 0; i < mResults.length(); i++){
list.add(mResults.getJSONObject(i).getString("address"));
}
} catch (JSONException e) {
e.printStackTrace();
return null;
}
return list;
}
/**
* Retrieves the GeoPoint from the JSON Array for the given index
* @param index for the place
* @return GeoPoint of the place
* @author ricky barrette
*/
private GeoPoint getCoords(int index){
if(Debug.DEBUG)
Log.d(TAG,"getCoords()");
try {
JSONArray coords = mResults.getJSONObject(index).getJSONObject("Point").getJSONArray("coordinates");
if(Debug.DEBUG)
Log.d(TAG,"creating geopoint: "+ new GeoPoint((int) (coords.getDouble(1) *1E6), (int) (coords.getDouble(0)*1E6)).toString());
return new GeoPoint((int) (coords.getDouble(1) *1E6), (int) (coords.getDouble(0)*1E6));
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
@Override
public void onClick(final View v) {
switch(v.getId()){
case R.id.ok:
v.setEnabled(false);
mProgress.setVisibility(View.VISIBLE);
mProgress.setIndeterminate(true);
new Thread( new Runnable(){
@Override
public void run(){
if(Debug.DEBUG)
Log.d(TAG,"strarting search and parsing") ;
try {
mResults = ReverseGeocoder.addressSearch(mAddress.getText().toString());
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
if(mResults != null){
if(Debug.DEBUG)
Log.d(TAG,"finished searching and parsing");
//update UI
mHandler.post(new Runnable(){
@Override
public void run(){
if(Debug.DEBUG)
Log.d(TAG,"populating list");
mAddressList.setAdapter(new ArrayAdapter<String>(mContext, android.R.layout.simple_list_item_1, getAddress()));
v.setEnabled(true);
mProgress.setVisibility(View.INVISIBLE);
mProgress.setIndeterminate(false);
if(Debug.DEBUG)
Log.d(TAG,"finished");
}
});
} else {
//update the UI
mHandler.post(new Runnable(){
@Override
public void run(){
v.setEnabled(true);
mProgress.setVisibility(View.INVISIBLE);
mProgress.setIndeterminate(false);
if(Debug.DEBUG)
Log.d(TAG,"failed");
}
});
}
}
}).start();
break;
}
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(Debug.DEBUG)
Log.d(TAG,"slected "+ (int) id);
mListener.onLocationSelected(getCoords((int) id));
this.dismiss();
}
}

View File

@@ -0,0 +1,166 @@
/**
* SettingsActivity.java
* @date May 4, 2011
* @author Twenty Codes, LLC
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.ui;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
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;
import android.os.Bundle;
import android.os.Environment;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import com.TwentyCodes.android.LocationRinger.R;
/**
* This is the settings activity for location ringer
* @author ricky barrette
*/
public class SettingsActivity extends PreferenceActivity implements OnPreferenceClickListener {
public static final String SETTINGS = "settings";
public static final String UPDATE_INTVERVAL = "update_interval";
public static final String IGNORE_LOCATION = "ignore_location";
public static final String ACCURACY = "accuracy";
public static final String TOASTY = "toasty";
public static final String EMAIL = "email";
public static final String START_ON_BOOT = "start_on_boot";
public static final String IS_SERVICE_STARTED = "is_service_started";
public static final String IS_FIRST_BOOT = "is_first_boot";
public static final String IS_REGISTERED = "is_registered";
public static final String IS_FIRST_RINGER_PROCESSING = "is_first_ringer_processing";
public static final String IS_DEFAULT = "is_default";
public static final String RESTORE = "restore";
public static final String BACKUP = "backup";
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
this.getPreferenceManager().setSharedPreferencesName(SETTINGS);
addPreferencesFromResource(R.xml.setings);
this.findPreference(EMAIL).setOnPreferenceClickListener(this);
}
/**
* called when the email preference button is clicked
*/
@Override
public boolean onPreferenceClick(Preference preference) {
this.startActivity(generateEmailIntent());
return false;
}
/**
* generates the exception repost email intent
* @param report
* @return intent to start users email client
* @author ricky barrette
*/
private Intent generateEmailIntent() {
/*
* get the build information, and build the string
*/
PackageManager pm = this.getPackageManager();
PackageInfo pi;
try {
pi = pm.getPackageInfo(this.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 = 1;
}
Intent intent = new Intent(Intent.ACTION_SEND);
String theSubject = this.getString(R.string.app_name);
String theBody = "\n\n\n"+ Build.FINGERPRINT +"\n"+ this.getString(R.string.app_name)+" "+pi.versionName+" bulid "+pi.versionCode;
intent.putExtra(Intent.EXTRA_EMAIL,new String[] {this.getString(R.string.email)});
intent.putExtra(Intent.EXTRA_TEXT, theBody);
intent.putExtra(Intent.EXTRA_SUBJECT, theSubject);
intent.setType("message/rfc822");
return intent;
}
/**
* Backs up the database
* @return true if successful
* @author ricky barrette
*/
public static boolean backup(Context context){
File dbFile = new File(Environment.getDataDirectory() + "/data/"+context.getPackageName()+"/shared_prefs/"+SETTINGS+".xml");
File exportDir = new File(Environment.getExternalStorageDirectory(), "/"+context.getString(R.string.app_name));
if (!exportDir.exists()) {
exportDir.mkdirs();
}
File file = new File(exportDir, dbFile.getName());
try {
file.createNewFile();
copyFile(dbFile, file);
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* Copies a file
* @param src file
* @param dst file
* @throws IOException
* @author ricky barrette
*/
private static void copyFile(File src, File dst) throws IOException {
FileChannel inChannel = new FileInputStream(src).getChannel();
FileChannel outChannel = new FileOutputStream(dst).getChannel();
try {
inChannel.transferTo(0, inChannel.size(), outChannel);
} finally {
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
}
}
/**
* Restores the database from the sdcard
* @return true if successful
* @author ricky barrette
*/
public static void restore(Context context){
File dbFile = new File(Environment.getDataDirectory() + "/data/"+context.getPackageName()+"/shared_prefs/"+SETTINGS+".xml");
File exportDir = new File(Environment.getExternalStorageDirectory(), "/"+context.getString(R.string.app_name));
if (!exportDir.exists()) {
exportDir.mkdirs();
}
File file = new File(exportDir, dbFile.getName());
try {
file.createNewFile();
copyFile(file, dbFile);
} catch (IOException e) {
e.printStackTrace();
}
context.getSharedPreferences(SETTINGS, Context.MODE_WORLD_WRITEABLE).edit().remove(IS_FIRST_RINGER_PROCESSING).remove(IS_DEFAULT).remove(IS_SERVICE_STARTED).commit();
}
}

View File

@@ -0,0 +1,93 @@
/**
* @author Twenty Codes
* @author ricky barrette
*/
package com.TwentyCodes.android.LocationRinger.ui;
import android.content.Context;
import android.graphics.Typeface;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* this class will be a simple TextView to be used in a preference activity. you set the text using the set title tag
* @author ricky barrette
*/
public class TextViewPreference extends Preference {
/**
* creates a preference that is nothing but a text view
* @param context
*/
public TextViewPreference(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
/**
* creates a preference that is nothing but a text view
* @param context
* @param attrs
*/
public TextViewPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* creates a preference that is nothing but a text view
* @param context
* @param attrs
* @param defStyle
*/
public TextViewPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* creates a linear layout the contains only a textview.
* (non-Javadoc)
* @see android.preference.Preference#onCreateView(android.view.ViewGroup)
* @param parent
* @return
* @author ricky barrette
*/
@Override
protected View onCreateView(ViewGroup parent){
/*
* create a vertical linear layout that width and height that wraps content
*/
LinearLayout layout = new LinearLayout(getContext());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.CENTER;
layout.setPadding(15, 5, 10, 5);
layout.setOrientation(LinearLayout.VERTICAL);
layout.removeAllViews();
/*
* create a textview that will be used to display the title provided in xml
* and add it to the lay out
*/
TextView title = new TextView(getContext());
title.setText(getTitle());
title.setTextSize(16);
title.setTypeface(Typeface.SANS_SERIF);
title.setGravity(Gravity.LEFT);
title.setLayoutParams(params);
/*
* add the title and the time picker views to the layout
*/
layout.addView(title);
layout.setId(android.R.id.widget_frame);
return layout;
}
}

View File

@@ -0,0 +1,118 @@
/**
* @author Twenty Codes
* @author ricky barrette
* @date June 29, 2011
*/
package com.TwentyCodes.android.LocationRinger.ui;
import com.TwentyCodes.android.LocationRinger.R;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Typeface;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* this class will be a simple preference that contains only a text view that will display the application build information
* @author ricky barrette
*/
public class VersionInformationPreference extends Preference {
private Context mContext;
/**
* creates a preference that is nothing but a text view
* @param context
*/
public VersionInformationPreference(Context context) {
super(context);
mContext = context;
}
/**
* creates a preference that is nothing but a text view
* @param context
* @param attrs
*/
public VersionInformationPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
}
/**
* creates a preference that is nothing but a text view
* @param context
* @param attrs
* @param defStyle
*/
public VersionInformationPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
}
/**
* creates a linear layout the contains only a textview.
* (non-Javadoc)
* @see android.preference.Preference#onCreateView(android.view.ViewGroup)
* @param parent
* @return
* @author ricky barrette
*/
@Override
protected View onCreateView(ViewGroup parent){
/*
* get the build information, and build the string
*/
PackageManager pm = mContext.getPackageManager();
PackageInfo pi;
try {
pi = pm.getPackageInfo(mContext.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 = 1;
}
/*
* create a vertical linear layout that width and height that wraps content
*/
LinearLayout layout = new LinearLayout(getContext());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
// params.gravity = Gravity.CENTER;
layout.setPadding(15, 5, 10, 5);
layout.setOrientation(LinearLayout.VERTICAL);
layout.removeAllViews();
/*
* create a textview that will be used to display the application's name and build information
* and add it to the layout
*/
TextView title = new TextView(getContext());
title.setText(mContext.getString(R.string.app_name)+" "+pi.versionName+" bulid "+pi.versionCode);
title.setTextSize(16);
title.setTypeface(Typeface.SANS_SERIF);
title.setGravity(Gravity.LEFT);
title.setLayoutParams(params);
/*
* add the title views to the layout
*/
layout.addView(title);
layout.setId(android.R.id.widget_frame);
return layout;
}
}