Posts tagged Android
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:
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);
}
Android: Implement a Dashboard Layout Activity
18In this post I will show you the steps to quickly implement a dashboard activity in your app starting with the open source, apache licence DashboardLayout by romannurik from the Google I/O app.
A dashboard is the welcoming screen of your app. It provides a starting point for the user. A dashboard can be static or dynamic, e.g. you can incorporate live wallpapers or changing content such as news items.
On a category dashboard, entrance points to content are displayed in several categories. The categories are represented by an icon and a title, and lie full screen in a grid orientation. This lay-out allows the user to find content faster.
First start by creating a new class DashboardLayout.java within your project and copy and pasting the code from github into it. You’ll need to change package com.google.android.apps.iosched.ui.widget; to the package where it is located in your project and press ctrl+shift+O in Eclipse to re-organise imports.
Next up create a new class, DashboardActivity that extends Activity – in my case it extends GDActivity as I am also using the Greendroid library – for quick implementation of an ActionBar but yours can just extend Activity.
Add this new Activity to your AndroidManifest.xml and make it the main one, (mine is in the .ui package, if yours is in the root or elsewhere then remove .ui and change as appropriate):
<activity android:name=".ui.DashboardActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Create a new xml layout, dashboard.xml. Where mine has the tag <com.samcoles.layout.DashboardLayout> you will need to change the part prefixing DashboardLayout to the package where it is located. You may notice they all use the same @drawable, dashboard_buton_add – you will want to change this per button to something more relevant but for simplicity, here they are all going to use the same graphics.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<com.samcoles.layout.DashboardLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button android:id="@+id/dashboard_button_add"
style="@style/DashboardButton"
android:text="@string/activity_add"
android:drawableTop="@drawable/dashboard_button_add" />
<Button android:id="@+id/dashboard_button_viewall"
style="@style/DashboardButton"
android:text="@string/activity_viewall"
android:drawableTop="@drawable/dashboard_button_add" />
<Button android:id="@+id/dashboard_button_manage"
style="@style/DashboardButton"
android:text="@string/activity_manage"
android:drawableTop="@drawable/dashboard_button_add" />
<Button android:id="@+id/dashboard_button_personalbests"
style="@style/DashboardButton"
android:text="@string/activity_personalbests"
android:drawableTop="@drawable/dashboard_button_add" />
</com.samcoles.layout.DashboardLayout>
</LinearLayout>
You’ll notice in the dashboard.xml layout there are a number of @string, @style and @drawable resources referenced. Create or replace the string resources within strings.xml, which is created by default in Eclipse when you create a project. Also in your /res/values folder create a new file style.xml and in here place the style for DashboardButton:
<?xml version="1.0" encoding="utf-8"?> <resources> <style name="DashboardButton"> <item name="android:layout_gravity">center_vertical</item> <item name="android:layout_width">wrap_content</item> <item name="android:layout_height">wrap_content</item> <item name="android:gravity">center_horizontal</item> <item name="android:drawablePadding">2dp</item> <item name="android:textSize">14sp</item> <item name="android:textStyle">bold</item> <item name="android:textColor">#ff0000</item> <item name="android:background">@null</item> </style> </resources>
Next up create a folder /res/drawable and in here create a new file, dashboard_button_add.xml (you will need to create multiple different xml files for each button in here and reference them from the dashboard.xml layout. As I mentioned before, we are using the same one for all four buttons here.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/dashboard_add_button_selected"
android:state_focused="true"
android:state_pressed="true" />
<item android:drawable="@drawable/dashboard_add_button_selected"
android:state_focused="false"
android:state_pressed="true" />
<item android:drawable="@drawable/dashboard_add_button_selected" android:state_focused="true" />
<item android:drawable="@drawable/dashboard_add_button_default"
android:state_focused="false"
android:state_pressed="false" />
</selector>
Create and add the graphics referenced above to your /res/drawable-hdpi folder. These are add_button_default.png and add_button_selected.png. I made mine the same size as the ones in the Google I/O app, 144px * 96px but the proportions aren’t fixed using DashboardLayout.
Here they are in all their glory. The best part about them is that I didn’t even manage to get the horizontal line straight. Once these placeholders are in you can update them later with proper graphics as well as create new @drawable xml for each different button on the dashboard.
Next up, head back to your DashboardActivity. Within this class create a new inner class, DashboardClickListener that implements the OnClickListener interface. Implement the method onClick(). Here you can call getId() on the View passed to the handler, to get the Id of which button was clicked – this is specified in your dashboard.xml layout. Put this in a switch block and you can then handle the click event however you like, it’s likely you’ll want to just start a new activity with each, here’s mine:
private class DashboardClickListener implements OnClickListener {
@Override
public void onClick(View v) {
Intent i = null;
switch (v.getId()) {
case R.id.dashboard_button_add:
i = new Intent(DashboardActivity.this, AddCapture.class);
break;
case R.id.dashboard_button_viewall:
i = new Intent(DashboardActivity.this, ViewAll.class);
break;
case R.id.dashboard_button_manage:
i = new Intent(DashboardActivity.this, Manage.class);
break;
case R.id.dashboard_button_personalbests:
i = new Intent(DashboardActivity.this, PersonalBests.class);
break;
default:
break;
}
if(i != null) {
startActivity(i);
}
}
}
Last but certainly not least, in your overridden onCreate() method in DashboardActivity, you need to create an instance of DashboardClickListener and attach this to each button. Below is my full overridden onCreate() method – setActionBarContentView() is just the GreenDroid alternative to setContentView() – you can use the latter instead.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setActionBarContentView(R.layout.dashboard);
//attach event handler to dash buttons
DashboardClickListener dBClickListener = new DashboardClickListener();
findViewById(R.id.dashboard_button_add).setOnClickListener(dBClickListener);
findViewById(R.id.dashboard_button_viewall).setOnClickListener(dBClickListener);
findViewById(R.id.dashboard_button_manage).setOnClickListener(dBClickListener);
findViewById(R.id.dashboard_button_personalbests).setOnClickListener(dBClickListener);
}
If all went well, you should now have a working dashboard! Remember you can have more or less buttons on your dashboard, but 6 options appears to be the standard max across most Android Apps I’ve seen and used. Aside from the Google I/O 2011 app, other examples include LinkedIn and tastecard.
A working example project based on this post can be found on github.












