Mega Code Archive

 
Categories / Android / Core Class
 

Application Widget

/* 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.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.Context; import android.content.Intent; public class AppWidget extends AppWidgetProvider {   @Override   public void onUpdate(Context ctxt,                         AppWidgetManager mgr,                         int[] appWidgetIds) {     ctxt.startService(new Intent(ctxt, WidgetService.class));   } } //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\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 (oldVersion<2) {       db.execSQL("ALTER TABLE restaurants ADD COLUMN feed TEXT");     }          if (oldVersion<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);                  c.close();       }       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\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-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>