Android Tutorial - Network : Service
Map Service
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.os.Bundle; import android.preference.PreferenceActivity; public class EditPreferences extends PreferenceActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); } } //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\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); } } } //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" /> </PreferenceScreen> //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> </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\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>
Widget Service
//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" />
Restful web service task
package app.test; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.DefaultHttpClient; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; public class RestTask extends AsyncTask<HttpUriRequest, Void, String> { public static final String HTTP_RESPONSE = "httpResponse"; private Context mContext; private HttpClient mClient; private String mAction; public RestTask(Context context, String action) { mContext = context; mAction = action; mClient = new DefaultHttpClient(); } public RestTask(Context context, String action, HttpClient client) { mContext = context; mAction = action; mClient = client; } @Override protected String doInBackground(HttpUriRequest... params) { try{ HttpUriRequest request = params[0]; HttpResponse serverResponse = mClient.execute(request); BasicResponseHandler handler = new BasicResponseHandler(); String response = handler.handleResponse(serverResponse); return response; } catch (Exception e) { e.printStackTrace(); return null; } } @Override protected void onPostExecute(String result) { Intent intent = new Intent(mAction); intent.putExtra(HTTP_RESPONSE, result); //Broadcast the completion mContext.sendBroadcast(intent); } }
Search with Restful service
package app.test; import java.net.URI; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.DefaultHttpClient; import android.app.Activity; import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.AsyncTask; import android.os.Bundle; import android.widget.TextView; class RestTask extends AsyncTask<HttpUriRequest, Void, String> { public static final String HTTP_RESPONSE = "httpResponse"; private Context mContext; private HttpClient mClient; private String mAction; public RestTask(Context context, String action) { mContext = context; mAction = action; mClient = new DefaultHttpClient(); } public RestTask(Context context, String action, HttpClient client) { mContext = context; mAction = action; mClient = client; } @Override protected String doInBackground(HttpUriRequest... params) { try { HttpUriRequest request = params[0]; HttpResponse serverResponse = mClient.execute(request); BasicResponseHandler handler = new BasicResponseHandler(); String response = handler.handleResponse(serverResponse); return response; } catch (Exception e) { e.printStackTrace(); return null; } } @Override protected void onPostExecute(String result) { Intent intent = new Intent(mAction); intent.putExtra(HTTP_RESPONSE, result); // Broadcast the completion mContext.sendBroadcast(intent); } } public class Test extends Activity { private static final String SEARCH_ACTION = "com.examples.rest.SEARCH"; private static final String SEARCH_URI = "http://search.yahooapis.com/WebSearchService/V1/webSearch?appid=%s&query=%s"; private TextView result; private ProgressDialog progress; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTitle("Activity"); result = new TextView(this); setContentView(result); try { String url = String.format(SEARCH_URI, "YahooDemo", "Android"); HttpGet searchRequest = new HttpGet(new URI(url)); RestTask task = new RestTask(this, SEARCH_ACTION); task.execute(searchRequest); progress = ProgressDialog.show(this, "Searching","Waiting For Results...", true); } catch (Exception e) { e.printStackTrace(); } } @Override public void onResume() { super.onResume(); registerReceiver(receiver, new IntentFilter(SEARCH_ACTION)); } @Override public void onPause() { super.onPause(); unregisterReceiver(receiver); } private BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (progress != null) { progress.dismiss(); } String response = intent.getStringExtra(RestTask.HTTP_RESPONSE); result.setText(response); } }; }
Post Restful service
package app.test; import java.net.URI; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import android.app.Activity; import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.AsyncTask; import android.os.Bundle; import android.widget.TextView; class RestTask extends AsyncTask<HttpUriRequest, Void, String> { public static final String HTTP_RESPONSE = "httpResponse"; private Context mContext; private HttpClient mClient; private String mAction; public RestTask(Context context, String action) { mContext = context; mAction = action; mClient = new DefaultHttpClient(); } public RestTask(Context context, String action, HttpClient client) { mContext = context; mAction = action; mClient = client; } @Override protected String doInBackground(HttpUriRequest... params) { try { HttpUriRequest request = params[0]; HttpResponse serverResponse = mClient.execute(request); BasicResponseHandler handler = new BasicResponseHandler(); String response = handler.handleResponse(serverResponse); return response; } catch (Exception e) { e.printStackTrace(); return null; } } @Override protected void onPostExecute(String result) { Intent intent = new Intent(mAction); intent.putExtra(HTTP_RESPONSE, result); // Broadcast the completion mContext.sendBroadcast(intent); } } public class Test extends Activity { private static final String SEARCH_ACTION = "com.examples.rest.SEARCH"; private static final String SEARCH_URI = "http://search.yahooapis.com/WebSearchService/V1/webSearch"; private static final String SEARCH_QUERY = "Android"; private TextView result; private ProgressDialog progress; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTitle("Activity"); result = new TextView(this); setContentView(result); try { HttpPost searchRequest = new HttpPost(new URI(SEARCH_URI)); List<NameValuePair> parameters = new ArrayList<NameValuePair>(); parameters.add(new BasicNameValuePair("appid", "YahooDemo")); parameters.add(new BasicNameValuePair("query", SEARCH_QUERY)); searchRequest.setEntity(new UrlEncodedFormEntity(parameters)); RestTask task = new RestTask(this, SEARCH_ACTION); task.execute(searchRequest); progress = ProgressDialog.show(this, "Searching", "Waiting For Results...", true); } catch (Exception e) { e.printStackTrace(); } } @Override public void onResume() { super.onResume(); registerReceiver(receiver, new IntentFilter(SEARCH_ACTION)); } @Override public void onPause() { super.onPause(); unregisterReceiver(receiver); } private BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (progress != null) { progress.dismiss(); } String response = intent.getStringExtra(RestTask.HTTP_RESPONSE); result.setText(response); } }; }
Tracker Service
package app.test; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.widget.Button; import android.widget.TextView; import android.view.View; import java.util.ArrayList; import android.app.Service; import android.content.Intent; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.widget.Toast; class TrackerService extends Service implements LocationListener { private static final String LOGTAG = "TrackerService"; private LocationManager manager; private ArrayList<Location> storedLocations; private boolean isTracking = false; @Override public void onCreate() { manager = (LocationManager)getSystemService(LOCATION_SERVICE); storedLocations = new ArrayList<Location>(); Log.i(LOGTAG, "Tracking Service Running..."); } public void startTracking() { if(!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { return; } Toast.makeText(this, "Starting Tracker", Toast.LENGTH_SHORT).show(); manager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 30000, 0, this); isTracking = true; } public void stopTracking() { Toast.makeText(this, "Stopping Tracker", Toast.LENGTH_SHORT).show(); manager.removeUpdates(this); isTracking = false; } public boolean isTracking() { return isTracking; } @Override public void onDestroy() { manager.removeUpdates(this); Log.i(LOGTAG, "Tracking Service Stopped..."); } public class TrackerBinder extends Binder { TrackerService getService() { return TrackerService.this; } } private final IBinder binder = new TrackerBinder(); @Override public IBinder onBind(Intent intent) { return binder; } public int getLocationsCount() { return storedLocations.size(); } public ArrayList<Location> getLocations() { return storedLocations; } @Override public void onLocationChanged(Location location) { Log.i("TrackerService", "Adding new location"); storedLocations.add(location); } @Override public void onProviderDisabled(String provider) { } @Override public void onProviderEnabled(String provider) { } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } } public class Test extends Activity implements View.OnClickListener { Button enableButton, disableButton; TextView statusView; TrackerService trackerService; Intent serviceIntent; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); enableButton = (Button)findViewById(R.id.enable); enableButton.setOnClickListener(this); disableButton = (Button)findViewById(R.id.disable); disableButton.setOnClickListener(this); statusView = (TextView)findViewById(R.id.status); serviceIntent = new Intent(this, TrackerService.class); } @Override public void onResume() { super.onResume(); startService(serviceIntent); bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE); } @Override public void onPause() { super.onPause(); if(!trackerService.isTracking()) { stopService(serviceIntent); } unbindService(serviceConnection); } @Override public void onClick(View v) { switch(v.getId()) { case R.id.enable: trackerService.startTracking(); break; case R.id.disable: trackerService.stopTracking(); break; default: break; } updateStatus(); } private void updateStatus() { if(trackerService.isTracking()) { statusView.setText(String.format("Tracking enabled. %d locations logged.",trackerService.getLocationsCount())); } else { statusView.setText("Tracking not currently enabled."); } } private ServiceConnection serviceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { trackerService = ((TrackerService.TrackerBinder)service).getService(); updateStatus(); } public void onServiceDisconnected(ComponentName className) { trackerService = null; } }; }
Weather web service
package com.commonsware.android.service; import android.app.Activity; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.os.Bundle; import android.os.DeadObjectException; import android.os.RemoteException; import android.os.IBinder; import android.view.Menu; import android.view.MenuItem; import android.webkit.WebView; import android.widget.Toast; public class WeatherPlus extends Activity { private static final int CLOSE_ID = Menu.FIRST+1; private WebView browser; private WeatherPlusService appService=null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); browser=(WebView)findViewById(R.id.webkit); bindService(new Intent(this, WeatherPlusService.class), onService, Context.BIND_AUTO_CREATE); } @Override public void onResume() { super.onResume(); registerReceiver(receiver, new IntentFilter(WeatherPlusService.BROADCAST_ACTION)); } @Override public void onPause() { super.onPause(); unregisterReceiver(receiver); } @Override public void onDestroy() { super.onDestroy(); unbindService(onService); } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(Menu.NONE, CLOSE_ID, Menu.NONE, "Close") .setIcon(R.drawable.eject) .setAlphabeticShortcut('c'); return(super.onCreateOptionsMenu(menu)); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case CLOSE_ID: finish(); return(true); } return(super.onOptionsItemSelected(item)); } private void updateForecast() { try { String page=appService.getForecastPage(); browser.loadDataWithBaseURL(null, page, "text/html", "UTF-8", null); } catch (final Throwable t) { goBlooey(t); } } private void goBlooey(Throwable t) { AlertDialog.Builder builder=new AlertDialog.Builder(this); builder .setTitle("Exception!") .setMessage(t.toString()) .setPositiveButton("OK", null) .show(); } private BroadcastReceiver receiver=new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { updateForecast(); } }; private ServiceConnection onService=new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder rawBinder) { appService=((WeatherPlusService.LocalBinder)rawBinder).getService(); } public void onServiceDisconnected(ComponentName className) { appService=null; } }; } //src\com\commonsware\android\service\WeatherPlusService.java /*** Copyright (c) 2008-2009 CommonsWare, LLC 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. */ package com.commonsware.android.service; import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.location.Criteria; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.AsyncTask; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import java.io.StringReader; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.http.client.ResponseHandler; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.DefaultHttpClient; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; public class WeatherPlusService extends Service { public static final int NOTIF_ID=1337; public static final String SHUTDOWN="SHUTDOWN"; public static final String BROADCAST_ACTION= "com.commonsware.android.service.ForecastUpdateEvent"; private LocationManager mgr=null; private String forecast=null; private HttpClient client=null; private String format=null; private Intent broadcast=new Intent(BROADCAST_ACTION); private final Binder binder=new LocalBinder(); @Override public void onCreate() { super.onCreate(); client=new DefaultHttpClient(); format=getString(R.string.url); mgr=(LocationManager)getSystemService(Context.LOCATION_SERVICE); mgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 10000.0f, onLocationChange); } @Override public IBinder onBind(Intent intent) { return(binder); } @Override public void onDestroy() { super.onDestroy(); mgr.removeUpdates(onLocationChange); } synchronized public String getForecastPage() { return(forecast); } private void updateForecast(Location loc) { new FetchForecastTask().execute(loc); } List<Forecast> buildForecasts(String raw) throws Exception { List<Forecast> forecasts=new ArrayList<Forecast>(); DocumentBuilder builder=DocumentBuilderFactory .newInstance() .newDocumentBuilder(); Document doc=builder.parse(new InputSource(new StringReader(raw))); NodeList times=doc.getElementsByTagName("start-valid-time"); for (int i=0;i<times.getLength();i++) { Element time=(Element)times.item(i); Forecast forecast=new Forecast(); forecasts.add(forecast); forecast.setTime(time.getFirstChild().getNodeValue()); } NodeList temps=doc.getElementsByTagName("value"); for (int i=0;i<temps.getLength();i++) { Element temp=(Element)temps.item(i); Forecast forecast=forecasts.get(i); forecast.setTemp(new Integer(temp.getFirstChild().getNodeValue())); } NodeList icons=doc.getElementsByTagName("icon-link"); for (int i=0;i<icons.getLength();i++) { Element icon=(Element)icons.item(i); Forecast forecast=forecasts.get(i); forecast.setIcon(icon.getFirstChild().getNodeValue()); } return(forecasts); } String generatePage(List<Forecast> forecasts) { StringBuilder bufResult=new StringBuilder("<html><body><table>"); bufResult.append("<tr><th width=\"50%\">Time</th>"+ "<th>Temperature</th><th>Forecast</th></tr>"); for (Forecast forecast : forecasts) { bufResult.append("<tr><td align=\"center\">"); bufResult.append(forecast.getTime()); bufResult.append("</td><td align=\"center\">"); bufResult.append(forecast.getTemp()); bufResult.append("</td><td><img src=\""); bufResult.append(forecast.getIcon()); bufResult.append("\"></td></tr>"); } bufResult.append("</table></body></html>"); return(bufResult.toString()); } LocationListener onLocationChange=new LocationListener() { public void onLocationChanged(Location location) { updateForecast(location); } 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 } }; public class LocalBinder extends Binder { WeatherPlusService getService() { return(WeatherPlusService.this); } } class Forecast { String time=""; Integer temp=null; String iconUrl=""; String getTime() { return(time); } void setTime(String time) { this.time=time.substring(0,16).replace('T', ' '); } Integer getTemp() { return(temp); } void setTemp(Integer temp) { this.temp=temp; } String getIcon() { return(iconUrl); } void setIcon(String iconUrl) { this.iconUrl=iconUrl; } } class FetchForecastTask extends AsyncTask<Location, Void, Void> { @Override protected Void doInBackground(Location... locs) { Location loc=locs[0]; String url=String.format(format, loc.getLatitude(), loc.getLongitude()); HttpGet getMethod=new HttpGet(url); try { ResponseHandler<String> responseHandler=new BasicResponseHandler(); String responseBody=client.execute(getMethod, responseHandler); String page=generatePage(buildForecasts(responseBody)); synchronized(this) { forecast=page; } sendBroadcast(broadcast); } catch (Throwable t) { android.util.Log.e("WeatherPlus", "Exception in updateForecast()", t); } return(null); } @Override protected void onProgressUpdate(Void... unused) { // not needed here } @Override protected void onPostExecute(Void unused) { // not needed here } } } //res\layout\main.xml <?xml version="1.0" encoding="utf-8"?> <WebView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/webkit" android:layout_width="fill_parent" android:layout_height="fill_parent" />
Access a Web service using GET
package app.test; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; public class Test extends Activity { ImageView img; private class BackgroundTask extends AsyncTask<String, Void, Bitmap> { protected Bitmap doInBackground(String... url) { // ---download an image--- Bitmap bitmap = DownloadImage(url[0]); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return bitmap; } protected void onPostExecute(Bitmap bitmap) { ImageView img = (ImageView) findViewById(R.id.img); img.setImageBitmap(bitmap); } } private InputStream OpenHttpConnection(String urlString) throws IOException { InputStream in = null; int response = -1; URL url = new URL(urlString); URLConnection conn = url.openConnection(); if (!(conn instanceof HttpURLConnection)) throw new IOException("Not an HTTP connection"); try { HttpURLConnection httpConn = (HttpURLConnection) conn; httpConn.setAllowUserInteraction(false); httpConn.setInstanceFollowRedirects(true); httpConn.setRequestMethod("GET"); httpConn.connect(); response = httpConn.getResponseCode(); if (response == HttpURLConnection.HTTP_OK) { in = httpConn.getInputStream(); } } catch (Exception ex) { throw new IOException("Error connecting"); } return in; } private Bitmap DownloadImage(String URL) { Bitmap bitmap = null; InputStream in = null; try { in = OpenHttpConnection(URL); bitmap = BitmapFactory.decodeStream(in); in.close(); } catch (IOException e1) { Toast.makeText(this, e1.getLocalizedMessage(), Toast.LENGTH_LONG) .show(); e1.printStackTrace(); } return bitmap; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button btnOpen = (Button) findViewById(R.id.Button01); btnOpen.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { new BackgroundTask().execute("http://yourHost.com/1.jpg"); String str = DownloadText("http://yourHost.com/a.rss"); Toast.makeText(getBaseContext(), str, Toast.LENGTH_SHORT) .show(); WordDefinition("Apple"); } }); } private String DownloadText(String URL) { int BUFFER_SIZE = 2000; InputStream in = null; try { in = OpenHttpConnection(URL); } catch (IOException e1) { e1.printStackTrace(); return ""; } InputStreamReader isr = new InputStreamReader(in); int charRead; String str = ""; char[] inputBuffer = new char[BUFFER_SIZE]; try { while ((charRead = isr.read(inputBuffer)) > 0) { String readString = String.copyValueOf(inputBuffer, 0, charRead); str += readString; inputBuffer = new char[BUFFER_SIZE]; } in.close(); } catch (IOException e) { e.printStackTrace(); return ""; } return str; } private void WordDefinition(String word) { InputStream in = null; try { in = OpenHttpConnection("http://services.aonaware.com/DictService/DictService.asmx/Define?word="+ word); Document doc = null; DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db; try { db = dbf.newDocumentBuilder(); doc = db.parse(in); } catch (Exception e) { e.printStackTrace(); } doc.getDocumentElement().normalize(); // ---retrieve all the <Definition> nodes--- NodeList definitionElements = doc.getElementsByTagName("Definition"); String strDefinition = ""; for (int i = 0; i < definitionElements.getLength(); i++) { Node itemNode = definitionElements.item(i); if (itemNode.getNodeType() == Node.ELEMENT_NODE) { Element definitionElement = (Element) itemNode; NodeList wordDefinitionElements = (definitionElement) .getElementsByTagName("WordDefinition"); strDefinition = ""; for (int j = 0; j < wordDefinitionElements.getLength(); j++) { Element wordDefinitionElement = (Element) wordDefinitionElements .item(j); NodeList textNodes = ((Node) wordDefinitionElement) .getChildNodes(); strDefinition += ((Node) textNodes.item(0)) .getNodeValue() + ". "; } Toast.makeText(getBaseContext(), strDefinition, Toast.LENGTH_SHORT).show(); } } } catch (IOException e1) { e1.printStackTrace(); } } } //main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> <Button android:text="Download Content" android:id="@+id/Button01" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
Alarm service
//http://moazzam-khan.com/blog/?p=157 package app.test; import java.util.Calendar; import android.app.Activity; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent arg1) { context.startService(new Intent(context, AlarmReceiver.class)); } } public class Test extends Activity implements OnClickListener { private static Test appRef = null; private Button b_call_service, b_exit_service; boolean k = false; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); appRef = this; setContentView(R.layout.main); b_call_service = (Button) findViewById(R.id.call_alarm_service); b_call_service.setOnClickListener(this); b_exit_service = (Button) findViewById(R.id.exit); b_exit_service.setOnClickListener(this); } public static Test getApp() { return appRef; } public void btEvent(String data) { setTitle(data); } public void onClick(View arg0) { if (arg0 == b_call_service) { setTitle("Waiting... Alarm=5"); Intent intent = new Intent(Test.this, AlarmReceiver.class); PendingIntent p_intent = PendingIntent.getBroadcast( Test.this, 0, intent, 0); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.add(Calendar.SECOND, 5); AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE); am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), p_intent); } if (arg0 == b_exit_service) { Intent intent = new Intent(Test.this, AlarmReceiver.class); PendingIntent p_intent = PendingIntent.getBroadcast( Test.this, 0, intent, 0); AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE); am.cancel(p_intent); finish(); } } } //main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <Button android:id="@+id/call_alarm_service" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="call_alarm_service" /> <Button android:id="@+id/exit" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Exit" /> </LinearLayout>