You are on page 1of 52

coursera-android-location-lab

coursera-android-locationlab/Skeleton/src/course/labs/locationlab/MockLocationProvider.java
kjorg50 on 20 Apr 2014
initial commit
1 contributor

RawBlameHistory

47 lines (34 sloc) 1.346 kb


package course.labs.locationlab;
// Adapted from code found at:
// http://mobiarch.wordpress.com/2012/07/17/testing-with-mock-location-data-in-android/
import
import
import
import

android.content.Context;
android.location.Location;
android.location.LocationManager;
android.os.SystemClock;

public class MockLocationProvider {


private String mProviderName;
private LocationManager mLocationManager;
private static float mockAccuracy = 5;
public MockLocationProvider(String name, Context ctx) {
this.mProviderName = name;
mLocationManager = (LocationManager) ctx
.getSystemService(Context.LOCATION_SERVICE);
mLocationManager.addTestProvider(mProviderName, false, false, false,
false, true, true, true, 0, 5);
mLocationManager.setTestProviderEnabled(mProviderName, true);
}
public void pushLocation(double lat, double lon) {
Location mockLocation = new Location(mProviderName);
mockLocation.setLatitude(lat);
mockLocation.setLongitude(lon);
mockLocation.setAltitude(0);
mockLocation.setTime(System.currentTimeMillis());
mockLocation
.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
mockLocation.setAccuracy(mockAccuracy);
mLocationManager.setTestProviderLocation(mProviderName, mockLocation);
}
public void shutdown() {
mLocationManager.removeTestProvider(mProviderName);
}
}

coursera-android-locationlab/Skeleton/src/course/labs/locationlab/PlaceDownloaderTask.java
kjorg50 on 20 Apr 2014
updaed geoname ID
1 contributor

RawBlameHistory

229 lines (178 sloc) 5.856 kb


package course.labs.locationlab;
import
import
import
import
import
import
import
import
import

java.io.BufferedReader;
java.io.IOException;
java.io.InputStream;
java.io.InputStreamReader;
java.io.StringReader;
java.lang.ref.WeakReference;
java.net.HttpURLConnection;
java.net.MalformedURLException;
java.net.URL;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import
import
import
import
import
import

org.w3c.dom.DOMException;
org.w3c.dom.Document;
org.w3c.dom.Node;
org.w3c.dom.NodeList;
org.xml.sax.InputSource;
org.xml.sax.SAXException;

import
import
import
import
import
import

android.graphics.Bitmap;
android.graphics.BitmapFactory;
android.location.Location;
android.location.LocationManager;
android.os.AsyncTask;
android.util.Log;

public class PlaceDownloaderTask extends AsyncTask<Location, Void, PlaceRecord> {


// Change to false if you don't have network access
private static final boolean HAS_NETWORK = true;
// DONE - put your www.geonames.org account name here.
private static String USERNAME = "kjorg50";
private HttpURLConnection mHttpUrl;

private
private
private
private

WeakReference<PlaceViewActivity> mParent;
static Bitmap mStubBitmap;
static Location mockLoc1 = new Location(LocationManager.NETWORK_PROVIDER);
static Location mockLoc2 = new Location(LocationManager.NETWORK_PROVIDER);

public PlaceDownloaderTask(PlaceViewActivity parent) {


super();
mParent = new WeakReference<PlaceViewActivity>(parent);
if (!HAS_NETWORK) {
mStubBitmap = BitmapFactory.decodeResource(parent.getResources(),R.drawable.stub);
mockLoc1.setLatitude(37.422);
mockLoc1.setLongitude(-122.084);
mockLoc2.setLatitude(38.996667);
mockLoc2.setLongitude(-76.9275);
}
}
@Override
protected PlaceRecord doInBackground(Location... location) {
PlaceRecord place = null;
if (HAS_NETWORK) {
place = getPlaceFromURL(generateURL(USERNAME, location[0]));
if ("" != place.getCountryName()) {
place.setLocation(location[0]);
place.setFlagBitmap(getFlagFromURL(place.getFlagUrl()));
} else {
place = null;
}
} else {
place = new PlaceRecord(location[0]);
if (location[0].distanceTo(mockLoc1) < 100) {
place.setCountryName("United States");
place.setPlace("The Greenhouse");
place.setFlagBitmap(mStubBitmap);
} else {
place.setCountryName("United States");
place.setPlace("Berwyn");
place.setFlagBitmap(mStubBitmap);
}
}
return place;
}
@Override
protected void onPostExecute(PlaceRecord result) {
if (null != result && null != mParent.get()) {
mParent.get().addNewPlace(result);
}
}
private PlaceRecord getPlaceFromURL(String... params) {
String result = null;

BufferedReader in = null;
try {
URL url = new URL(params[0]);
mHttpUrl = (HttpURLConnection) url.openConnection();
in = new BufferedReader(new InputStreamReader(
mHttpUrl.getInputStream()));
StringBuffer sb = new StringBuffer("");
String line = "";
while ((line = in.readLine()) != null) {
sb.append(line + "\n");
}
result = sb.toString();
} catch (MalformedURLException e) {
} catch (IOException e) {
} finally {
try {
if (null != in) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
mHttpUrl.disconnect();
}
return placeDataFromXml(result);
}
private Bitmap getFlagFromURL(String flagUrl) {
InputStream in = null;
Log.i("temp", flagUrl);
try {
URL url = new URL(flagUrl);
mHttpUrl = (HttpURLConnection) url.openConnection();
in = mHttpUrl.getInputStream();
return BitmapFactory.decodeStream(in);
} catch (MalformedURLException e) {
Log.e("DEBUG", e.toString());
} catch (IOException e) {
Log.e("DEBUG", e.toString());
} finally {
try {
if (null != in) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
mHttpUrl.disconnect();
}
return BitmapFactory.decodeResource(mParent.get().getResources(),

R.drawable.stub);
}
private static PlaceRecord placeDataFromXml(String xmlString) {
DocumentBuilder builder;
String countryName = "";
String countryCode = "";
String placeName = "";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
builder = factory.newDocumentBuilder();
Document document = builder.parse(new InputSource(new StringReader(
xmlString)));
NodeList list = document.getDocumentElement().getChildNodes();
for (int i = 0; i < list.getLength(); i++) {
Node curr = list.item(i);
NodeList list2 = curr.getChildNodes();
for (int j = 0; j < list2.getLength(); j++) {
Node curr2 = list2.item(j);
if (curr2.getNodeName() != null) {
if (curr2.getNodeName().equals("countryName")) {
countryName = curr2.getTextContent();
} else if (curr2.getNodeName().equals("countryCode")) {
countryCode = curr2.getTextContent();
} else if (curr2.getNodeName().equals("name")) {
placeName = curr2.getTextContent();
}
}
}
}
} catch (DOMException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return new PlaceRecord(generateFlagURL(countryCode.toLowerCase()),
countryName, placeName);
}
private static String generateURL(String username, Location location) {
return "http://www.geonames.org/findNearbyPlaceName?username="
+ username + "&style=full&lat=" + location.getLatitude()
+ "&lng=" + location.getLongitude();
}
private static String generateFlagURL(String countryCode) {
return "http://www.geonames.org/flags/x/" + countryCode + ".gif";
}
}

coursera-android-locationlab/Skeleton/src/course/labs/locationlab/PlaceViewActivity.java
kjorg50 on 20 Apr 2014
remove TODOs
1 contributor

RawBlameHistory

243 lines (188 sloc) 7.046 kb


package course.labs.locationlab;
import java.util.ArrayList;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import

android.app.ListActivity;
android.content.Context;
android.location.Location;
android.location.LocationListener;
android.location.LocationManager;
android.os.Bundle;
android.util.Log;
android.view.Menu;
android.view.MenuInflater;
android.view.MenuItem;
android.view.View;
android.view.View.OnClickListener;
android.widget.ListView;
android.widget.TextView;
android.widget.Toast;

public class PlaceViewActivity extends ListActivity implements LocationListener {


private static final long FIVE_MINS = 5 * 60 * 1000;
private static String TAG = "Lab-Location";
private Location mLastLocationReading;
private PlaceViewAdapter mAdapter;
// default minimum time between new readings
private long mMinTime = 5000;
// default minimum distance between old and new readings.
private float mMinDistance = 1000.0f;
private LocationManager mLocationManager;
// A fake location provider used for testing
private MockLocationProvider mMockLocationProvider;
private TextView mFooterView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// DONE - Set up the app's user interface
// This class is a ListActivity, so it has its own ListView
// ListView's adapter should be a PlaceViewAdapter
mAdapter = new PlaceViewAdapter(getApplicationContext());
// from UI lab...
// Put divider between ToDoItems and FooterView
getListView().setFooterDividersEnabled(true);
// DONE - add a footerView to the ListView
// You can use footer_view.xml to define the footer
// 1. get a layout inflater
// 2. call the inflate method, with the id of the footer view resource
// 3. cast it as a TextView
mFooterView = (TextView) this.getLayoutInflater().inflate(R.layout.footer_view, null);
// adds it to the ListView
getListView().addFooterView(mFooterView);
// enable it only if there is a location
mFooterView.setEnabled(mLastLocationReading != null);
// DONE - When the footerView's onClick() method is called, it must issue the
// following log call
// log("Entered footerView.OnClickListener.onClick()");
mFooterView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
log("Entered footerView.OnClickListener.onClick()");
// footerView must respond to user clicks.
// Must handle 3 cases:
// 3) There is no current location - response is up to you. The best
// solution is to disable the footerView until you have a location.
if (mLastLocationReading == null)
{
log("Location data is not available");
mFooterView.setEnabled(false);
}
// 1) The current location is new - download new Place Badge. Issue the
// following log call:
// log("Starting Place Download");
if(! mAdapter.intersects(mLastLocationReading))
{
log("Starting Place Download");
PlaceDownloaderTask pdt = new PlaceDownloaderTask(PlaceViewActivity.this);
pdt.execute(mLastLocationReading);
} else {
// 2) The current location has been seen before - issue Toast message.
// Issue the following log call:
log("You already have this location badge");
Toast.makeText(getApplicationContext(), "You already have this location badge",
Toast.LENGTH_LONG).show();
}

}
});
// Attach the adapter to this ListActivity's ListView
getListView().setAdapter(mAdapter);
}
@Override
protected void onResume() {
super.onResume();
Location tempLoc;
mMockLocationProvider = new MockLocationProvider(
LocationManager.NETWORK_PROVIDER, this);
// DONE - Check NETWORK_PROVIDER for an existing location reading.
// Acquire reference to the LocationManager
if (null == (mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE)))
finish();
tempLoc = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
// Only keep this last reading if it is fresh - less than 5 minutes old.
if(tempLoc != null && age(tempLoc)<FIVE_MINS)
{
mLastLocationReading = tempLoc;
}
// DONE - register to receive location updates from NETWORK_PROVIDER
// can use "this" since this class implements LocationListener
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, mMinTime,
mMinDistance, this);
}
@Override
protected void onPause() {
mMockLocationProvider.shutdown();
// DONE - unregister for location updates
mLocationManager.removeUpdates(this);
super.onPause();
}
// Callback method used by PlaceDownloaderTask
public void addNewPlace(PlaceRecord place) {
log("Entered addNewPlace()");
mAdapter.add(place);
}
@Override
public void onLocationChanged(Location currentLocation) {
//
//
//
//
//
//

DONE - Handle location updates


Cases to consider
1) If there is no last location, keep the current location.
2) If the current location is older than the last location, ignore
the current location
3) If the current location is newer than the last locations, keep the

// current location.
if(mLastLocationReading == null || age(currentLocation) < age(mLastLocationReading))
{
mLastLocationReading = currentLocation;
// enable the footer view again since we have an updated location
mFooterView.setEnabled(true);
}
}
@Override
public void onProviderDisabled(String provider) {
// not implemented
}
@Override
public void onProviderEnabled(String provider) {
// not implemented
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// not implemented
}
private long age(Location location) {
return System.currentTimeMillis() - location.getTime();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.print_badges:
ArrayList<PlaceRecord> currData = mAdapter.getList();
for (int i = 0; i < currData.size(); i++) {
log(currData.get(i).toString());
}
return true;
case R.id.delete_badges:
mAdapter.removeAllViews();
return true;
case R.id.place_one:
mMockLocationProvider.pushLocation(37.422, -122.084);
return true;
case R.id.place_invalid:
mMockLocationProvider.pushLocation(0, 0);
return true;
case R.id.place_two:
mMockLocationProvider.pushLocation(38.996667, -76.9275);
return true;
default:

return super.onOptionsItemSelected(item);
}
}
private static void log(String msg) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG, msg);
}
}

coursera-android-contentproviders-lab

branch: master

coursera-android-contentproviderslab/Skeleton/ContentProviderLabUser/src/course/labs/contentproviderlab/PlaceDownloaderTask.java
kjorg50 on 26 Apr 2014
clean up TODOs
1 contributor

RawBlameHistory

227 lines (182 sloc) 5.938 kb


package course.labs.contentproviderlab;
import
import
import
import
import
import
import
import
import

java.io.BufferedReader;
java.io.IOException;
java.io.InputStream;
java.io.InputStreamReader;
java.io.StringReader;
java.lang.ref.WeakReference;
java.net.HttpURLConnection;
java.net.MalformedURLException;
java.net.URL;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import
import
import
import
import
import

org.w3c.dom.DOMException;
org.w3c.dom.Document;
org.w3c.dom.Node;
org.w3c.dom.NodeList;
org.xml.sax.InputSource;
org.xml.sax.SAXException;

import
import
import
import
import
import

android.graphics.Bitmap;
android.graphics.BitmapFactory;
android.location.Location;
android.location.LocationManager;
android.os.AsyncTask;
android.util.Log;

public class PlaceDownloaderTask extends AsyncTask<Location, Void, PlaceRecord> {


// Change to false if you don't have network access
private static final boolean HAS_NETWORK = true;
// DONE - put your www.geonames.org account name here.
private static String USERNAME = "kjorg50";
private HttpURLConnection mHttpUrl;
private WeakReference<PlaceViewActivity> mParent;
private static Bitmap mStubBitmap;
private static Location mockLoc1 = new Location(
LocationManager.NETWORK_PROVIDER);
private static Location mockLoc2 = new Location(
LocationManager.NETWORK_PROVIDER);
public PlaceDownloaderTask(PlaceViewActivity parent) {

coursera-android-contentproviderslab/Skeleton/ContentProviderLabUser/src/course/labs/contentproviderlab/Place
ViewActivity.java
kjorg50 on 26 Apr 2014
clean up TODOs
1 contributor

RawBlameHistory

296 lines (227 sloc) 8.87 kb


package course.labs.contentproviderlab;
import java.util.ArrayList;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import

android.app.ListActivity;
android.app.LoaderManager;
android.app.LoaderManager.LoaderCallbacks;
android.content.Context;
android.content.CursorLoader;
android.content.Loader;
android.database.Cursor;
android.location.Location;
android.location.LocationListener;
android.location.LocationManager;
android.os.Bundle;
android.util.Log;
android.view.Menu;
android.view.MenuInflater;
android.view.MenuItem;
android.view.View;
android.view.View.OnClickListener;
android.widget.ListView;
android.widget.TextView;
android.widget.Toast;
course.labs.contentproviderlab.provider.PlaceBadgesContract;

public class PlaceViewActivity extends ListActivity implements


LocationListener, LoaderCallbacks<Cursor> {
private static final long FIVE_MINS = 5 * 60 * 1000;
private static String TAG = "Lab-ContentProvider";
// The last valid location reading
private Location mLastLocationReading;
// The ListView's adapter

// private PlaceViewAdapter mAdapter;


private PlaceViewAdapter mCursorAdapter;
// default minimum time between new location readings
private long mMinTime = 5000;
// default minimum distance between old and new readings.
private float mMinDistance = 1000.0f;
// Reference to the LocationManager
private LocationManager mLocationManager;
// A fake location provider used for testing
private MockLocationProvider mMockLocationProvider;
private TextView mFooterView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// - Set up the app's user interface
// This class is a ListActivity, so it has its own ListView
mCursorAdapter = new PlaceViewAdapter(this, null, 0);
// from UI lab...
// Put divider between ToDoItems and FooterView
getListView().setFooterDividersEnabled(true);
// - add a footerView to the ListView
// You can use footer_view.xml to define the footer
// 1. get a layout inflater
// 2. call the inflate method, with the id of the footer view resource
// 3. cast it as a TextView
mFooterView = (TextView) this.getLayoutInflater().inflate(R.layout.footer_view, null);
// adds it to the ListView
getListView().addFooterView(mFooterView);
// enable it only if there is a location
mFooterView.setEnabled(mLastLocationReading != null);
// - When the footerView's onClick() method is called, it must issue the
// following log call
// log("Entered footerView.OnClickListener.onClick()");
mFooterView.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View arg0) {
log("Entered footerView.OnClickListener.onClick()");
// footerView must respond to user clicks.
// Must handle 3 cases:
// 3) There is no current location - response is up to you. The best
// solution is to disable the footerView until you have a location.
if (mLastLocationReading == null)
{
log("Location data is not available");
mFooterView.setEnabled(false);
}
// 1) The current location is new - download new Place Badge. Issue the
// following log call:

// log("Starting Place Download");


if(! mCursorAdapter.intersects(mLastLocationReading))
{
log("Starting Place Download");
PlaceDownloaderTask pdt = new PlaceDownloaderTask(PlaceViewActivity.this);
pdt.execute(mLastLocationReading);
} else {
// 2) The current location has been seen before - issue Toast message.
// Issue the following log call:
log("You already have this location badge");
Toast.makeText(getApplicationContext(), "You already have this location badge",
Toast.LENGTH_LONG).show();
}
}
});
// - Create and set empty PlaceViewAdapter
// ListView's adapter should be a PlaceViewAdapter called mCursorAdapter
// Attach the adapter to this ListActivity's ListView
getListView().setAdapter(mCursorAdapter);
// - Initialize a CursorLoader
// See - ContentProviderWithCursorLoader example
getLoaderManager().initLoader(0, null, this);
}
@Override
protected void onResume() {
super.onResume();
Location tempLoc;
mMockLocationProvider = new MockLocationProvider(
LocationManager.NETWORK_PROVIDER, this);
// - Check NETWORK_PROVIDER for an existing location reading.
// Acquire reference to the LocationManager
if (null == (mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE)))
finish();
tempLoc = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
// Only keep this last reading if it is fresh - less than 5 minutes old.
if(tempLoc != null && age(tempLoc)<FIVE_MINS)
{
mLastLocationReading = tempLoc;
}
// - Register to receive location updates from NETWORK_PROVIDER
// can use "this" since this class implements LocationListener
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, mMinTime,
mMinDistance, this);
}
@Override
protected void onPause() {
mMockLocationProvider.shutdown();

// - Unregister for location updates


mLocationManager.removeUpdates(this);
super.onPause();
}
public void addNewPlace(PlaceRecord place) {
log("Entered addNewPlace()");
mCursorAdapter.add(place);
}
@Override
public void onLocationChanged(Location currentLocation) {
// - Handle location updates
// Cases to consider
// 1) If there is no last location, keep the current location.
// 2) If the current location is older than the last location, ignore
// the current location
// 3) If the current location is newer than the last locations, keep the
// current location.
if(mLastLocationReading == null || age(currentLocation) < age(mLastLocationReading))
{
mLastLocationReading = currentLocation;
// enable the footer view again since we have an updated location
mFooterView.setEnabled(true);
}
}
@Override
public void onProviderDisabled(String provider) {
// not implemented
}
@Override
public void onProviderEnabled(String provider) {
// not implemented
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// not implemented
}
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
log("Entered onCreateLoader()");
// - Create a new CursorLoader and return it
// can pass null to most of the values, and gets the URI form the Contract
return new CursorLoader(getApplicationContext(),
PlaceBadgesContract.CONTENT_URI,null,null,null,null);
}
@Override
public void onLoadFinished(Loader<Cursor> newLoader, Cursor newCursor) {
// - Swap in the newCursor
// This gets called after the cursor loader uses a cursor to query the content provider

// in the background thread.


/* As soon as the cursor loader finishes loading up the results of our querying the content provider,
this method will be called. At this point, we use the swapCursor method to give the new cursor to the
PlaceViewAdapter. The adapter is then responsible for making sure that the list view is refreshed with
the
appropriate data. */
mCursorAdapter.swapCursor(newCursor);
}
@Override
public void onLoaderReset(Loader<Cursor> newLoader) {
// - Swap in a null Cursor
// This is basically the opposite of onLoadFinished. It is called whenever the cursor we obtained from the
// cursor loader is about to be closed down.
mCursorAdapter.swapCursor(null);
}
private long age(Location location) {
return System.currentTimeMillis() - location.getTime();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.print_badges:
ArrayList<PlaceRecord> currData = mCursorAdapter.getList();
for (int i = 0; i < currData.size(); i++) {
log(currData.get(i).toString());
}
return true;
case R.id.delete_badges:
mCursorAdapter.removeAllViews();
return true;
case R.id.place_one:
mMockLocationProvider.pushLocation(37.422, -122.084);
return true;
case R.id.place_invalid:
mMockLocationProvider.pushLocation(0, 0);
return true;
case R.id.place_two:
mMockLocationProvider.pushLocation(38.996667, -76.9275);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private static void log(String msg) {
try {

Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG, msg);
}
}

coursera-android-contentproviderslab/Skeleton/ContentProviderLabUser/src/course/labs/contentproviderlab/Place
ViewAdapter.java
kjorg50 on 26 Apr 2014
clean up TODOs
1 contributor

RawBlameHistory

255 lines (186 sloc) 6.982 kb


package course.labs.contentproviderlab;
import
import
import
import
import
import

java.io.BufferedOutputStream;
java.io.File;
java.io.FileNotFoundException;
java.io.FileOutputStream;
java.io.IOException;
java.util.ArrayList;

import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import

android.content.ContentValues;
android.content.Context;
android.database.Cursor;
android.graphics.Bitmap;
android.graphics.Bitmap.CompressFormat;
android.graphics.BitmapFactory;
android.location.Location;
android.net.Uri;
android.os.Environment;
android.view.LayoutInflater;
android.view.View;
android.view.ViewGroup;
android.widget.CursorAdapter;
android.widget.ImageView;
android.widget.TextView;
course.labs.contentproviderlab.provider.PlaceBadgesContract;

public class PlaceViewAdapter extends CursorAdapter {


private
private
private
private
private

static final String APP_DIR = "ContentProviderLab/Badges";


ArrayList<PlaceRecord> list = new ArrayList<PlaceRecord>();
static LayoutInflater inflater = null;
Context mContext;
String mBitmapStoragePath;

public PlaceViewAdapter(Context context, Cursor cursor, int flags) {


super(context, cursor, flags);
mContext = context;
inflater = LayoutInflater.from(mContext);
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
try {
String root = mContext.getExternalFilesDir(null)
.getCanonicalPath();
if (null != root) {
File bitmapStorageDir = new File(root, APP_DIR);
bitmapStorageDir.mkdirs();
mBitmapStoragePath = bitmapStorageDir.getCanonicalPath();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public Cursor swapCursor(Cursor newCursor) {
super.swapCursor(newCursor);
if (null != newCursor) {
//
//
//
//

DONE - clear the ArrayList list so it contains


the current set of PlaceRecords. Use the
getPlaceRecordFromCursor() method to add the
current place to the list

list.clear();
// Check if the database is empty!
if(newCursor.moveToFirst())
{
do
{ // combine the getting of the record with adding it to the list
list.add(getPlaceRecordFromCursor(newCursor));
} while(newCursor.moveToNext());
// moveToNext() returns false when the cursor is already past the last entry in the result set
}
// Set the NotificationURI for the new cursor
newCursor.setNotificationUri(mContext.getContentResolver(),
PlaceBadgesContract.CONTENT_URI);
}

return newCursor;
}
// returns a new PlaceRecord for the data at the cursor's
// current position
private PlaceRecord getPlaceRecordFromCursor(Cursor cursor) {
String flagBitmapPath = cursor.getString(cursor
.getColumnIndex(PlaceBadgesContract.FLAG_BITMAP_PATH));
String countryName = cursor.getString(cursor
.getColumnIndex(PlaceBadgesContract.COUNTRY_NAME));
String placeName = cursor.getString(cursor
.getColumnIndex(PlaceBadgesContract.PLACE_NAME));
double lat = cursor.getDouble(cursor
.getColumnIndex(PlaceBadgesContract.LAT));
double lon = cursor.getDouble(cursor
.getColumnIndex(PlaceBadgesContract.LON));
return new PlaceRecord(null, flagBitmapPath, countryName, placeName,
lat, lon);
}
public int getCount() {
return list.size();
}
public Object getItem(int position) {
return list.get(position);
}
public long getItemId(int position) {
return position;
}
static class ViewHolder {
ImageView flag;
TextView country;
TextView place;
}
public boolean intersects(Location location) {
for (PlaceRecord item : list) {
if (item.intersects(location)) {
return true;
}
}
return false;
}
public void add(PlaceRecord listItem) {
String lastPathSegment = Uri.parse(listItem.getFlagUrl())
.getLastPathSegment();
String filePath = mBitmapStoragePath + "/" + lastPathSegment;
if (storeBitmapToFile(listItem.getFlagBitmap(), filePath)) {
listItem.setFlagBitmapPath(filePath);
list.add(listItem);
// DONE - Insert new record into the ContentProvider

ContentValues values = new ContentValues();


// @see ContentProviderCustomUser example for inserting items with a ContentResolver and
ContentValues objects.
// Use a contentValues object to set the values we want to put in the Content Resolver
// basically, creating one row to put in the SQLite storage
values.put(PlaceBadgesContract.FLAG_BITMAP_PATH, listItem.getFlagBitmapPath());
values.put(PlaceBadgesContract.COUNTRY_NAME, listItem.getCountryName());
values.put(PlaceBadgesContract.PLACE_NAME, listItem.getPlace());
values.put(PlaceBadgesContract.LAT, listItem.getLat());
values.put(PlaceBadgesContract.LON, listItem.getLon());
// Use a ContentResolver object to actually insert the values into the content provider
mContext.getContentResolver().insert(PlaceBadgesContract.CONTENT_URI, values);
}
}
public ArrayList<PlaceRecord> getList() {
return list;
}
public void removeAllViews() {
list.clear();
// DONE - delete all records in the ContentProvider
// we can use the content resolver's delete() method and just pass it the URI.
// This will make it delete all the rows
mContext.getContentResolver().delete(PlaceBadgesContract.CONTENT_URI, null, null);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder holder = (ViewHolder) view.getTag();
holder.flag.setImageBitmap(getBitmapFromFile(cursor.getString(cursor
.getColumnIndex(PlaceBadgesContract.FLAG_BITMAP_PATH))));
holder.country.setText("Country: "
+ cursor.getString(cursor
.getColumnIndex(PlaceBadgesContract.COUNTRY_NAME)));
holder.place.setText("Place: "
+ cursor.getString(cursor
.getColumnIndex(PlaceBadgesContract.PLACE_NAME)));
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View newView;
ViewHolder holder = new ViewHolder();
newView = inflater.inflate(R.layout.place_badge_view, null);
holder.flag = (ImageView) newView.findViewById(R.id.flag);
holder.country = (TextView) newView.findViewById(R.id.country_name);
holder.place = (TextView) newView.findViewById(R.id.place_name);
newView.setTag(holder);
return newView;

}
private Bitmap getBitmapFromFile(String filePath) {
return BitmapFactory.decodeFile(filePath);
}
private boolean storeBitmapToFile(Bitmap bitmap, String filePath) {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
try {
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(filePath));
bitmap.compress(CompressFormat.PNG, 100, bos);
bos.flush();
bos.close();
} catch (FileNotFoundException e) {
return false;
} catch (IOException e) {
return false;
}
return true;
}
return false;
}
}

android2-week8/W8-A7-ThreadedDownloadsBoundServices/src/edu/vuum/mocca/DownloadActivity.java
LFenske on 11 Jul 2014
Change "DONE" back to "TODO" for grading.
1 contributor

RawBlameHistory

268 lines (240 sloc) 10.233 kb


package edu.vuum.mocca;
import android.content.ComponentName;

import
import
import
import
import
import
import

android.content.ServiceConnection;
android.net.Uri;
android.os.IBinder;
android.os.RemoteException;
android.util.Log;
android.view.View;
android.os.AsyncTask;

/**
* This is the main Activity that the program uses to start the
* ThreadedDownloads application. It allows the user to input the URL
* of an image and download that image using one of two different
* Android Bound Service implementations: synchronous and
* asynchronous. The Activity starts the Service using bindService().
* After the Service is started, its onBind() hook method returns an
* implementation of an AIDL interface to the Activity by
* asynchronously calling the onServiceConnected() hook method in the
* Activity. The AIDL interface object that's returned can then be
* used to interact with the Service either synchronously or
* asynchronously, depending on the type of AIDL interface requested.
*
* Starting Bound Services to run synchronously in background Threads
* from the asynchronous UI Thread is an example of the
* Half-Sync/Half-Async Pattern. Starting Bound Services using
* Intents is an example of the Activator and Command Processor
* patterns. The DownloadActivity plays the role of the Creator and
* creates a Command in the form of an Intent. The Intent is received
* by the Service process, which plays the role of the Executor.
*
* The use of AIDL interfaces to pass information between two
* different processes is an example of the Broker Pattern, in which
* all communication-related functionality is encapsulated in the AIDL
* interface and the underlying Android Binder framework, shielding
* applications from tedious and error-prone aspects of inter-process
* communication.
*/
public class DownloadActivity extends DownloadBase {
/**
* Used for debugging.
*/
private final String TAG = this.getClass().getSimpleName();
/**
* The AIDL Interface that's used to make twoway calls to the
* DownloadServiceSync Service. This object plays the role of
* Requestor in the Broker Pattern. If it's null then there's no
* connection to the Service.
*/
DownloadCall mDownloadCall;
/**
* The AIDL Interface that we will use to make oneway calls to the
* DownloadServiceAsync Service. This plays the role of Requestor
* in the Broker Pattern. If it's null then there's no connection
* to the Service.
*/

DownloadRequest mDownloadRequest;
/**
* This ServiceConnection is used to receive results after binding
* to the DownloadServiceSync Service using bindService().
*/
ServiceConnection mServiceConnectionSync = new ServiceConnection() {
/**
* Cast the returned IBinder object to the DownloadCall
* AIDL Interface and store it for later use in
* mDownloadCall.
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "ComponentName: " + name);
// TODO You fill in here to replace null with a call
// to a generated stub method that converts the
// service parameter into an interface that can be
// used to make RPC calls to the Service.
mDownloadCall = DownloadCall.Stub.asInterface(service);
}
/**
* Called if the remote service crashes and is no longer
* available. The ServiceConnection will remain bound,
* but the service will not respond to any requests.
*/
@Override
public void onServiceDisconnected(ComponentName name) {
mDownloadCall = null;
}
};
/**
* This ServiceConnection is used to receive results after binding
* to the DownloadServiceAsync Service using bindService().
*/
ServiceConnection mServiceConnectionAsync = new ServiceConnection() {
/**
* Cast the returned IBinder object to the DownloadRequest
* AIDL Interface and store it for later use in
* mDownloadRequest.
*/
@Override
public void onServiceConnected(ComponentName name,
IBinder service) {
// TODO You fill in here to replace null with a call
// to a generated stub method that converts the
// service parameter into an interface that can be
// used to make RPC calls to the Service.
mDownloadRequest = DownloadRequest.Stub.asInterface(service);
}
/**
* Called if the remote service crashes and is no longer
* available. The ServiceConnection will remain bound,

* but the service will not respond to any requests.


*/
@Override
public void onServiceDisconnected(ComponentName name) {
mDownloadRequest = null;
}
};
/**
* The implementation of the DownloadCallback AIDL
* Interface. Should be passed to the DownloadBoundServiceAsync
* Service using the DownloadRequest.downloadImage() method.
*
* This implementation of DownloadCallback.Stub plays the role of
* Invoker in the Broker Pattern.
*/
DownloadCallback.Stub mDownloadCallback = new DownloadCallback.Stub() {
/**
* Called when the DownloadServiceAsync finishes obtaining
* the results from the GeoNames Web service. Use the
* provided String to display the results in a TextView.
*/
@Override
public void sendPath(final String imagePathname) throws RemoteException {
// TODO - You fill in here to replace null with a new
// Runnable whose run() method displays the bitmap
// image whose pathname is passed as a parameter to
// sendPath(). Please use displayBitmap() defined in
// DownloadBase.
Runnable displayRunnable = new Runnable() {
public void run() {
displayBitmap(imagePathname);
}
};
DownloadActivity.this.runOnUiThread(displayRunnable);
}
};
/**
* This method is called when a user presses a button (see
* res/layout/activity_download.xml)
*/
public void runService(View view) {
Uri uri = Uri.parse(getUrlString());
hideKeyboard();
switch (view.getId()) {
case R.id.bound_sync_button:
// TODO - You fill in here to use mDownloadCall to
// download the image & then display it.
if (mDownloadCall != null) {
// Create an AsyncTask for the two-way call so that it doesn't take too
// long in this, the UI thread.
new AsyncTask<Uri, Void, String> () {
protected String doInBackground(Uri... uris) {

try {
return mDownloadCall.downloadImage(uris[0]);
} catch (RemoteException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String filePath) {
// This is executed in the UI thread.
displayBitmap(filePath);
}
}.execute(uri);
}
break;
case R.id.bound_async_button:
// TODO - You fill in here to call downloadImage() on
// mDownloadRequest, passing in the appropriate Uri and
// callback.
if (mDownloadRequest != null) {
try {
mDownloadRequest.downloadImage(uri, mDownloadCallback);
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
}
}
/**
* Hook method called when the DownloadActivity becomes visible to
* bind the Activity to the Services.
*/
@Override
public void onStart () {
super.onStart();
// Bind this activity to the DownloadBoundService* Services if
// they aren't already bound Use mBoundSync/mBoundAsync
if (mDownloadCall == null)
bindService(DownloadBoundServiceSync.makeIntent(this),
mServiceConnectionSync,
BIND_AUTO_CREATE);
if (mDownloadRequest == null)
bindService(DownloadBoundServiceAsync.makeIntent(this),
mServiceConnectionAsync,
BIND_AUTO_CREATE);
}
/**
* Hook method called when the DownloadActivity becomes completely
* hidden to unbind the Activity from the Services.
*/
@Override
public void onStop () {
super.onStop();

// Unbind the Sync/Async Services if they are bound. Use


// mBoundSync/mBoundAsync
if (mDownloadCall != null)
unbindService(mServiceConnectionSync);
if (mDownloadRequest != null)
unbindService(mServiceConnectionAsync);
}
// Public accessor method for testing purposes
public DownloadCall getDownloadCall () {
return mDownloadCall;
}
// Public accessor method for testing purposes
public DownloadRequest getDownloadRequest () {
return mDownloadRequest;
}
// Public accessor method for testing purposes
public DownloadCallback getDownloadCallback () {
return mDownloadCallback;
}
// Public accessor method for testing purposes
public boolean isBoundToSync () {
return mDownloadCall != null;
}
// Public accessor method for testing purposes
public boolean isBoundToAsync () {
return mDownloadRequest != null;
}
}

android2-week8/W8-A7-ThreadedDownloadsBoundServices/src/edu/vuum/mocca/DownloadBase.java
LFenske on 11 Jul 2014
Use AsyncTask so the UI thread doesn't block.
1 contributor

RawBlameHistory

149 lines (132 sloc) 5.385 kb


package edu.vuum.mocca;

import
import
import
import
import
import
import
import
import
import
import
import

android.app.Activity;
android.content.Context;
android.graphics.Bitmap;
android.graphics.BitmapFactory;
android.graphics.drawable.BitmapDrawable;
android.os.Bundle;
android.os.StrictMode;
android.util.Log;
android.view.View;
android.view.inputmethod.InputMethodManager;
android.widget.EditText;
android.widget.ImageView;

/**
* This class is used the base class for the DownloadActivity. It
* instantiates the UI and handles displaying images and getting text
* from the EditText object by making displayBitmap() and
* getUrlString() available to subclasses. This design separates
* concerns by having DownloadBase handle UI functionality while
* subclasses (such as DownloadActivity) handle any Service-related
* communication with the GeoNames Web service.
*
* GeoNamesBase is an example of the Template Method pattern since it
* extends Activity and overrides its onCreate() hook method. More
* generally, any object that extends Activity and overrides its hook
* methods, such as onStart() or onPause(), is also an example of the
* Template Method pattern.
*/
public class DownloadBase extends Activity {
/**
* Used for debugging.
*/
private final String TAG = this.getClass().getSimpleName();
/**
* This is the reference to the text box that allows the user to
* input a URL to an image for downloading.
*/
private EditText mUrlEditText;
/**
* This is a reference to the container of an image in the UI.
* When we finish downloading, we update this to display the image
* we just stored on the file system.
*/
private ImageView mImageView;
/**
* The original bitmap (used for reseting the image).
*/
private Bitmap mDefaultBitmap;
/**
* Store the current bitmap for testing purposes.
*/
public Bitmap mCurrentBitmap;
/**

* Hide the keyboard after a user has finished typing the url.
*/
protected void hideKeyboard() {
InputMethodManager mgr =
(InputMethodManager) getSystemService
(Context.INPUT_METHOD_SERVICE);
mgr.hideSoftInputFromWindow(mUrlEditText.getWindowToken(),
0);
}
/**
* Display the given file in the ImageView. Use
* BitmapFactory.decodeFile(). Store the bitmap used to update
* the file to make testing easier.
*/
void displayBitmap (String pathname) {
mCurrentBitmap = BitmapFactory.decodeFile(pathname);
mImageView.setImageBitmap(mCurrentBitmap);
}
/**
* Gets the URL from the EditText
*/
String getUrlString () {
return mUrlEditText.getText().toString();
}
/**
* Resets image to the default image stored with the program.
*/
public void resetImage(View view) {
mImageView.setImageBitmap(mDefaultBitmap);
mCurrentBitmap = mDefaultBitmap;
Log.d(TAG, "reset Image");
}
/**
* This is called when the Activity is initially created. This is
* where we setup the UI for the activity and initialize any
* objects that need to exist while the activity exists.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d(getClass().getSimpleName(), "onCreate");
super.onCreate(savedInstanceState);
// Use the Android framework to create a User Interface for
// this activity. The interface that should be created is
// defined in activity_download.xml in the res/layout folder.
setContentView(R.layout.activity_download);
// Once the UI is created, get a reference to the instantiated
// EditText and ImageView objects by providing their ids to
// the Android framework.
mUrlEditText = (EditText) findViewById(R.id.url);
mImageView = (ImageView) findViewById(R.id.imageView1);
// Store whatever image is originally displayed in the

// ImageView as a local Bitmap object so that we can quickly


// reset the image when a button is pressed.
mCurrentBitmap = ((BitmapDrawable)(mImageView.getDrawable())).getBitmap();
mDefaultBitmap = mCurrentBitmap;
/**
* Turn off strict mode.
*
* Normally, if you try to do any networking from the main UI
* thread, the Android framework will throw an exception and
* stop working. However, part of this application uses a
* synchronous AIDL interface to demonstrate how to execute
* functions in services synchronously. For this purpose, we
* turn off strict mode so that the Android framework will
* work without complaining.
*
* Please note that this is for demonstration purposes ONLY,
* and you should NEVER, EVER turn off strict mode in
* production code. You should also not do networking
* operations on the main thread, because it might cause your
* application to crash.
*/
if (false) {
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
}
}

android2-week8/W8-A7-ThreadedDownloadsBoundServices/src/edu/vuum/mocca/DownloadBoundServiceAsync.java
LFenske on 11 Jul 2014
Change "DONE" back to "TODO" for grading.
1 contributor

RawBlameHistory

83 lines (76 sloc) 3.192 kb


package edu.vuum.mocca;
import android.app.Service;
import android.content.Context;

import
import
import
import

android.content.Intent;
android.net.Uri;
android.os.IBinder;
android.os.RemoteException;

/**
* @class DownloadBoundServiceAsync
* @brief This class handles downloads using asynchronous AIDL
* interactions. The component that binds to this service
* should receive an IBinder. This IBinder should be an
* instance of DownloadRequest, which extends IBinder. The
* component can then interact with this service by making
* normal calls on the DownloadRequest object. Specifically,
* the component can ask this service to download an image,
* passing in a DownloadCallback object. Once the download is
* finished, this service should send the pathname of the
* downloaded file back to the calling component by calling
* sendPath() on the DownloadCallback object.
*
* AIDL is an example of the Broker Pattern, in which all
* interprocess communication details are hidden behind the
* AIDL interfaces.
*/
public class DownloadBoundServiceAsync extends Service{
/**
* The concrete implementation of the AIDL Interface
* DownloadRequest. We extend the Stub class, which implements
* DownloadRequest, so that Android can properly handle calls
* across process boundaries.
*
* This implementation plays the role of Invoker in the Broker
* Pattern.
*/
DownloadRequest.Stub mDownloadRequestImpl = new DownloadRequest.Stub() {
/**
* Download the image at the given Uri and return a
* pathname to the file on the Android file system by
* calling the sendPath() method on the provided callback
*
* Use the methods defined in DownloadUtils for code brevity.
*/
@Override
public void downloadImage(Uri uri,
DownloadCallback callback)
throws RemoteException {
// TODO You fill in here to download the file using
// the appropriate helper method in DownloadUtils and
// then send the pathname back to the client via the
// callback object.
String filePath = DownloadUtils.downloadFile(DownloadBoundServiceAsync.this, uri);
callback.sendPath(filePath);
}
};
/**

* Called when a component calls bindService() with the proper


* intent. Return the concrete implementation of DownloadRequest
* cast as an IBinder.
*/
@Override
public IBinder onBind(Intent intent) {
return mDownloadRequestImpl;
}
/**
* Make an Intent that will start this service when passed to
* bindService().
*
* @param context The context of the calling component.
*/
public static Intent makeIntent(Context context) {
// TODO - replace the null to create the appropriate Intent
// and return it to the caller.
return new Intent(context, DownloadBoundServiceAsync.class);
}
}

android2-week8/W8-A7-ThreadedDownloadsBoundServices/src/edu/vuum/mocca/DownloadBoundServiceSync.java
LFenske on 11 Jul 2014
Change "DONE" back to "TODO" for grading.
1 contributor

RawBlameHistory

80 lines (74 sloc) 2.926 kb


package edu.vuum.mocca;
import
import
import
import
import
import

android.app.Service;
android.content.Context;
android.content.Intent;
android.net.Uri;
android.os.IBinder;
android.os.RemoteException;

/**
* @class DownloadBoundServiceSync
*

* @brief This class handles downloads using synchronous AIDL


* interactions.
*
* The component that binds to this service should receive an
* IBinder. This IBinder should be an instance of DownloadCall,
* which extends IBinder. The component can then interact with
* this service by making normal calls on the DownloadCall
* object. Specifically, the component can ask this service to
* download an image by calling downloadImage() on the
* DownloadCall object, which will run synchronously in this
* service until it finishes downloading and returns the file
* name of the downloaded file as a String.
*
* AIDL is an example of the Broker Pattern, in which all
* interprocess communication details are hidden behind the
* AIDL interfaces.
*/
public class DownloadBoundServiceSync extends Service {
/**
* An implementation of the AIDL Interface DownloadCall. We
* extend the Stub class, which implements DownloadCall, so that
* Android can properly handle calls across process boundaries.
*
* This implementation plays the role of Invoker in the Broker
* Pattern
*/
DownloadCall.Stub mDownloadCallImpl = new DownloadCall.Stub() {
/**
* Download the image at the given Uri and return a
* pathname to the file on the Android file system.
*
* Use the methods defined in DownloadUtils for code
* brevity.
*/
@Override
public String downloadImage(Uri uri) throws RemoteException {
// TODO You fill in here to replace the null and
// download the file using the appropriate helper
// method in DownloadUtils and then return the
// pathname back to the client.
return DownloadUtils.downloadFile(DownloadBoundServiceSync.this, uri);
}
};
/**
* Called when a component calls bindService() with the proper
* intent. Return the concrete implementation of DownloadCall
* cast as an IBinder.
*/
@Override
public IBinder onBind(Intent intent) {
return mDownloadCallImpl;
}
/**
* Make an Intent that will start this service when passed to

* bindService().
*
* @param context The context of the calling component.
*/
public static Intent makeIntent(Context context) {
// TODO - replace the null to create the appropriate Intent
// and return it to the caller.
return new Intent(context, DownloadBoundServiceSync.class);
}
}

android2-week8/W8-A7-ThreadedDownloadsBoundServices/src/edu/vuum/mocca/DownloadUtils.java
LFenske on 11 Jul 2014
Use AsyncTask so the UI thread doesn't block.
1 contributor

RawBlameHistory

165 lines (140 sloc) 5.523 kb


package edu.vuum.mocca;
import
import
import
import
import
import

java.io.File;
java.io.FileOutputStream;
java.io.IOException;
java.io.InputStream;
java.io.OutputStream;
java.net.URL;

import edu.vuum.mocca.R;
import
import
import
import

android.content.Context;
android.net.Uri;
android.util.Base64;
android.util.Log;

/**
* @class DownloadUtils
*
* @brief This class encapsulates several static methods so that all
* Services can access them without redefining them in each
* Service.
*/
public class DownloadUtils {

/**
* Used for debugging.
*/
static final String TAG = "DownloadActivity";
/**
* If you have access to a stable Internet connection for testing
* purposes, feel free to change this variable to false so it
* actually downloads the image from a remote server.
*/
// TODO - You can change this to the appropriate setting for your
// environment.
static final boolean DOWNLOAD_OFFLINE = false;
/**
* The resource that we write to the file system in offline
* mode. Note that this must be the same image that the testing
* project expects. (found in res/drawable-nodpi and Options.java)
*/
static final int OFFLINE_TEST_IMAGE = R.raw.dougs;
/**
* The file name that we should use to store the image in offline mode
*/
static final String OFFLINE_FILENAME = "dougs.jpg";
/**
* Download the file located at the provided internet url using
* the URL class, store it on the android file system using
* openFileOutput(), and return the path to the file on disk.
*
* @param context the context in which to write the file
* @param uri the web url
*
* @return the path to the downloaded file on the file system
*/
public static String downloadFile (Context context,
Uri uri) {
try {
// If we're offline, write the image in our resources to
// disk, then return that pathname.
if (DOWNLOAD_OFFLINE) {
// Store the image on the file system. We can store it
// as private since the test project runs in the same
// process as the target project
FileOutputStream out =
context.openFileOutput(OFFLINE_FILENAME, 0);
// Get a stream from the image resource
InputStream in =
context.getResources().openRawResource(OFFLINE_TEST_IMAGE);
// Write the resource to disk.
copy(in, out);
in.close();
out.close();

return context.getFilesDir().toString() + File.separator + OFFLINE_FILENAME;


}
// Otherwise, go ahead and download the file
else {
// Create a temp file.
final File file = getTemporaryFile(context,
uri.toString());
Log.d(TAG, " downloading to " + file);
// Download the contents at the URL, which should
// reference an image.
final InputStream in = (InputStream)
new URL(uri.toString()).getContent();
final OutputStream os =
new FileOutputStream(file);
// Copy the contents of the downloaded image to the
// temp file.
copy(in, os);
in.close();
os.close();
// Return the pathname of the temp file.
return file.getAbsolutePath();
}
} catch (Exception e) {
Log.e(TAG, "Exception while downloading. Returning null.");
Log.e(TAG, e.toString());
e.printStackTrace();
return null;
}
}
/**
* Create a temp file to store the result of a download.
*
* @param context
* @param url
* @return
* @throws IOException
*/
static private File getTemporaryFile(final Context context,
final String url) throws IOException {
//
//
//
//
//
//
//

This is what you'd normally call to get a unique temporary


file, but for testing purposes we always name the file the
same to avoid filling up student phones with numerous
files!
return context.getFileStreamPath(Base64.encodeToString(url.getBytes(),
Base64.NO_WRAP)
+ System.currentTimeMillis());

return context.getFileStreamPath(Base64.encodeToString(url.getBytes(),
Base64.NO_WRAP));
}
/**
* Copy the contents of an InputStream into an OutputStream.

*
* @param in
* @param out
* @return
* @throws IOException
*/
static public int copy(final InputStream in,
final OutputStream out) throws IOException {
final int BUFFER_LENGTH = 1024;
final byte[] buffer = new byte[BUFFER_LENGTH];
int totalRead = 0;
int read = 0;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
totalRead += read;
}
return totalRead;
}
}

Coursera_Android_Week8/SourceFiles/Skeleton/
Completed Assignment
latest commit 0d385d1fa4
ShankOffice authored on 20 Mar 2014

..
ContentProviderLabContentProvider First commit
a year ago
ContentProviderLabUser
Completed Assignment

Coursera_Android_Week8/SourceFiles/Skeleton/ContentProviderLabUser/src/
course/labs/contentproviderlab/PlaceDownloaderTask.java
ShankOffice on 20 Mar 2014
Completed Assignment
0 contributors

RawBlameHistory

227 lines (182 sloc) 5.938 kb


package course.labs.contentproviderlab;
import
import
import
import
import
import
import
import
import

java.io.BufferedReader;
java.io.IOException;
java.io.InputStream;
java.io.InputStreamReader;
java.io.StringReader;
java.lang.ref.WeakReference;
java.net.HttpURLConnection;
java.net.MalformedURLException;
java.net.URL;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import
import
import
import
import

org.w3c.dom.DOMException;
org.w3c.dom.Document;
org.w3c.dom.Node;
org.w3c.dom.NodeList;
org.xml.sax.InputSource;

import org.xml.sax.SAXException;
import
import
import
import
import
import

android.graphics.Bitmap;
android.graphics.BitmapFactory;
android.location.Location;
android.location.LocationManager;
android.os.AsyncTask;
android.util.Log;

public class PlaceDownloaderTask extends AsyncTask<Location, Void, PlaceRecord> {


// Change to false if you don't have network access
private static final boolean HAS_NETWORK = true;
// TODO - put your www.geonames.org account name here.
private static String USERNAME = "shakhub";
private HttpURLConnection mHttpUrl;
private WeakReference<PlaceViewActivity> mParent;
private static Bitmap mStubBitmap;
private static Location mockLoc1 = new Location(
LocationManager.NETWORK_PROVIDER);
private static Location mockLoc2 = new Location(
LocationManager.NETWORK_PROVIDER);
public PlaceDownloaderTask(PlaceViewActivity parent) {
super();
mParent = new WeakReference<PlaceViewActivity>(parent);
if (!HAS_NETWORK) {
mStubBitmap = BitmapFactory.decodeResource(parent.getResources(),
R.drawable.stub);
mockLoc1.setLatitude(37.422);
mockLoc1.setLongitude(-122.084);
mockLoc2.setLatitude(38.996667);
mockLoc2.setLongitude(-76.9275);
}
}
@Override
protected PlaceRecord doInBackground(Location... location) {
PlaceRecord place = null;
if (HAS_NETWORK) {
place = getPlaceFromURL(generateURL(USERNAME, location[0]));
if ("" != place.getCountryName()) {
place.setLocation(location[0]);
place.setFlagBitmap(getFlagFromURL(place.getFlagUrl()));
} else {
place = null;
}
} else {
place = new PlaceRecord(location[0]);
if (location[0].distanceTo(mockLoc1) < 100) {
place.setCountryName("United States");
place.setPlace("The Greenhouse");
place.setFlagBitmap(mStubBitmap);
place.setFlagUrl("stub.jpg");
} else {

place.setCountryName("United States");
place.setPlace("Berwyn");
place.setFlagBitmap(mStubBitmap);
place.setFlagUrl("stub.jpg");
}
}
return place;
}
@Override
protected void onPostExecute(PlaceRecord result) {
if (null != result && null != mParent.get()) {
mParent.get().addNewPlace(result);
}
}
private PlaceRecord getPlaceFromURL(String... params) {
String result = null;
BufferedReader in = null;
try {
URL url = new URL(params[0]);
mHttpUrl = (HttpURLConnection) url.openConnection();
in = new BufferedReader(new InputStreamReader(
mHttpUrl.getInputStream()));
StringBuffer sb = new StringBuffer("");
String line = "";
while ((line = in.readLine()) != null) {
sb.append(line + "\n");
}
result = sb.toString();
} catch (MalformedURLException e) {
} catch (IOException e) {
} finally {
try {
if (null != in) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
mHttpUrl.disconnect();
}
return placeDataFromXml(result);
}
private Bitmap getFlagFromURL(String flagUrl) {
InputStream in = null;
try {
URL url = new URL(flagUrl);
mHttpUrl = (HttpURLConnection) url.openConnection();
in = mHttpUrl.getInputStream();
return BitmapFactory.decodeStream(in);

} catch (MalformedURLException e) {
Log.e("DEBUG", e.toString());
} catch (IOException e) {
Log.e("DEBUG", e.toString());
} finally {
try {
if (null != in) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
mHttpUrl.disconnect();
}
return BitmapFactory.decodeResource(mParent.get().getResources(),
R.drawable.stub);
}
private static PlaceRecord placeDataFromXml(String xmlString) {
DocumentBuilder builder;
String countryName = "";
String countryCode = "";
String placeName = "";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
builder = factory.newDocumentBuilder();
Document document = builder.parse(new InputSource(new StringReader(
xmlString)));
NodeList list = document.getDocumentElement().getChildNodes();
for (int i = 0; i < list.getLength(); i++) {
Node curr = list.item(i);
NodeList list2 = curr.getChildNodes();
for (int j = 0; j < list2.getLength(); j++) {
Node curr2 = list2.item(j);
if (curr2.getNodeName() != null) {
if (curr2.getNodeName().equals("countryName")) {
countryName = curr2.getTextContent();
} else if (curr2.getNodeName().equals("countryCode")) {
countryCode = curr2.getTextContent();
} else if (curr2.getNodeName().equals("name")) {
placeName = curr2.getTextContent();
}
}
}
}
} catch (DOMException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {

e.printStackTrace();
}
return new PlaceRecord(generateFlagURL(countryCode.toLowerCase()),
null, countryName, placeName, -1, -1);
}
private static String generateURL(String username, Location location) {
return "http://www.geonames.org/findNearbyPlaceName?username="
+ username + "&style=full&lat=" + location.getLatitude()
+ "&lng=" + location.getLongitude();
}
private static String generateFlagURL(String countryCode) {
return "http://www.geonames.org/flags/x/" + countryCode + ".gif";
}
}

Coursera_Android_Week8/SourceFiles/Skeleton/ContentProviderLabUser/src/
course/labs/contentproviderlab/PlaceViewActivity.java
ShankOffice on 20 Mar 2014
Completed Assignment
0 contributors

RawBlameHistory

272 lines (201 sloc) 7.677 kb


package course.labs.contentproviderlab;
import java.util.ArrayList;
import
import
import
import
import
import
import
import
import
import
import
import

android.app.ListActivity;
android.app.LoaderManager.LoaderCallbacks;
android.content.Context;
android.content.CursorLoader;
android.content.Loader;
android.database.Cursor;
android.location.Location;
android.location.LocationListener;
android.location.LocationManager;
android.os.Bundle;
android.util.Log;
android.view.Menu;

import
import
import
import
import
import
import

android.view.MenuInflater;
android.view.MenuItem;
android.view.View;
android.view.View.OnClickListener;
android.widget.TextView;
android.widget.Toast;
course.labs.contentproviderlab.provider.PlaceBadgesContract;

public class PlaceViewActivity extends ListActivity implements


LocationListener, LoaderCallbacks<Cursor> {
private static final long FIVE_MINS = 5 * 60 * 1000;
private static String TAG = "Lab-ContentProvider";
// The last valid location reading
private Location mLastLocationReading;
// The ListView's adapter
// private PlaceViewAdapter mAdapter;
private PlaceViewAdapter mCursorAdapter;
// default minimum time between new location readings
private long mMinTime = 5000;
// default minimum distance between old and new readings.
private float mMinDistance = 1000.0f;
// Reference to the LocationManager
private LocationManager mLocationManager;
// A fake location provider used for testing
private MockLocationProvider mMockLocationProvider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// TODO - Set up the app's user interface
// This class is a ListActivity, so it has its own ListView
// TODO - add a footerView to the ListView
// You can use footer_view.xml to define the footer
TextView footerView = (TextView) getLayoutInflater().inflate(R.layout.footer_view, null);
getListView().setFooterDividersEnabled(true);
getListView().addFooterView(footerView);
// TODO - When the footerView's onClick() method is called, it must issue the
// following log call
// log("Entered footerView.OnClickListener.onClick()");
//
//
//
//
//

footerView must respond to user clicks.


Must handle 3 cases:
1) The current location is new - download new Place Badge. Issue the
following log call:
log("Starting Place Download");

// 2) The current location has been seen before - issue Toast message.
// Issue the following log call:
// log("You already have this location badge");
// 3) There is no current location - response is up to you. The best
// solution is to disable the footerView until you have a location.
// Issue the following log call:

// log("Location data is not available");


footerView.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View V){
log("Entered footerView.OnClickListener.onClick()");
if(mLastLocationReading == null){
log("Location data is not available");
return;
}
if(mCursorAdapter.intersects(mLastLocationReading)){
log("You already have this location badge");
Toast.makeText(getApplicationContext(), "You already have this location
badge",Toast.LENGTH_LONG).show();
return;
}
PlaceDownloaderTask pd = new PlaceDownloaderTask(PlaceViewActivity.this);
pd.execute(mLastLocationReading);
log("Starting Place Download");
}
});
// TODO - Create and set empty PlaceViewAdapter
// ListView's adapter should be a PlaceViewAdapter called mCursorAdapter
Cursor cursor = getContentResolver().query(PlaceBadgesContract.CONTENT_URI, null, null, null, null);
mCursorAdapter = new PlaceViewAdapter(this, cursor, 0);
setListAdapter (mCursorAdapter);
// TODO - Initialize a CursorLoader
getLoaderManager().initLoader(0, null, this);
}
@Override
protected void onResume() {
super.onResume();
mMockLocationProvider = new MockLocationProvider(
LocationManager.NETWORK_PROVIDER, this);
// TODO - Check NETWORK_PROVIDER for an existing location reading.
// Only keep this last reading if it is fresh - less than 5 minutes old.
mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
Location newLocation =
mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if(newLocation != null && ( age(mLastLocationReading) > FIVE_MINS)){
mLastLocationReading = newLocation;
}

// TODO - Register to receive location updates from NETWORK_PROVIDER


mLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, mMinTime, mMinDistance,
this);
}
@Override

protected void onPause() {


mMockLocationProvider.shutdown();
// TODO - Unregister for location updates
mLocationManager.removeUpdates(this);
super.onPause();
}
public void addNewPlace(PlaceRecord place) {
log("Entered addNewPlace()");
mCursorAdapter.add(place);
}
@Override
public void onLocationChanged(Location currentLocation) {
// TODO - Handle location updates
// Cases to consider
// 1) If there is no last location, keep the current location.
// 2) If the current location is older than the last location, ignore
// the current location
// 3) If the current location is newer than the last locations, keep the
// current location.
if(mLastLocationReading == null || age(mLastLocationReading) > age(currentLocation)){
mLastLocationReading = currentLocation;
}

}
@Override
public void onProviderDisabled(String provider) {
// not implemented
}
@Override
public void onProviderEnabled(String provider) {
// not implemented
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// not implemented
}
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
log("Entered onCreateLoader()");
// TODO - Create a new CursorLoader and return it
return new CursorLoader(getApplicationContext(),PlaceBadgesContract.CONTENT_URI,null,null,null,null);
}
@Override
public void onLoadFinished(Loader<Cursor> newLoader, Cursor newCursor) {
// TODO - Swap in the newCursor
mCursorAdapter.swapCursor(newCursor);

}
@Override
public void onLoaderReset(Loader<Cursor> newLoader) {
// TODO - Swap in a null Cursor
mCursorAdapter.swapCursor(null);
}
private long age(Location location) {
return System.currentTimeMillis() - location.getTime();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.print_badges:
ArrayList<PlaceRecord> currData = mCursorAdapter.getList();
for (int i = 0; i < currData.size(); i++) {
log(currData.get(i).toString());
}
return true;
case R.id.delete_badges:
mCursorAdapter.removeAllViews();
return true;
case R.id.place_one:
mMockLocationProvider.pushLocation(37.422, -122.084);
return true;
case R.id.place_invalid:
mMockLocationProvider.pushLocation(0, 0);
return true;
case R.id.place_two:
mMockLocationProvider.pushLocation(38.996667, -76.9275);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private static void log(String msg) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG, msg);
}
}

Coursera_Android_Week8/SourceFiles/Skeleton/ContentProviderLabUser/src/
course/labs/contentproviderlab/PlaceViewAdapter.java
ShankOffice on 20 Mar 2014
Completed Assignment
0 contributors

RawBlameHistory

246 lines (190 sloc) 6.683 kb


package course.labs.contentproviderlab;
import
import
import
import
import
import

java.io.BufferedOutputStream;
java.io.File;
java.io.FileNotFoundException;
java.io.FileOutputStream;
java.io.IOException;
java.util.ArrayList;

import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import

android.content.ContentValues;
android.content.Context;
android.database.Cursor;
android.graphics.Bitmap;
android.graphics.Bitmap.CompressFormat;
android.graphics.BitmapFactory;
android.location.Location;
android.net.Uri;
android.os.Environment;
android.util.Log;
android.view.LayoutInflater;
android.view.View;
android.view.ViewGroup;
android.widget.CursorAdapter;
android.widget.ImageView;
android.widget.TextView;
course.labs.contentproviderlab.provider.PlaceBadgesContract;

public class PlaceViewAdapter extends CursorAdapter {


private
private
private
private
private
private

static final String APP_DIR = "ContentProviderLab/Badges";


ArrayList<PlaceRecord> list = new ArrayList<PlaceRecord>();
static LayoutInflater inflater = null;
Context mContext;
String mBitmapStoragePath;
static String TAG = "Lab-Shashank";

public PlaceViewAdapter(Context context, Cursor cursor, int flags) {

super(context, cursor, flags);


mContext = context;
inflater = LayoutInflater.from(mContext);
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
try {
String root = mContext.getExternalFilesDir(null)
.getCanonicalPath();
if (null != root) {
File bitmapStorageDir = new File(root, APP_DIR);
bitmapStorageDir.mkdirs();
mBitmapStoragePath = bitmapStorageDir.getCanonicalPath();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public Cursor swapCursor(Cursor newCursor) {
super.swapCursor(newCursor);
if (null != newCursor) {
// TODO - clear the ArrayList list so it contains
// the current set of PlaceRecords. Use the
// getPlaceRecordFromCursor() method to add the
// current place to the list
list.clear();
if(newCursor.moveToFirst()){
do{
list.add(getPlaceRecordFromCursor(newCursor));
}while(newCursor.moveToNext() == true);
}
// Set the NotificationURI for the new cursor
newCursor.setNotificationUri(mContext.getContentResolver(),
PlaceBadgesContract.CONTENT_URI);
}
return newCursor;
}
// returns a new PlaceRecord for the data at the cursor's
// current position
private PlaceRecord getPlaceRecordFromCursor(Cursor cursor) {
String flagBitmapPath = cursor.getString(cursor
.getColumnIndex(PlaceBadgesContract.FLAG_BITMAP_PATH));
String countryName = cursor.getString(cursor
.getColumnIndex(PlaceBadgesContract.COUNTRY_NAME));
String placeName = cursor.getString(cursor
.getColumnIndex(PlaceBadgesContract.PLACE_NAME));
double lat = cursor.getDouble(cursor
.getColumnIndex(PlaceBadgesContract.LAT));

double lon = cursor.getDouble(cursor


.getColumnIndex(PlaceBadgesContract.LON));
return new PlaceRecord(null, flagBitmapPath, countryName, placeName,
lat, lon);
}
public int getCount() {
return list.size();
}
public Object getItem(int position) {
return list.get(position);
}
public long getItemId(int position) {
return position;
}
static class ViewHolder {
ImageView flag;
TextView country;
TextView place;
}
public boolean intersects(Location location) {
for (PlaceRecord item : list) {
if (item.intersects(location)) {
return true;
}
}
return false;
}
public void add(PlaceRecord listItem) {
String lastPathSegment = Uri.parse(listItem.getFlagUrl())
.getLastPathSegment();
String filePath = mBitmapStoragePath + "/" + lastPathSegment;
log("Entered add method");
if (storeBitmapToFile(listItem.getFlagBitmap(), filePath)) {
listItem.setFlagBitmapPath(filePath);
list.add(listItem);
log("Entered add method1");
// TODO - Insert new record into the ContentProvider
ContentValues values = new ContentValues();
values.put(PlaceBadgesContract.FLAG_BITMAP_PATH, listItem.getFlagBitmapPath());
values.put(PlaceBadgesContract.COUNTRY_NAME, listItem.getCountryName());
values.put(PlaceBadgesContract.PLACE_NAME, listItem.getPlace());
values.put(PlaceBadgesContract.LAT, listItem.getLat());
values.put(PlaceBadgesContract.LON, listItem.getLon());
mContext.getContentResolver().insert(PlaceBadgesContract.CONTENT_URI, values);
mContext.getContentResolver().notifyChange(PlaceBadgesContract.CONTENT_URI, null);
}
}
public ArrayList<PlaceRecord> getList() {

return list;
}
public void removeAllViews() {
list.clear();
// TODO - delete all records in the ContentProvider
mContext.getContentResolver().delete(PlaceBadgesContract.CONTENT_URI, null, null);
mContext.getContentResolver().notifyChange(PlaceBadgesContract.CONTENT_URI, null);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder holder = (ViewHolder) view.getTag();
holder.flag.setImageBitmap(getBitmapFromFile(cursor.getString(cursor
.getColumnIndex(PlaceBadgesContract.FLAG_BITMAP_PATH))));
holder.country.setText("Country: "
+ cursor.getString(cursor
.getColumnIndex(PlaceBadgesContract.COUNTRY_NAME)));
holder.place.setText("Place: "
+ cursor.getString(cursor
.getColumnIndex(PlaceBadgesContract.PLACE_NAME)));
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View newView;
ViewHolder holder = new ViewHolder();
newView = inflater.inflate(R.layout.place_badge_view, null);
holder.flag = (ImageView) newView.findViewById(R.id.flag);
holder.country = (TextView) newView.findViewById(R.id.country_name);
holder.place = (TextView) newView.findViewById(R.id.place_name);
newView.setTag(holder);
return newView;
}
private Bitmap getBitmapFromFile(String filePath) {
return BitmapFactory.decodeFile(filePath);
}
private boolean storeBitmapToFile(Bitmap bitmap, String filePath) {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
try {
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(filePath));
bitmap.compress(CompressFormat.PNG, 100, bos);
bos.flush();
bos.close();
} catch (FileNotFoundException e) {
return false;
} catch (IOException e) {
return false;

}
return true;
}
return false;
}
private static void log(String msg) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG, msg);
}
}

Coursera_Android_Week8/SourceFiles/Skeleton/ContentProviderLabUser/And
roidManifest.xml
ShankOffice on 20 Mar 2014
Completed Assignment
0 contributors

RawBlameHistory

33 lines (28 sloc) 1.242 kb


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="course.labs.contentproviderlab"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-sdk
android:minSdkVersion="17"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"

android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".PlaceViewActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

You might also like