Mega Code Archive

 
Categories / Android / Network
 

Widget Service

/* 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<appWidgetIds.length; 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.app.Activity; 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.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.EditText; import android.widget.RadioGroup; import android.widget.TextView; import android.widget.Toast; public class DetailForm extends Activity {   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 savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.detail_form);          locMgr=(LocationManager)getSystemService(LOCATION_SERVICE);     helper=new RestaurantHelper(this);          name=(EditText)findViewById(R.id.name);     address=(EditText)findViewById(R.id.addr);     notes=(EditText)findViewById(R.id.notes);     types=(RadioGroup)findViewById(R.id.types);     feed=(EditText)findViewById(R.id.feed);     location=(TextView)findViewById(R.id.location);          restaurantId=getIntent().getStringExtra(LunchList.ID_EXTRA);          if (restaurantId!=null) {       load();     }   }      @Override   public void onPause() {     save();          super.onPause();   }      @Override   public void onDestroy() {     helper.close();     locMgr.removeUpdates(onLocationChange);          super.onDestroy();   }      @Override   public boolean onCreateOptionsMenu(Menu menu) {     new MenuInflater(this).inflate(R.menu.details_option, menu);     return(super.onCreateOptionsMenu(menu));   }   @Override   public boolean onPrepareOptionsMenu(Menu menu) {     if (restaurantId==null) {       menu.findItem(R.id.location).setEnabled(false);       menu.findItem(R.id.map).setEnabled(false);     }     return(super.onPrepareOptionsMenu(menu));   }      @Override   public boolean onOptionsItemSelected(MenuItem item) {     if (item.getItemId()==R.id.feed) {       if (isNetworkAvailable()) {         Intent i=new Intent(this, FeedActivity.class);                  i.putExtra(FeedActivity.FEED_URL, feed.getText().toString());         startActivity(i);       }       else {         Toast           .makeText(this, "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(this, 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)getSystemService(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(DetailForm.this, "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\LunchList.java package apt.tutorial; import android.app.ListActivity; 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.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 LunchList extends ListActivity {   public final static String ID_EXTRA="apt.tutorial._ID";   Cursor model=null;   RestaurantAdapter adapter=null;   RestaurantHelper helper=null;   SharedPreferences prefs=null;      @Override   public void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.main);          helper=new RestaurantHelper(this);     prefs=PreferenceManager.getDefaultSharedPreferences(this);     initList();     prefs.registerOnSharedPreferenceChangeListener(prefListener);   }      @Override   public void onDestroy() {     super.onDestroy();          helper.close();   }      @Override   public void onListItemClick(ListView list, View view,                               int position, long id) {     Intent i=new Intent(LunchList.this, DetailForm.class);     i.putExtra(ID_EXTRA, String.valueOf(id));     startActivity(i);   }      @Override   public boolean onCreateOptionsMenu(Menu menu) {     new MenuInflater(this).inflate(R.menu.option, menu);     return(super.onCreateOptionsMenu(menu));   }   @Override   public boolean onOptionsItemSelected(MenuItem item) {     if (item.getItemId()==R.id.add) {       startActivity(new Intent(LunchList.this, DetailForm.class));              return(true);     }     else if (item.getItemId()==R.id.prefs) {       startActivity(new Intent(this, EditPreferences.class));            return(true);     }     return(super.onOptionsItemSelected(item));   }      private void initList() {     if (model!=null) {       stopManagingCursor(model);       model.close();     }          model=helper.getAll(prefs.getString("sort_order", "name"));     startManagingCursor(model);     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();       }     }   };      class RestaurantAdapter extends CursorAdapter {     RestaurantAdapter(Cursor c) {       super(LunchList.this, 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=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\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()<System.currentTimeMillis()) {       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<OverlayItem> {     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 <?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"   android:minWidth="220dip"   android:minHeight="220dip"   android:updatePeriodMillis="1800000"   android:initialLayout="@layout/widget"   android:previewImage="@drawable/hc_widget_preview" /> // //res\xml\preferences.xml <PreferenceScreen   xmlns:android="http://schemas.android.com/apk/res/android">   <ListPreference     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" />   <CheckBoxPreference     android:key="alarm"     android:title="Sound a Lunch Alarm"     android:summary="Check if you want to know when it is time for lunch" />   <apt.tutorial.TimePreference     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" />   <CheckBoxPreference     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" /> </PreferenceScreen> //res\xml\widget_provider.xml <?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"    android:minWidth="300dip"    android:minHeight="79dip"    android:updatePeriodMillis="1800000"    android:initialLayout="@layout/widget" /> // //res\values\arrays.xml <?xml version="1.0" encoding="utf-8"?> <resources>   <string-array name="sort_names">     <item>By Name, Ascending</item>     <item>By Name, Descending</item>     <item>By Type</item>     <item>By Address, Ascending</item>     <item>By Address, Descending</item>   </string-array>   <string-array name="sort_clauses">     <item>name ASC</item>     <item>name DESC</item>     <item>type, name ASC</item>     <item>address ASC</item>     <item>address DESC</item>   </string-array> </resources> //res\values\strings.xml <?xml version="1.0" encoding="utf-8"?> <resources>     <string name="app_name">LunchList</string>     <string name="empty">No restaurants!</string> </resources> // //res\menu\details_option.xml <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android">   <item android:id="@+id/feed"     android:title="RSS Feed"     android:icon="@drawable/ic_menu_friendslist"   />   <item android:id="@+id/location"     android:title="Save Location"     android:icon="@drawable/ic_menu_compass"   />   <item android:id="@+id/map"     android:title="Show on Map"     android:icon="@drawable/ic_menu_mapmode"   /> </menu> //res\menu\option.xml <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android">   <item android:id="@+id/add"     android:title="Add"     android:icon="@drawable/ic_menu_add"   />   <item android:id="@+id/prefs"     android:title="Settings"     android:icon="@drawable/ic_menu_preferences"   /> </menu> // //res\layout-v11\widget.xml <?xml version="1.0" encoding="utf-8"?> <ListView xmlns:android="http://schemas.android.com/apk/res/android"   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 <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"   android:layout_width="fill_parent"   android:layout_height="wrap_content"   android:stretchColumns="2"   >   <TableRow>     <TextView android:text="Name:" />     <EditText android:id="@+id/name"       android:layout_span="2"     />   </TableRow>   <TableRow>     <TextView android:text="Address:" />     <EditText android:id="@+id/addr"       android:layout_span="2"     />   </TableRow>   <TableRow>     <TextView android:text="Type:" />     <RadioGroup android:id="@+id/types">       <RadioButton android:id="@+id/take_out"         android:text="Take-Out"       />       <RadioButton android:id="@+id/sit_down"         android:text="Sit-Down"       />       <RadioButton android:id="@+id/delivery"         android:text="Delivery"       />     </RadioGroup>     <LinearLayout android:orientation="vertical">       <EditText android:id="@+id/notes"         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"       />       <EditText android:id="@+id/feed"         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:hint="Feed URL"       />       <LinearLayout         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:orientation="horizontal"         >         <TextView android:text="Location:"           android:layout_width="wrap_content"           android:layout_height="wrap_content"         />         <TextView android:id="@+id/location"           android:text="(not set)"           android:layout_width="wrap_content"           android:layout_height="wrap_content"         />       </LinearLayout>     </LinearLayout>   </TableRow> </TableLayout> // //res\layout\alarm.xml <?xml version="1.0" encoding="utf-8"?> <TextView   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_form.xml <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"   android:layout_width="fill_parent"   android:layout_height="wrap_content"   android:stretchColumns="1"   >   <TableRow>     <TextView android:text="Name:" />     <EditText android:id="@+id/name" />   </TableRow>   <TableRow>     <TextView android:text="Address:" />     <EditText android:id="@+id/addr" />   </TableRow>   <TableRow>     <TextView android:text="Type:" />     <RadioGroup android:id="@+id/types">       <RadioButton android:id="@+id/take_out"         android:text="Take-Out"       />       <RadioButton android:id="@+id/sit_down"         android:text="Sit-Down"       />       <RadioButton android:id="@+id/delivery"         android:text="Delivery"       />     </RadioGroup>   </TableRow>   <TableRow>     <TextView android:text="Location:" />     <TextView android:id="@+id/location" android:text="(not set)" />   </TableRow>   <EditText android:id="@+id/notes"     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"   />   <EditText android:id="@+id/feed"     android:layout_span="2"     android:hint="Feed URL"   /> </TableLayout> //res\layout\main.xml <?xml version="1.0" encoding="utf-8"?> <ListView xmlns:android="http://schemas.android.com/apk/res/android"   android:id="@android:id/list"   android:layout_width="fill_parent"   android:layout_height="fill_parent" /> //res\layout\map.xml <?xml version="1.0" encoding="utf-8"?> <com.google.android.maps.MapView   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 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   android:layout_width="fill_parent"   android:layout_height="wrap_content"   android:orientation="horizontal"   android:padding="4dip"   >   <ImageView android:id="@+id/icon"     android:layout_width="wrap_content"     android:layout_height="fill_parent"     android:layout_alignParentTop="true"     android:layout_alignParentBottom="true"     android:layout_marginRight="4dip"   />   <LinearLayout     android:layout_width="fill_parent"     android:layout_height="wrap_content"     android:orientation="vertical"     >       <TextView android:id="@+id/title"       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"     />     <TextView android:id="@+id/address"       android:layout_width="fill_parent"       android:layout_height="wrap_content"       android:layout_weight="1"       android:gravity="center_vertical"       android:singleLine="true"       android:ellipsize="end"     />   </LinearLayout> </LinearLayout> //res\layout\widget.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"   android:layout_width="fill_parent"   android:layout_height="fill_parent"   android:background="@drawable/widget_frame" >   <TextView android:id="@+id/name"     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"   />   <ImageButton android:id="@id/next"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_centerVertical="true"     android:layout_alignParentRight="true"     android:src="@drawable/ff"   /> </RelativeLayout> //res\layout\widget_row.xml <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2006 The Android Open Source Project      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. --> <TextView xmlns:android="http://schemas.android.com/apk/res/android"     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" />