package org.openintents.provider;
/*
* Copyright (C) 2007-2008 OpenIntents.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.app.AlarmManager;
import android.content.*;
import android.database.Cursor;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.util.Log;
/**
* Provider for the Alert Framework, Make sure you call init(Context c) before
* using any of the convenience functions. Location.Position is an Uri of the
* format geo:long,lat example: geo:3.1472,567890 Location.Distance is distance
* in meters as long.
*
* @author Ronan 'Zero' Schwarz
*/
public class Alert {
public static final String _TAG = "org.openintents.provider.Alert";
public static final String TYPE_LOCATION = "location";
public static final String TYPE_SENSOR = "sensor";
public static final String TYPE_GENERIC = "generic";
public static final String TYPE_COMBINED = "combined";
public static final String TYPE_DATE_TIME = "datetime";
public static final String NATURE_USER = "user";
public static final String NATURE_SYSTEM = "system";
public static ContentResolver mContentResolver;
private static final UriMatcher URL_MATCHER;
private static final int ALERT_GENERIC = 100;
private static final int ALERT_GENERIC_ID = 101;
private static final int ALERT_LOCATION = 102;
private static final int ALERT_LOCATION_ID = 103;
private static final int ALERT_COMBINED = 104;
private static final int ALERT_COMBINED_ID = 105;
private static final int ALERT_SENSOR = 106;
private static final int ALERT_SENSOR_ID = 106;
private static final int ALERT_DATE_TIME = 107;
private static final int ALERT_DATE_TIME_ID = 108;
// ugly hack to make the mock provider work,
// see [..]
public static final long LOCATION_EXPIRES = 1000000;
public static final String EXTRA_URI = "URI";
protected static LocationManager locationManager;
protected static AlarmManager alarmManager;
protected static Context context;
public static final class Generic implements BaseColumns {
public static final Uri CONTENT_URI = Uri
.parse("content://org.openintents.alert/generic");
public static final String CONDITION1 = "condition1";
public static final String CONDITION2 = "condition2";
public static final String TYPE = "alert_type";
public static final String RULE = "rule";
public static final String NATURE = "nature";
public static final String ACTIVE = "active";
public static final String ACTIVATE_ON_BOOT = "activate_on_boot";
public static final String INTENT = "intent";
public static final String INTENT_CATEGORY = "intent_category";
public static final String INTENT_URI = "intent_uri";
public static final String INTENT_MIME_TYPE = "intent_mime_type";
public static final String DEFAULT_SORT_ORDER = "";
public static final String[] PROJECTION = {_ID, _COUNT, CONDITION1,
CONDITION2, TYPE, RULE, NATURE, ACTIVE, ACTIVATE_ON_BOOT,
INTENT, INTENT_CATEGORY, INTENT_URI, INTENT_MIME_TYPE};
}
/**
* location based alerts. you must at least specify a position
*/
public static final class Location implements BaseColumns {
public static final Uri CONTENT_URI = Uri
.parse("content://org.openintents.alert/location");
/**
* Location.Position is an Uri of the format geo:long,lat example:
* geo:3.1472,567890
*/
public static final String POSITION = Generic.CONDITION1;
/**
* Location.Distance is distance in meters as long.
*/
public static final String DISTANCE = Generic.CONDITION2;
/**
* Type must always be of Alert.TYPE_LOCATION any other values will
* result in your alert not being processed.
*/
public static final String TYPE = Generic.TYPE;
public static final String RULE = Generic.RULE;
public static final String NATURE = Generic.NATURE;
public static final String ACTIVE = Generic.ACTIVE;
public static final String ACTIVATE_ON_BOOT = Generic.ACTIVATE_ON_BOOT;
public static final String INTENT = Generic.INTENT;
public static final String INTENT_CATEGORY = Generic.INTENT_CATEGORY;
public static final String INTENT_URI = Generic.INTENT_URI;
public static final String INTENT_MIME_TYPE = Generic.INTENT_MIME_TYPE;
public static final String DEFAULT_SORT_ORDER = "";
public static final String[] PROJECTION = {_ID, _COUNT, POSITION,
DISTANCE, TYPE, RULE, NATURE, ACTIVE, ACTIVATE_ON_BOOT, INTENT,
INTENT_CATEGORY, INTENT_URI, INTENT_MIME_TYPE};
}
public static final class DateTime implements BaseColumns {
public static final Uri CONTENT_URI = Uri
.parse("content://org.openintents.alert/datetime");
/**
* The point in time for the alarm, in format time:epoch1234456 number
* is time in millisecond sice 1970, like you get from
* System.getCurrentMillis
*/
public static final String TIME = Generic.CONDITION1;
/**
* the alert reocurs every n milliseconds, or not at all if set to 0.
* reouccreny should be at least 1 minute.
*/
public static final String REOCCURENCE = Generic.CONDITION2;
public static final String TYPE = Generic.TYPE;
public static final String RULE = Generic.RULE;
public static final String NATURE = Generic.NATURE;
public static final String ACTIVE = Generic.ACTIVE;
public static final String ACTIVATE_ON_BOOT = Generic.ACTIVATE_ON_BOOT;
public static final String INTENT = Generic.INTENT;
public static final String INTENT_CATEGORY = Generic.INTENT_CATEGORY;
public static final String INTENT_URI = Generic.INTENT_URI;
public static final String INTENT_MIME_TYPE = Generic.INTENT_MIME_TYPE;
public static final String DEFAULT_SORT_ORDER = "";
public static final String[] PROJECTION = {_ID, _COUNT, TIME,
REOCCURENCE, TYPE, RULE, NATURE, ACTIVE, ACTIVATE_ON_BOOT,
INTENT, INTENT_CATEGORY, INTENT_URI, INTENT_MIME_TYPE};
}
public static final class ManagedService implements BaseColumns {
public static final Uri CONTENT_URI = Uri
.parse("content://org.openintents.alert/managedservice");
public static final String SERVICE_CLASS = "service_class";
public static final String TIME_INTERVALL = "time_intervall";
public static final String DO_ROAMING = "do_roaming";
public static final String LAST_TIME = "last_time";
public static final String[] PROJECTION = {_ID, _COUNT, SERVICE_CLASS,
TIME_INTERVALL, DO_ROAMING, LAST_TIME};
}
public static void registerManagedService(String serviceClassName,
long timeIntervall, boolean useWhileRoaming) {
long minTime;
ContentValues cv;
Cursor c = mContentResolver.query(ManagedService.CONTENT_URI,
ManagedService.PROJECTION, ManagedService.SERVICE_CLASS
+ " like '" + serviceClassName + "'", null, null
);
if (c != null && c.getCount() > 0) {// update
c.moveToFirst();
String id = c
.getString(c.getColumnIndexOrThrow(ManagedService._ID));
ContentValues values = new ContentValues();
values.put(ManagedService.TIME_INTERVALL,
Long.toString(timeIntervall));
values.put(ManagedService.DO_ROAMING,
Boolean.toString(useWhileRoaming));
mContentResolver.update(
Uri.withAppendedPath(ManagedService.CONTENT_URI, id),
values, null, null);
} else {
// insert
cv = new ContentValues();
cv.put(ManagedService.SERVICE_CLASS, serviceClassName);
cv.put(ManagedService.TIME_INTERVALL, timeIntervall);
cv.put(ManagedService.DO_ROAMING, useWhileRoaming);
insert(ManagedService.CONTENT_URI, cv);
}
if (c != null) {
c.close();
}
// get all entry && compute new minimum time intervall
// TODO: make this in sql.
c = mContentResolver.query(ManagedService.CONTENT_URI,
ManagedService.PROJECTION, null, null, null);
c.moveToFirst();
minTime = c.getLong(c.getColumnIndex(ManagedService.TIME_INTERVALL));
while (!c.isAfterLast()) {
long l = c.getLong(c.getColumnIndex(ManagedService.TIME_INTERVALL));
if (l < minTime) {
minTime = l;
}
c.moveToNext();
}
c.close();
c = mContentResolver.query(DateTime.CONTENT_URI, DateTime.PROJECTION,
DateTime.INTENT + " like '"
+ org.openintents.OpenIntents.SERVICE_MANAGER + "'",
null, null
);
String now = "time:epoch," + System.currentTimeMillis();
cv = new ContentValues();
cv.put(DateTime.TIME, now);
cv.put(DateTime.REOCCURENCE, minTime);
cv.put(DateTime.INTENT, org.openintents.OpenIntents.SERVICE_MANAGER);
cv.put(DateTime.NATURE, Alert.NATURE_SYSTEM);
cv.put(DateTime.ACTIVATE_ON_BOOT, true);
cv.put(DateTime.ACTIVE, true);
cv.put(DateTime.TYPE, Alert.TYPE_DATE_TIME);
if (c != null && c.getCount() > 0) {
update(DateTime.CONTENT_URI, cv, DateTime.INTENT + " like '"
+ org.openintents.OpenIntents.SERVICE_MANAGER + "'", null);
// TODO new SDK cancle PendingIntent
// alarmManager.cancel(new
// Intent().setAction(org.openintents.OpenIntents.SERVICE_MANAGER));
registerDateTimeAlert(cv);
// registerDateTimeAlert
} else {
insert(DateTime.CONTENT_URI, cv);
}
if (c != null) {
c.close();
}
Log.d(_TAG, "registerManagedService: finished");
}
public static void unregisterManagedService(String serviceClassName) {
ContentValues cv = new ContentValues();
long minTime;
delete(ManagedService.CONTENT_URI, ManagedService.SERVICE_CLASS
+ " like '" + serviceClassName + "'", null);
// get all entry && compute new minimum time intervall
// TODO: make this in sql.
Cursor c = mContentResolver.query(ManagedService.CONTENT_URI,
ManagedService.PROJECTION, null, null, null);
c.moveToFirst();
minTime = c.getLong(c.getColumnIndex(ManagedService.TIME_INTERVALL));
while (!c.isAfterLast()) {
long l = c.getLong(c.getColumnIndex(ManagedService.TIME_INTERVALL));
if (l < minTime) {
minTime = l;
}
c.moveToNext();
}
c.close();
c = mContentResolver.query(DateTime.CONTENT_URI, DateTime.PROJECTION,
DateTime.INTENT + " like '"
+ org.openintents.OpenIntents.SERVICE_MANAGER + "'",
null, null
);
String now = "time:epoch," + System.currentTimeMillis();
cv.put(DateTime.TIME, now);
cv.put(DateTime.REOCCURENCE, minTime);
cv.put(DateTime.INTENT, org.openintents.OpenIntents.SERVICE_MANAGER);
cv.put(DateTime.NATURE, Alert.NATURE_SYSTEM);
cv.put(DateTime.ACTIVATE_ON_BOOT, true);
cv.put(DateTime.ACTIVE, true);
cv.put(DateTime.TYPE, Alert.TYPE_DATE_TIME);
if (c != null && c.getCount() > 0) {
update(DateTime.CONTENT_URI, cv, DateTime.INTENT + " like '"
+ org.openintents.OpenIntents.SERVICE_MANAGER + "'", null);
// TODO new SDK cancle PendingIntent
// alarmManager.cancel(new
// Intent().setAction(org.openintents.OpenIntents.SERVICE_MANAGER));
registerDateTimeAlert(cv);
// registerDateTimeAlert
}
}
/**
* @param uri the content uri to insert to
* @param cv the ContentValues that will be inserted to
*/
public static Uri insert(Uri uri, ContentValues cv) {
Uri res;
int type = URL_MATCHER.match(uri);
res = mContentResolver.insert(uri, cv);
Log.d(_TAG, " insert, result>>" + res + "<<");
if (res != null) {// register alert
Log.d(_TAG, "uri>>" + uri + "<< matched>>" + type + "<<");
switch (type) {
case ALERT_LOCATION:
registerLocationAlert(cv);
break;
case ALERT_DATE_TIME:
registerDateTimeAlert(cv);
break;
default:
break;
}
}
return res;
}
/**
* @param uri the content uri to delete
* @param selection the selection to check against
* @param selectionArgs the arguments applied to selection string (optional)
* @return number of deleted rows
*/
public static int delete(Uri uri, String selection, String[] selectionArgs) {
return mContentResolver.delete(uri, selection, selectionArgs);
}
/**
* @param uri the content uri to update
* @param cv the ContentValues that will be update in selected rows.
* @param selection the selection to check against
* @param selectionArgs the arguments applied to selection string (optional)
* @return number of updated rows
*/
public static int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
return mContentResolver.update(uri, values, selection, selectionArgs);
}
public static void registerLocationAlert(ContentValues cv) {
Uri gUri = null;
String distStr = "";
String geo = "";
String[] loc = null;
try {
gUri = Uri.parse(cv.getAsString(Location.POSITION));
// do this for easier debugging.
distStr = cv.getAsString(Location.DISTANCE);
// float dist=cv.getAsFloat(Location.DISTANCE);
geo = gUri.getSchemeSpecificPart();
loc = geo.split(",");
// TODO: find out how to handle this now
/*
* PendingIntent i= new PendingIntent();
* //i.setClassName("org.openintents.alert"
* ,"LocationAlertDispatcher");
* i.setAction("org.openintents.action.LOCATION_ALERT_DISPATCH");
* //i.setData(gUri); i.putExtra(Location.POSITION,
* cv.getAsString(Location.POSITION));
*
* locationManager.addProximityAlert( latitude, longitude, dist,
* LOCATION_EXPIRES, i );
* Log.d(_TAG,"Registerd alert geo:"+geo+" dist:"+dist);
* Log.d(_TAG,"Registered alert intent:" + i);
*/
} catch (ArrayIndexOutOfBoundsException aioe) {
Log.e(_TAG, "Error parsing geo uri. not in format geo:lat,long");
} catch (NumberFormatException nfe) {
Log.e(_TAG,
"Error parsing longitude/latitude. Not A Number (NAN)\n uri>>"
+ gUri + "<< \n dist>>" + distStr + "<<"
);
} catch (NullPointerException npe) {
Log.e(_TAG, "Nullpointer occured. did you call init(context) ?");
npe.printStackTrace();
}
// registerReceiver(org.openintents.alert.LocationAlertDispatcher,);
}
public static void init(Context c) {
context = c;
locationManager = (LocationManager) context
.getSystemService(Context.LOCATION_SERVICE);
mContentResolver = context.getContentResolver();
alarmManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
}
public static void registerDateTimeAlert(ContentValues cv) {
String myDate = cv.getAsString(DateTime.TIME);
String[] s = myDate.split(",");
Log.d(_TAG, "registerDateTimeAlert: s[0]>>" + s[0] + "<< s[1]>>+"
+ s[1] + "<<");
long time = 0;
long myReoccurence = cv.getAsLong(DateTime.REOCCURENCE);
Intent i = new Intent();
Bundle b = new Bundle();
b.putString(DateTime.TIME, myDate);
b.putLong(DateTime.REOCCURENCE, myReoccurence);
i.setAction(org.openintents.OpenIntents.DATE_TIME_ALERT_DISPATCH);
try {
time = Long.parseLong(s[1]);
} catch (NumberFormatException nfe) {
Log.e(_TAG,
"registerDateTimeAlert: Date/Time couldn't be parsed, check time format of >"
+ myDate + "<"
);
return;
}
if (myReoccurence == 0) {
// TODO new SDK cancle PendingIntent
// alarmManager.set(AlarmManager.RTC,time,i);
Log.d(_TAG, "registerDateTimeAlert: registerd single @>>" + time
+ "<<");
} else {
// TODO new SDK cancle PendingIntent
// alarmManager.setRepeating(AlarmManager.RTC,time,myReoccurence,i);
Log.d(_TAG, "registerDateTimeAlert: registerd reoccuirng @>>"
+ time + "<< intervall>>" + myReoccurence + "<<");
}
}
public static void unregisterDateTimeAlert(ContentValues cv) {
/*
* String myDate=cv.getAsString(DateTime.TIME); String
* s[]=myDate.split(",");
* Log.d(_TAG,"registerDateTimeAlert: s[0]>>"+s[0]
* +"<< s[1]>>+"+s[1]+"<<"); long time=0; long
* myReoccurence=cv.getAsLong(DateTime.REOCCURENCE);
*
* Cursor c=mContentResolver.query( DateTime.CONTENT_URI,
* DateTime.PROJECTION_MAP, DateTime.TIME+" like '"+myDate+"'", null
* null );
*
* if (c==null||c.count()==0) {//alert has been deleted
*
* }else if (c!=null&&c.count()==1) {//exactly out alert alarmManager. }
* //TODO: check if there are now other alerts at this time.
*/
// atm it would oly be possible to delete all dateTimeDispatch alerts
// and register the need a new. so we just leave them be, means some
// emtpy lookups, but hey! :/
}
static {
URL_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
URL_MATCHER.addURI("org.openintents.alert", "generic/", ALERT_GENERIC);
URL_MATCHER.addURI("org.openintents.alert", "generic/#",
ALERT_GENERIC_ID);
URL_MATCHER.addURI("org.openintents.alert", "location", ALERT_LOCATION);
URL_MATCHER.addURI("org.openintents.alert", "location/#",
ALERT_LOCATION_ID);
URL_MATCHER.addURI("org.openintents.alert", "combined", ALERT_COMBINED);
URL_MATCHER.addURI("org.openintents.alert", "combined/#",
ALERT_COMBINED_ID);
URL_MATCHER
.addURI("org.openintents.alert", "datetime", ALERT_DATE_TIME);
URL_MATCHER.addURI("org.openintents.alert", "datetime/#",
ALERT_DATE_TIME_ID);
URL_MATCHER.addURI("org.openintents.alert", "", 6000);
URL_MATCHER.addURI("org.openintents.alert", "/", 6001);
}
}/* eoc */