Mobile
Take Photo Using ACTION_IMAGE_CAPTURE Intent
3In this post we will build a working sample app that allows the user to press a button to take a photo using the phone’s camera app (or any other available) and then loads this photo into an ImageView. You could of course do anything you like with the photo such as upload it to a web service or save it to permanent storage.
Begin by creating a new Android project, then open up your main.xml layout file and edit it. The below xml creates an ImageButton and an ImageView. Everything we need for the sample. The ImageView references a placeholder image.. just a little snap of someone I spotted the last time I was at the beach.
<?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"
android:gravity="center_horizontal"
android:background="#FFFFFF">
<ImageButton
android:id="@+id/btn_take_photo"
android:src="@android:drawable/ic_menu_camera"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="5dp" />
<ImageView
android:id="@+id/img_main"
android:src="@drawable/kiss_from_a_rose"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:scaleType="fitXY"
android:adjustViewBounds="true"
android:padding="5dp" />
</LinearLayout>
In your Activity’s onCreate() method, attach a listener to the button. When the button is clicked we want to start an ACTION_IMAGE_CAPTURE Intent using startActivityForResult().
findViewById(R.id.btn_take_photo).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(i, REQ_CODE_PHOTO_TAKE);
}
});
You’ll also need to create the REQ_CODE_PHOTO_TAKE constant. This value will be returned in the resultCode.
private static final int REQ_CODE_PHOTO_TAKE = 1;
Next up push Alt+Shift+S and click “Override/Implement Methods” from the menu. Choose to Override onActivityResult() and click ok.
You’ll notice this method has three parameters. ‘resultCode’ is self explanatory – if this is anything other than RESULT_OK we’ll want to return immediately. An example where this might happen is if the user were to push the button to take a photo but then push their phone’s back button immediately rather than take one. requestCode contains the value that we passed in during startActivityForResult(), in our case this is REQ_CODE_PHOTO_TAKE. Lastly is the returned Intent. We can use this to get a Uri to the data by calling getData().
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode != RESULT_OK) return;
switch (requestCode) {
case REQ_CODE_PHOTO_TAKE:
Uri u = data.getData();
onPhotoReturned(u);
break;
default:
break;
}
}
Lastly we’ll want to display the photo in our ImageView. Create the new method, onPhotoReturn(Uri u). We use the Uri to open an InputStream and from this we can create a BitmapDrawable which can be used to set the Drawable for the ImageView.
private void onPhotoReturned(Uri u) {
InputStream is = null;
try {
ContentResolver cResolver = getContentResolver();
is = cResolver.openInputStream(u);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
BitmapDrawable bmp = new BitmapDrawable(is);
ImageView mainImage = (ImageView)findViewById(R.id.img_main);
mainImage.setImageDrawable(bmp);
}
Working code for this app can be found on my github and a screenshot of it in action is below:
Do not use City Main Administrators or The Fone Clinic
13Since purchasing my HTC Desire nearly 18 months’ ago I’ve had insurance through Citymain Administrators. It’s £5.99 a month and covers me for theft and accidents. The service from their call centre has been all in all quite good since I dropped and broke the screen on my phone on September 15th 2011, unfortunately the company they use for repairs has now taken almost three weeks to repair my phone. I was told last Friday that my phone was finally being repaired – after being told this I kind of expected it to arrive Saturday or Monday. That’s a reasonable expectation in a world that expects good customer service, no? Monday 3rd October I was told it was repaired but waiting to be posted to me. Today, Wednesday 5th October I was told that it was still waiting to be posted to me and this should hopefully happen tomorrow. If this holds true – and I have my doubts – then I’ll get my phone back on Friday which makes it three weeks. The worst part is the length of time that I know my phone has been sat idle.
They don’t appear to be a small outfit either, covering units 18 – 20 in the picture below. You’d think someone could post a phone for a customer regularly chasing and specifically requesting it be returned in time for Droidcon tomorrow?
From this experience I will soon be cancelling my policy with Citymain Administrators and do not recommend you use either them or The Fone Clinic in Southend-On-Sea.
If anyone can recommend to me a UK phone insurance policy that doesn’t let you down when it comes to needing a repair, please let me know…
Android: Simple Full Screen Image Viewer Activity
0Here’s the code for a simple full screen ImageViewerActivity. It uses the SDImageLoader from this post to load the image asynchronously from the SD card.
public class ImageViewerActivity extends Activity {
public static final String IMAGE_PATH = "imagevieweractivityfilepath";
private final SDImageLoader mImageLoader = new SDImageLoader();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.imageviewer);
Bundle extras = getIntent().getExtras();
if(extras != null) {
String imagePath = extras.getString(IMAGE_PATH);
if(imagePath != null) {
ImageView i = (ImageView)findViewById(R.id.image_viewer_image);
mImageLoader.load(this, imagePath, i);
}
}
}
}
Here’s an example of how to use this activity:
//load the filepath from the database Cursor c = mDbHelper.fetchCapture(info.id); String filePath = c.getString(c.getColumnIndexOrThrow(SpecimenHunterDatabaseAdapter.KEY_CAPTURES_PHOTO)); //create the new intent Intent it = new Intent(this, ImageViewerActivity.class); //put the filepath into the extras bundle it.putExtra(ImageViewerActivity.IMAGE_PATH, filePath); //start activity. startActivity(it);
Here’s the xml layout file. Use the src of the ImageView to set the image to use as a placeholder while the image you wish to display loads from the SD card.
<?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" android:layout_weight="1" android:layout_gravity="center" android:gravity="center"> <ImageView android:id="@+id/image_viewer_image" android:src="@drawable/thumbnail_placeholder" android:layout_width="fill_parent" android:layout_height="fill_parent" android:adjustViewBounds="true" android:layout_gravity="center" android:gravity="center" /> </LinearLayout>
Android: Using a custom font
0Can you set a custom font from XML? As far as I’ve managed to find, the answer is no.
So instead, how do you do this programatically?
First start by creating an ‘assets’ folder in your project, within this create a folder called ‘fonts’. ‘assets’ should be on the same level as ‘res’ and not within it. Drag your font file in here. Need a font? Lots of free, open source ones available here: http://www.google.com/webfonts/v2.
Setting the font on a View couldn’t be simpler, here’s an example using the Lobster font from Google webfonts
TextView someTextView = (TextView)findViewById(R.id.some_text_view_id); Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Lobster.ttf"); someTextView.setTypeface(tf);
If needing to set the font in a list item, I load the font to a member variable within the constructor of my ListAdapter so that it can be used in my overridden newView() rather than loading it every time.
Android: Retain values on orientation change
0When you change the orientation of your phone. The current activity is destroyed via onDestroy() and then recreated with onCreate() being called. This presented a problem for me with a list that has different ways of sorting – I wanted this sorted order to persist while the current activity was open, but there was no need for it to do so when coming to the activity again. Here’s a quick demonstration of how to achieve this.
The type of sort to do is stored in a member variable. This uses constants from my Database Adapter class. When the data is pulled from the database, this sort code is passed in and used by the DB Adapter, data is returned sorted correctly. When the phone’s orientation is changed we want the list to remain sorted in the same order.
private Integer mListSortCode;
Next in your activity, override onRetainNonConfigurationInstance(). This method is called just before onDestroy(). In my example I need only one value so I made the mListSortCode an Integer object. It’s easy to see how you could create an inner class that would hold all the data you need to retain and use it here.
@Override
public Object onRetainNonConfigurationInstance() {
final Integer sortcode = mListSortCode;
return sortcode;
}
In your onCreate() method call getLastNonConfigurationInstance() to get a reference to this object and cast it to the correct type. If onCreate() is being called because of any reason other than an orientation change it will be null, so check for this and handle appropriately:
final Integer previousConfigSortCode = (Integer)getLastNonConfigurationInstance();
if (previousConfigSortCode != null) {
mListSortCode = previousConfigSortCode;
} else {
//set to default
mListSortCode = SpecimenHunterDatabaseAdapter.SORT_NONE;
}
Android: populate a Spinner from a SQLite database
22Here’s a bit of code to populate a spinner with data from a database. The database table contains info about all the different species of fish within my app. I want the user to choose the species from the spinner and then the ID of that species is then stored as a foreign key within my ‘captures’ table.
First start by defining the spinner in your xml layout, here’s the example from my layout:
<Spinner
android:id="@+id/spinner_species"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:prompt="@string/addcapture_species_prompt" />
From your Activity, within your onCreate() method, get a reference to the spinner and a Cursor to all your species from your database. Pass your cursor into startManagingCursor() to let your Activity take care of it:
Spinner speciesSpinner = (Spinner)findViewById(R.id.spinner_species); Cursor speciesCursor = mDbAdapter.fetchAllSpecies(); startManagingCursor(speciesCursor);
Create a SimpleCursorAdapter to bind the text you want to be displayed on your spinner to the textview display on your spinner and set this to the spinner. SpecimenHunterDatabaseAdapter.KEY_SPECIES_NAME is a String constant of the name of the column in my database containing the name. android.R.layout.simple_spinner_item is a predefined Android layout for the spinner and android.R.id.text1 is the textview defined within this. android.R.layout.simple_spinner_dropdown_item is our layout for the items in the menu that appears when you tap the spinner.
String[] from = new String[] { SpecimenHunterDatabaseAdapter.KEY_SPECIES_NAME };
int[] to = new int[] { android.R.id.text1 };
SimpleCursorAdapter speciesSpinnerAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item, speciesCursor, from, to);
speciesSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
speciesSpinner.setAdapter(speciesSpinnerAdapter);
When the user selects an option on the spinner, we need store that somewhere. Create a member in your Activity to hold the value:
private int mSpinnerSpeciesId;
Lastly, back in your onCreate() method below the call to setAdapter() we need to attach an OnItemSelectedListener to the spinner. The method onItemSelected() will be called when the selected item on the spinner changes – it’s also called when your activity starts with the first value on the spinner’s list.
speciesSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
Cursor c = (Cursor)parent.getItemAtPosition(pos);
mSpinnerSpeciesId = c.getInt(c.getColumnIndexOrThrow(SpecimenHunterDatabaseAdapter.KEY_SPECIES_ROWID));
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
Here’s the spinner in action after being pressed:
Android: Lock and unlock screen orientation
15Need to temporarily lock the screen orientation on your app? When calling setRequestedOrientation() on your activity, it will no longer allow the orientation to change even when the phone is rotated. So check what the current orientation of the screen is and set it to the same orientation with setRequestedOrientation()
public static void lockCurrentScreenOrientation(Activity a) {
if(a.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
a.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else {
a.setRequestedOrientation(a.getRequestedOrientation());
}
}
To unlock it again, pass ActivityInfo.SCREEN_ORIENTATION_USER:
public static void unlockScreenOrientation(Activity a) {
a.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
}









