/*
Welcome to the source code for Android Programming Tutorials (http://commonsware.com/AndTutorials)!
Specifically, this is for Version 3.2 and above of this book.
For the source code for older versions of this book, please
visit:
https://github.com/commonsguy/cw-andtutorials
All of the source code in this archive is licensed under the
Apache 2.0 license except as noted.
The names of the top-level directories roughly correspond to a
shortened form of the chapter titles. Since chapter numbers
change with every release, and since some samples are used by
multiple chapters, I am loathe to put chapter numbers in the
actual directory names.
If you wish to use this code, bear in mind a few things:
* The projects are set up to be built by Ant, not by Eclipse.
If you wish to use the code with Eclipse, you will need to
create a suitable Android Eclipse project and import the
code and other assets.
* You should delete build.xml from the project, then run
android update project -p ...
(where ... is the path to a project of interest)
on those projects you wish to use, so the build files are
updated for your Android SDK version.
*/
//
//src\apt\tutorial\AlarmActivity.java
package apt.tutorial;
import android.app.Activity;
import android.os.Bundle;
public class AlarmActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.alarm);
}
}
//src\apt\tutorial\AppWidget.java
package apt.tutorial;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.widget.RemoteViews;
public class AppWidget extends AppWidgetProvider {
@Override
public void onUpdate(Context ctxt,
AppWidgetManager mgr,
int[] appWidgetIds) {
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) {
onHCUpdate(ctxt, mgr, appWidgetIds);
}
else {
ctxt.startService(new Intent(ctxt, WidgetService.class));
}
}
public void onHCUpdate(Context ctxt, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
for (int i=0; i Intent svcIntent=new Intent(ctxt, ListWidgetService.class);
svcIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
svcIntent.setData(Uri.parse(svcIntent.toUri(Intent.URI_INTENT_SCHEME)));
RemoteViews widget=new RemoteViews(ctxt.getPackageName(),
R.layout.widget);
widget.setRemoteAdapter(appWidgetIds[i], R.id.restaurants,
svcIntent);
Intent clickIntent=new Intent(ctxt, DetailForm.class);
PendingIntent clickPI=PendingIntent
.getActivity(ctxt, 0,
clickIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
widget.setPendingIntentTemplate(R.id.restaurants, clickPI);
appWidgetManager.updateAppWidget(appWidgetIds[i], widget);
}
super.onUpdate(ctxt, appWidgetManager, appWidgetIds);
}
}
//src\apt\tutorial\DetailForm.java
package apt.tutorial;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class DetailForm extends FragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.detail_activity);
}
}
//src\apt\tutorial\DetailFragment.java
package apt.tutorial;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
public class DetailFragment extends Fragment {
EditText name=null;
EditText address=null;
EditText notes=null;
EditText feed=null;
RadioGroup types=null;
RestaurantHelper helper=null;
String restaurantId=null;
TextView location=null;
LocationManager locMgr=null;
double latitude=0.0d;
double longitude=0.0d;
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return(inflater.inflate(R.layout.detail_form, container, false));
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
locMgr=(LocationManager)getActivity().
getSystemService(Context.LOCATION_SERVICE);
name=(EditText)getView().findViewById(R.id.name);
address=(EditText)getView().findViewById(R.id.addr);
notes=(EditText)getView().findViewById(R.id.notes);
types=(RadioGroup)getView().findViewById(R.id.types);
feed=(EditText)getView().findViewById(R.id.feed);
location=(TextView)getView().findViewById(R.id.location);
}
@Override
public void onResume() {
super.onResume();
helper=new RestaurantHelper(getActivity());
restaurantId=getActivity().getIntent().getStringExtra(LunchList.ID_EXTRA);
if (restaurantId!=null) {
load();
}
}
@Override
public void onPause() {
save();
helper.close();
locMgr.removeUpdates(onLocationChange);
super.onPause();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.details_option, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
if (restaurantId==null) {
menu.findItem(R.id.location).setEnabled(false);
menu.findItem(R.id.map).setEnabled(false);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId()==R.id.feed) {
if (isNetworkAvailable()) {
Intent i=new Intent(getActivity(), FeedActivity.class);
i.putExtra(FeedActivity.FEED_URL, feed.getText().toString());
startActivity(i);
}
else {
Toast
.makeText(getActivity(), "Sorry, the Internet is not available",
Toast.LENGTH_LONG)
.show();
}
return(true);
}
else if (item.getItemId()==R.id.location) {
locMgr.requestLocationUpdates(LocationManager.GPS_PROVIDER,
0, 0, onLocationChange);
return(true);
}
else if (item.getItemId()==R.id.map) {
Intent i=new Intent(getActivity(), RestaurantMap.class);
i.putExtra(RestaurantMap.EXTRA_LATITUDE, latitude);
i.putExtra(RestaurantMap.EXTRA_LONGITUDE, longitude);
i.putExtra(RestaurantMap.EXTRA_NAME, name.getText().toString());
startActivity(i);
return(true);
}
return(super.onOptionsItemSelected(item));
}
private boolean isNetworkAvailable() {
ConnectivityManager cm=(ConnectivityManager)getActivity().
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info=cm.getActiveNetworkInfo();
return(info!=null);
}
private void load() {
Cursor c=helper.getById(restaurantId);
c.moveToFirst();
name.setText(helper.getName(c));
address.setText(helper.getAddress(c));
notes.setText(helper.getNotes(c));
feed.setText(helper.getFeed(c));
if (helper.getType(c).equals("sit_down")) {
types.check(R.id.sit_down);
}
else if (helper.getType(c).equals("take_out")) {
types.check(R.id.take_out);
}
else {
types.check(R.id.delivery);
}
latitude=helper.getLatitude(c);
longitude=helper.getLongitude(c);
location.setText(String.valueOf(latitude)
+", "
+String.valueOf(longitude));
c.close();
}
private void save() {
if (name.getText().toString().length()>0) {
String type=null;
switch (types.getCheckedRadioButtonId()) {
case R.id.sit_down:
type="sit_down";
break;
case R.id.take_out:
type="take_out";
break;
default:
type="delivery";
break;
}
if (restaurantId==null) {
helper.insert(name.getText().toString(),
address.getText().toString(), type,
notes.getText().toString(),
feed.getText().toString());
}
else {
helper.update(restaurantId, name.getText().toString(),
address.getText().toString(), type,
notes.getText().toString(),
feed.getText().toString());
}
}
}
LocationListener onLocationChange=new LocationListener() {
public void onLocationChanged(Location fix) {
helper.updateLocation(restaurantId, fix.getLatitude(),
fix.getLongitude());
location.setText(String.valueOf(fix.getLatitude())
+", "
+String.valueOf(fix.getLongitude()));
locMgr.removeUpdates(onLocationChange);
Toast
.makeText(getActivity(), "Location saved",
Toast.LENGTH_LONG)
.show();
}
public void onProviderDisabled(String provider) {
// required for interface, not used
}
public void onProviderEnabled(String provider) {
// required for interface, not used
}
public void onStatusChanged(String provider, int status,
Bundle extras) {
// required for interface, not used
}
};
}
//src\apt\tutorial\EditPreferences.java
package apt.tutorial;
import android.app.Activity;
import android.content.ComponentName;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
public class EditPreferences extends PreferenceActivity {
SharedPreferences prefs=null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
@Override
public void onResume() {
super.onResume();
prefs=PreferenceManager.getDefaultSharedPreferences(this);
prefs.registerOnSharedPreferenceChangeListener(onChange);
}
@Override
public void onPause() {
prefs.unregisterOnSharedPreferenceChangeListener(onChange);
super.onPause();
}
SharedPreferences.OnSharedPreferenceChangeListener onChange=
new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs,
String key) {
if ("alarm".equals(key)) {
boolean enabled=prefs.getBoolean(key, false);
int flag=(enabled ?
PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
ComponentName component=new ComponentName(EditPreferences.this,
OnBootReceiver.class);
getPackageManager()
.setComponentEnabledSetting(component,
flag,
PackageManager.DONT_KILL_APP);
if (enabled) {
OnBootReceiver.setAlarm(EditPreferences.this);
}
else {
OnBootReceiver.cancelAlarm(EditPreferences.this);
}
}
else if ("alarm_time".equals(key)) {
OnBootReceiver.cancelAlarm(EditPreferences.this);
OnBootReceiver.setAlarm(EditPreferences.this);
}
}
};
}
//src\apt\tutorial\FeedActivity.java
package apt.tutorial;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import org.mcsoxford.rss.RSSItem;
import org.mcsoxford.rss.RSSFeed;
public class FeedActivity extends ListActivity {
public static final String FEED_URL="apt.tutorial.FEED_URL";
private InstanceState state=null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
state=(InstanceState)getLastNonConfigurationInstance();
if (state==null) {
state=new InstanceState();
state.handler=new FeedHandler(this);
Intent i=new Intent(this, FeedService.class);
i.putExtra(FeedService.EXTRA_URL,
getIntent().getStringExtra(FEED_URL));
i.putExtra(FeedService.EXTRA_MESSENGER,
new Messenger(state.handler));
startService(i);
}
else {
if (state.handler!=null) {
state.handler.attach(this);
}
if (state.feed!=null) {
setFeed(state.feed);
}
}
}
@Override
public Object onRetainNonConfigurationInstance() {
if (state.handler!=null) {
state.handler.detach();
}
return(state);
}
private void setFeed(RSSFeed feed) {
state.feed=feed;
setListAdapter(new FeedAdapter(feed));
}
private void goBlooey(Throwable t) {
AlertDialog.Builder builder=new AlertDialog.Builder(this);
builder
.setTitle("Exception!")
.setMessage(t.toString())
.setPositiveButton("OK", null)
.show();
}
private static class InstanceState {
RSSFeed feed=null;
FeedHandler handler=null;
}
private class FeedAdapter extends BaseAdapter {
RSSFeed feed=null;
FeedAdapter(RSSFeed feed) {
super();
this.feed=feed;
}
@Override
public int getCount() {
return(feed.getItems().size());
}
@Override
public Object getItem(int position) {
return(feed.getItems().get(position));
}
@Override
public long getItemId(int position) {
return(position);
}
@Override
public View getView(int position, View convertView,
ViewGroup parent) {
View row=convertView;
if (row==null) {
LayoutInflater inflater=getLayoutInflater();
row=inflater.inflate(android.R.layout.simple_list_item_1,
parent, false);
}
RSSItem item=(RSSItem)getItem(position);
((TextView)row).setText(item.getTitle());
return(row);
}
}
private static class FeedHandler extends Handler {
FeedActivity activity=null;
FeedHandler(FeedActivity activity) {
attach(activity);
}
void attach(FeedActivity activity) {
this.activity=activity;
}
void detach() {
this.activity=null;
}
@Override
public void handleMessage(Message msg) {
if (msg.arg1==RESULT_OK) {
activity.setFeed((RSSFeed)msg.obj);
}
else {
activity.goBlooey((Exception)msg.obj);
}
}
};
}
//src\apt\tutorial\FeedService.java
package apt.tutorial;
import android.app.Activity;
import android.app.IntentService;
import android.content.Intent;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
import org.mcsoxford.rss.RSSItem;
import org.mcsoxford.rss.RSSFeed;
import org.mcsoxford.rss.RSSReader;
public class FeedService extends IntentService {
public static final String EXTRA_URL="apt.tutorial.EXTRA_URL";
public static final String EXTRA_MESSENGER="apt.tutorial.EXTRA_MESSENGER";
public FeedService() {
super("FeedService");
}
@Override
public void onHandleIntent(Intent i) {
RSSReader reader=new RSSReader();
Messenger messenger=(Messenger)i.getExtras().get(EXTRA_MESSENGER);
Message msg=Message.obtain();
try {
RSSFeed result=reader.load(i.getStringExtra(EXTRA_URL));
msg.arg1=Activity.RESULT_OK;
msg.obj=result;
}
catch (Exception e) {
Log.e("LunchList", "Exception parsing feed", e);
msg.arg1=Activity.RESULT_CANCELED;
msg.obj=e;
}
try {
messenger.send(msg);
}
catch (Exception e) {
Log.w("LunchList", "Exception sending results to activity", e);
}
}
}
//src\apt\tutorial\ListViewsFactory.java
package apt.tutorial;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;
public class ListViewsFactory
implements RemoteViewsService.RemoteViewsFactory {
private Context ctxt=null;
private RestaurantHelper helper=null;
private Cursor restaurants=null;
public ListViewsFactory(Context ctxt, Intent intent) {
this.ctxt=ctxt;
}
@Override
public void onCreate() {
helper=new RestaurantHelper(ctxt);
restaurants=helper
.getReadableDatabase()
.rawQuery("SELECT _ID, name FROM restaurants", null);
}
@Override
public void onDestroy() {
restaurants.close();
helper.close();
}
@Override
public int getCount() {
return(restaurants.getCount());
}
@Override
public RemoteViews getViewAt(int position) {
RemoteViews row=new RemoteViews(ctxt.getPackageName(),
R.layout.widget_row);
restaurants.moveToPosition(position);
row.setTextViewText(android.R.id.text1,
restaurants.getString(1));
Intent i=new Intent();
Bundle extras=new Bundle();
extras.putString(LunchList.ID_EXTRA,
String.valueOf(restaurants.getInt(0)));
i.putExtras(extras);
row.setOnClickFillInIntent(android.R.id.text1, i);
return(row);
}
@Override
public RemoteViews getLoadingView() {
return(null);
}
@Override
public int getViewTypeCount() {
return(1);
}
@Override
public long getItemId(int position) {
restaurants.moveToPosition(position);
return(restaurants.getInt(0));
}
@Override
public boolean hasStableIds() {
return(true);
}
@Override
public void onDataSetChanged() {
// no-op
}
}
//src\apt\tutorial\ListWidgetService.java
package apt.tutorial;
import android.content.Intent;
import android.widget.RemoteViewsService;
public class ListWidgetService extends RemoteViewsService {
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return(new ListViewsFactory(this.getApplicationContext(),
intent));
}
}
//src\apt\tutorial\LunchFragment.java
package apt.tutorial;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.ListFragment;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
import android.widget.AdapterView;
import android.widget.CursorAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
public class LunchFragment extends ListFragment {
public final static String ID_EXTRA="apt.tutorial._ID";
Cursor model=null;
RestaurantAdapter adapter=null;
RestaurantHelper helper=null;
SharedPreferences prefs=null;
OnRestaurantListener listener=null;
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
setHasOptionsMenu(true);
}
@Override
public void onResume() {
super.onResume();
helper=new RestaurantHelper(getActivity());
prefs=PreferenceManager.getDefaultSharedPreferences(getActivity());
initList();
prefs.registerOnSharedPreferenceChangeListener(prefListener);
}
@Override
public void onPause() {
helper.close();
super.onPause();
}
@Override
public void onListItemClick(ListView list, View view,
int position, long id) {
if (listener!=null) {
listener.onRestaurantSelected(id);
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.option, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId()==R.id.add) {
startActivity(new Intent(getActivity(), DetailForm.class));
return(true);
}
else if (item.getItemId()==R.id.prefs) {
startActivity(new Intent(getActivity(), EditPreferences.class));
return(true);
}
return(super.onOptionsItemSelected(item));
}
public void setOnRestaurantListener(OnRestaurantListener listener) {
this.listener=listener;
}
private void initList() {
if (model!=null) {
model.close();
}
model=helper.getAll(prefs.getString("sort_order", "name"));
adapter=new RestaurantAdapter(model);
setListAdapter(adapter);
}
private SharedPreferences.OnSharedPreferenceChangeListener prefListener=
new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences sharedPrefs,
String key) {
if (key.equals("sort_order")) {
initList();
}
}
};
public interface OnRestaurantListener {
void onRestaurantSelected(long id);
}
class RestaurantAdapter extends CursorAdapter {
RestaurantAdapter(Cursor c) {
super(getActivity(), c);
}
@Override
public void bindView(View row, Context ctxt,
Cursor c) {
RestaurantHolder holder=(RestaurantHolder)row.getTag();
holder.populateFrom(c, helper);
}
@Override
public View newView(Context ctxt, Cursor c,
ViewGroup parent) {
LayoutInflater inflater=getActivity().getLayoutInflater();
View row=inflater.inflate(R.layout.row, parent, false);
RestaurantHolder holder=new RestaurantHolder(row);
row.setTag(holder);
return(row);
}
}
static class RestaurantHolder {
private TextView name=null;
private TextView address=null;
private ImageView icon=null;
RestaurantHolder(View row) {
name=(TextView)row.findViewById(R.id.title);
address=(TextView)row.findViewById(R.id.address);
icon=(ImageView)row.findViewById(R.id.icon);
}
void populateFrom(Cursor c, RestaurantHelper helper) {
name.setText(helper.getName(c));
address.setText(helper.getAddress(c));
if (helper.getType(c).equals("sit_down")) {
icon.setImageResource(R.drawable.ball_red);
}
else if (helper.getType(c).equals("take_out")) {
icon.setImageResource(R.drawable.ball_yellow);
}
else {
icon.setImageResource(R.drawable.ball_green);
}
}
}
}
//src\apt\tutorial\LunchList.java
package apt.tutorial;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class LunchList extends FragmentActivity
implements LunchFragment.OnRestaurantListener {
public final static String ID_EXTRA="apt.tutorial._ID";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LunchFragment lunch
=(LunchFragment)getSupportFragmentManager()
.findFragmentById(R.id.lunch);
lunch.setOnRestaurantListener(this);
}
public void onRestaurantSelected(long id) {
Intent i=new Intent(this, DetailForm.class);
i.putExtra(ID_EXTRA, String.valueOf(id));
startActivity(i);
}
}
//src\apt\tutorial\OnAlarmReceiver.java
package apt.tutorial;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
public class OnAlarmReceiver extends BroadcastReceiver {
private static final int NOTIFY_ME_ID=1337;
@Override
public void onReceive(Context ctxt, Intent intent) {
SharedPreferences prefs=PreferenceManager.getDefaultSharedPreferences(ctxt);
boolean useNotification=prefs.getBoolean("use_notification",
true);
if (useNotification) {
NotificationManager mgr=
(NotificationManager)ctxt.getSystemService(Context.NOTIFICATION_SERVICE);
Notification note=new Notification(R.drawable.stat_notify_chat,
"It's time for lunch!",
System.currentTimeMillis());
PendingIntent i=PendingIntent.getActivity(ctxt, 0,
new Intent(ctxt, AlarmActivity.class),
0);
note.setLatestEventInfo(ctxt, "LunchList",
"It's time for lunch! Aren't you hungry?",
i);
note.flags|=Notification.FLAG_AUTO_CANCEL;
mgr.notify(NOTIFY_ME_ID, note);
}
else {
Intent i=new Intent(ctxt, AlarmActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctxt.startActivity(i);
}
}
}
//src\apt\tutorial\OnBootReceiver.java
package apt.tutorial;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import java.util.Calendar;
public class OnBootReceiver extends BroadcastReceiver {
public static void setAlarm(Context ctxt) {
AlarmManager mgr=(AlarmManager)ctxt.getSystemService(Context.ALARM_SERVICE);
Calendar cal=Calendar.getInstance();
SharedPreferences prefs=PreferenceManager.getDefaultSharedPreferences(ctxt);
String time=prefs.getString("alarm_time", "12:00");
cal.set(Calendar.HOUR_OF_DAY, TimePreference.getHour(time));
cal.set(Calendar.MINUTE, TimePreference.getMinute(time));
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
if (cal.getTimeInMillis() cal.add(Calendar.DAY_OF_YEAR, 1);
}
android.util.Log.e("***OnBootReceiver", android.text.format.DateFormat.format("MM/dd/yy h:mmaa", cal).toString());
mgr.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
AlarmManager.INTERVAL_DAY,
getPendingIntent(ctxt));
}
public static void cancelAlarm(Context ctxt) {
AlarmManager mgr=(AlarmManager)ctxt.getSystemService(Context.ALARM_SERVICE);
mgr.cancel(getPendingIntent(ctxt));
}
private static PendingIntent getPendingIntent(Context ctxt) {
Intent i=new Intent(ctxt, OnAlarmReceiver.class);
return(PendingIntent.getBroadcast(ctxt, 0, i, 0));
}
@Override
public void onReceive(Context ctxt, Intent intent) {
android.util.Log.e("****OnBootReceiver", "got here");
setAlarm(ctxt);
}
}
//src\apt\tutorial\RestaurantHelper.java
package apt.tutorial;
import android.content.Context;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
class RestaurantHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME="lunchlist.db";
private static final int SCHEMA_VERSION=3;
public RestaurantHelper(Context context) {
super(context, DATABASE_NAME, null, SCHEMA_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE restaurants (_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, address TEXT, type TEXT, notes TEXT, feed TEXT, lat REAL, lon REAL);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion<2) {
db.execSQL("ALTER TABLE restaurants ADD COLUMN feed TEXT");
}
if (newVersion<3) {
db.execSQL("ALTER TABLE restaurants ADD COLUMN lat REAL");
db.execSQL("ALTER TABLE restaurants ADD COLUMN lon REAL");
}
}
public Cursor getAll(String orderBy) {
return(getReadableDatabase()
.rawQuery("SELECT _id, name, address, type, notes, lat, lon FROM restaurants ORDER BY "+orderBy,
null));
}
public Cursor getById(String id) {
String[] args={id};
return(getReadableDatabase()
.rawQuery("SELECT _id, name, address, type, notes, feed, lat, lon FROM restaurants WHERE _ID=?",
args));
}
public void insert(String name, String address,
String type, String notes,
String feed) {
ContentValues cv=new ContentValues();
cv.put("name", name);
cv.put("address", address);
cv.put("type", type);
cv.put("notes", notes);
cv.put("feed", feed);
getWritableDatabase().insert("restaurants", "name", cv);
}
public void update(String id, String name, String address,
String type, String notes, String feed) {
ContentValues cv=new ContentValues();
String[] args={id};
cv.put("name", name);
cv.put("address", address);
cv.put("type", type);
cv.put("notes", notes);
cv.put("feed", feed);
getWritableDatabase().update("restaurants", cv, "_ID=?",
args);
}
public void updateLocation(String id, double lat, double lon) {
ContentValues cv=new ContentValues();
String[] args={id};
cv.put("lat", lat);
cv.put("lon", lon);
getWritableDatabase().update("restaurants", cv, "_ID=?",
args);
}
public String getName(Cursor c) {
return(c.getString(1));
}
public String getAddress(Cursor c) {
return(c.getString(2));
}
public String getType(Cursor c) {
return(c.getString(3));
}
public String getNotes(Cursor c) {
return(c.getString(4));
}
public String getFeed(Cursor c) {
return(c.getString(5));
}
public double getLatitude(Cursor c) {
return(c.getDouble(6));
}
public double getLongitude(Cursor c) {
return(c.getDouble(7));
}
}
//src\apt\tutorial\RestaurantMap.java
package apt.tutorial;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.widget.Toast;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;
public class RestaurantMap extends MapActivity {
public static final String EXTRA_LATITUDE="apt.tutorial.EXTRA_LATITUDE";
public static final String EXTRA_LONGITUDE="apt.tutorial.EXTRA_LONGITUDE";
public static final String EXTRA_NAME="apt.tutorial.EXTRA_NAME";
private MapView map=null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map);
double lat=getIntent().getDoubleExtra(EXTRA_LATITUDE, 0);
double lon=getIntent().getDoubleExtra(EXTRA_LONGITUDE, 0);
map=(MapView)findViewById(R.id.map);
map.getController().setZoom(17);
GeoPoint status=new GeoPoint((int)(lat*1000000.0),
(int)(lon*1000000.0));
map.getController().setCenter(status);
map.setBuiltInZoomControls(true);
Drawable marker=getResources().getDrawable(R.drawable.marker);
marker.setBounds(0, 0, marker.getIntrinsicWidth(),
marker.getIntrinsicHeight());
map
.getOverlays()
.add(new RestaurantOverlay(marker, status,
getIntent().getStringExtra(EXTRA_NAME)));
}
@Override
protected boolean isRouteDisplayed() {
return(false);
}
private class RestaurantOverlay extends ItemizedOverlay {
private OverlayItem item=null;
public RestaurantOverlay(Drawable marker, GeoPoint point,
String name) {
super(marker);
boundCenterBottom(marker);
item=new OverlayItem(point, name, name);
populate();
}
@Override
protected OverlayItem createItem(int i) {
return(item);
}
@Override
protected boolean onTap(int i) {
Toast.makeText(RestaurantMap.this,
item.getSnippet(),
Toast.LENGTH_SHORT).show();
return(true);
}
@Override
public int size() {
return(1);
}
}
}
//src\apt\tutorial\TimePreference.java
package apt.tutorial;
import android.content.Context;
import android.content.res.TypedArray;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TimePicker;
public class TimePreference extends DialogPreference {
private int lastHour=0;
private int lastMinute=0;
private TimePicker picker=null;
public static int getHour(String time) {
String[] pieces=time.split(":");
return(Integer.parseInt(pieces[0]));
}
public static int getMinute(String time) {
String[] pieces=time.split(":");
return(Integer.parseInt(pieces[1]));
}
public TimePreference(Context ctxt, AttributeSet attrs) {
super(ctxt, attrs);
setPositiveButtonText("Set");
setNegativeButtonText("Cancel");
}
@Override
protected View onCreateDialogView() {
picker=new TimePicker(getContext());
return(picker);
}
@Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
picker.setCurrentHour(lastHour);
picker.setCurrentMinute(lastMinute);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
lastHour=picker.getCurrentHour();
lastMinute=picker.getCurrentMinute();
String time=String.valueOf(lastHour)+":"+String.valueOf(lastMinute);
if (callChangeListener(time)) {
persistString(time);
}
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return(a.getString(index));
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
String time=null;
if (restoreValue) {
if (defaultValue==null) {
time=getPersistedString("00:00");
}
else {
time=getPersistedString(defaultValue.toString());
}
}
else {
time=defaultValue.toString();
}
lastHour=getHour(time);
lastMinute=getMinute(time);
}
}
//src\apt\tutorial\WidgetService.java
package apt.tutorial;
import android.app.IntentService;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.widget.RemoteViews;
public class WidgetService extends IntentService {
public WidgetService() {
super("WidgetService");
}
@Override
public void onHandleIntent(Intent intent) {
ComponentName me=new ComponentName(this, AppWidget.class);
RemoteViews updateViews=new RemoteViews("apt.tutorial",
R.layout.widget);
RestaurantHelper helper=new RestaurantHelper(this);
AppWidgetManager mgr=AppWidgetManager.getInstance(this);
try {
Cursor c=helper
.getReadableDatabase()
.rawQuery("SELECT COUNT(*) FROM restaurants", null);
c.moveToFirst();
int count=c.getInt(0);
c.close();
if (count>0) {
int offset=(int)(count*Math.random());
String args[]={String.valueOf(offset)};
c=helper
.getReadableDatabase()
.rawQuery("SELECT _ID, name FROM restaurants LIMIT 1 OFFSET ?", args);
c.moveToFirst();
updateViews.setTextViewText(R.id.name, c.getString(1));
Intent i=new Intent(this, DetailForm.class);
i.putExtra(LunchList.ID_EXTRA, c.getString(0));
PendingIntent pi=PendingIntent.getActivity(this, 0, i,
PendingIntent.FLAG_UPDATE_CURRENT);
updateViews.setOnClickPendingIntent(R.id.name, pi);
}
else {
updateViews.setTextViewText(R.id.title,
this.getString(R.string.empty));
}
}
finally {
helper.close();
}
Intent i=new Intent(this, WidgetService.class);
PendingIntent pi=PendingIntent.getService(this, 0, i, 0);
updateViews.setOnClickPendingIntent(R.id.next, pi);
mgr.updateAppWidget(me, updateViews);
}
}
//
//res\xml-v11\widget_provider.xml
android:minWidth="220dip"
android:minHeight="220dip"
android:updatePeriodMillis="1800000"
android:initialLayout="@layout/widget"
android:previewImage="@drawable/hc_widget_preview"
/>
//
//res\xml\preferences.xml
xmlns:android="http://schemas.android.com/apk/res/android">
android:key="sort_order"
android:title="Sort Order"
android:summary="Choose the order the list uses"
android:entries="@array/sort_names"
android:entryValues="@array/sort_clauses"
android:dialogTitle="Choose a sort order" />
android:key="alarm"
android:title="Sound a Lunch Alarm"
android:summary="Check if you want to know when it is time for lunch" />
android:key="alarm_time"
android:title="Lunch Alarm Time"
android:defaultValue="12:00"
android:summary="Set your desired time for the lunch alarm"
android:dependency="alarm" />
android:key="use_notification"
android:title="Use a Notification"
android:defaultValue="true"
android:summary="Check if you want a status bar icon at lunchtime, or uncheck for a full-screen notice"
android:dependency="alarm" />
//res\xml\widget_provider.xml
android:minWidth="300dip"
android:minHeight="79dip"
android:updatePeriodMillis="1800000"
android:initialLayout="@layout/widget"
/>
//
//res\values\arrays.xml
- By Name, Ascending
- By Name, Descending
- By Type
- By Address, Ascending
- By Address, Descending
- name ASC
- name DESC
- type, name ASC
- address ASC
- address DESC
//res\values\strings.xml
LunchList
No restaurants!
//
//res\menu\details_option.xml
//res\menu\option.xml
//
//res\layout-v11\widget.xml
android:id="@+id/restaurants"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginTop="3dp"
android:layout_marginLeft="3dp"
android:background="@drawable/widget_frame"
/>
//
//res\layout-land\detail_form.xml
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="2"
>
android:layout_span="2"
/>
android:layout_span="2"
/>
android:text="Take-Out"
/>
android:text="Sit-Down"
/>
android:text="Delivery"
/>
android:singleLine="false"
android:gravity="top"
android:lines="2"
android:scrollHorizontally="false"
android:maxLines="2"
android:maxWidth="140sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="Notes"
/>
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="Feed URL"
/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
android:text="(not set)"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
//
//res\layout\alarm.xml
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="It's time for lunch!"
android:textSize="30sp"
android:textStyle="bold"
/>
//res\layout\detail_activity.xml
class="apt.tutorial.DetailFragment"
android:id="@+id/details"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
//res\layout\detail_form.xml
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="1"
>
android:text="Take-Out"
/>
android:text="Sit-Down"
/>
android:text="Delivery"
/>
android:singleLine="false"
android:gravity="top"
android:lines="2"
android:scrollHorizontally="false"
android:maxLines="2"
android:maxWidth="200sp"
android:layout_span="2"
android:hint="Notes"
android:layout_marginTop="4dip"
/>
android:layout_span="2"
android:hint="Feed URL"
/>
//res\layout\main.xml
class="apt.tutorial.LunchFragment"
android:id="@+id/lunch"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
//res\layout\map.xml
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:apiKey="00yHj0k7_7vxbuQ9zwyXI4bNMJrAjYrJ9KKHgbQ"
android:clickable="true" />
//res\layout\row.xml
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="4dip"
>
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="4dip"
/>
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:textStyle="bold"
android:singleLine="true"
android:ellipsize="end"
/>
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:singleLine="true"
android:ellipsize="end"
/>
//res\layout\widget.xml
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/widget_frame"
>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@+id/next"
android:textSize="10pt"
android:textColor="#FFFFFFFF"
/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:src="@drawable/ff"
/>
//res\layout\widget_row.xml
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="center_vertical"
android:paddingLeft="6dip"
android:minHeight="?android:attr/listPreferredItemHeight"
/>