Android for Ubiquitous Computing Researchers Andrew Rice University of Cambridge 17-Sep-2011
Getting started Website for the tutorial: http://www.cl.cam.ac.uk/~acr31/ubicomp/ Contains links to downloads and resources. First we need to install and set up the development tools: Java Eclipse Android Software Development Kit Android Developer Tools plugin for Eclipse Instructions are on the tutorial website
We will build a GeoMessaging application The user can leave a message consisting of an image and some text at their current location Whenever anyone with the application installed goes near that location their phone displays the message
1) Press button to take a picture with the camera 2) Type message into the box provided 3) Press the "Leave Message" button to send message & location to the server
Use the Android SDK to build applications Available for free for Windows, Linux and Mac 1) target libraries for different android versions 2) extra versions with Google API (like maps) 3) emulator 4) tools for building apks 5) proguard for code obfuscation 6) adb debugger Optional eclipse plugin installed separately
A phone emulator is included Based around QEMU Emulates an ARM platform (goldfish) Contains some useful features like injecting a location Tips: Leave it running all the time in the background Turn on snapshots [CTRL]+[F21] simulates a screen rotation
Don't expect the emulator to be fast! Intel Core2 Quad CPU 2.66GHz, 8GB RAM Intel Core Duo CPU 1.66 GHz, 1GB RAM
The emulator supports a wide range of configurations
This tutorial uses Version 2.1 Platform Codename API Level Usage Cool new feature 1.5 Cupcake 3 1.0% Assisted GPS 1.6 Donut 4 1.8% Gestures and Text-to-speech 2.1 Eclair 7 13.3% Bluetooth API 2.2 Froyo 8 51.2% Wifi hotspots + JIT for Dalvik 2.3-2.3.2 Gingerbread 9 0.6% 2.3.2-2.3.4 Gingerbread 10 30.7% Concurrent garbage collector 3.0 Honeycomb 11 0.2% Large screen support (tablets) 3.1 Honeycomb 12 0.7% USB Host support 3.2 Honeycomb 13 0.5% Usage figures from 2 weeks in September 2011
Launch the emulator, leave it running [CTRL]+[F12]
GeoTutorial Overview 1. Creating the project 2. Building the user interface 3. Taking and storing a photo 4. Collecting a GPS location 5. Uploading message to the server
Create a new project File -> New -> Other... -> Android project
Launch your project Right-click on GeoTutorial Run As -> Android Application
GeoTutorial Overview 1. Creating the project 2. Building the user interface 3. Taking and storing a photo 4. Collecting a GPS location 5. Uploading message to the server
Now we will design the user interface Double click on GeoTutorial -> res -> main.xml
Make sure that the 'Outline' and 'Properties' views are visible You can add it by going to Window -> Show view -> Outline Window -> Show view -> Other... -> Properties
The user interface is declared in XML under the hood
The abstraction is of a tree of views
Delete the default TextView Delete the TextView - "HelloWorld, GeoTutorial" by clicking on it in the Outline view and pressing [DELETE]
Add another LinearLayout 1. Click on the Layouts section of the Palette 2. Drag the LinearLayout (Vertical) 3. Drop it onto the phone 4. Click the Properties view 5. Change the id to @+id/takephotocontainer 6. Save your changes
The Android plugin automatically generates ID's to use in your code Double click on GeoTutorial -> gen -> R.java We entered an id of @+id/takephotobutton @ + id/ entry in R.java auto-generate it the 'id' section
Set the size of the LinearLayout 1. Click back to main.xml 2. Open the Misc Properties section 3. Set Layout height to '150dp' 4. Set Layout width to 'fill_parent'
The size of a View can be 'relative' or 'absolute' Absolute size Relative size fill_parent View will grow to fill as much space as is available dp Size will be exactly this number of Density Independent Pixels (dp). One dp is 0.15875 millimeters on wrap_content View will shrink to be as small as possible for the content it contains the screen of the device you are running on
Now add an ImageButton 1. Choose the Images & Media Palette 2. Drag the ImageButton view 3. Drop it on the phone 4. Popup dialog, choose System resources 5. Choose ic_menu_camera 6. Click OK 7. Autogenerate a new ID 'takephotobutton' 8. Expand it to fill the width and height
Now add a plain text box (EditText) 1. Choose the Text Fields Palette 2. Drag the 'Plain Text' component 3. Drop it on the lower part of the phone screen 4. Autogenerate an ID 'editmessage' Ensure your design has editmessage as a child of the first LinearLayout and not of takephotocontainer
Constant strings in your application should be placed in a separate resource file 1. Open GeoTutorial -> res -> values -> strings.xml 2. Click Add... 3. In dialog, choose String 4. Enter name 'editmessagedefaulttext' 5. Enter value 'Please enter your message here' (or in your choice of language) 6. Save your changes
Set the default text of the text box Set the Text property to @string/editmessagedefaulttext Notice the similarity between strings and IDs Have a look in R. java to see what's happened
Add the final button to the user interface 1. Drag the Button view from the Form Widgets palette 2. Drop it on the phone screen under the text box 3. Set it to fill the width of the screen 4. Change the ID to 'sendmessagebutton' 5. Add a new string 1. Set the key to be 'sendmessagebuttontext' 2. Set the value to be 'Send Message' 6. Set the Text property of the new button to use this string 7. Save your changes 8. Run your application (Run as -> Android application)
When we rotate the screen our application layout rotates with it We can provide different layouts if we want main.xml Default layout main-land.xml Override default for landscape orientation main-large.xml Override default for large screens main-land-large.xml Override default for large, landscape screens Complete list of qualifiers is here: http://developer.android. com/guide/topics/resources/providing-resources.html
GeoTutorial Overview 1. Creating the project 2. Building the user interface 3. Taking and storing a photo 4. Collecting a GPS location 5. Uploading message to the server
Android calls oncreate() first 1. Open GeoTutorialActivity.java 2. The oncreate() method gets called when your app is starting 3. The call to setcontentview(...) finds the XML defining the layout 'main' and creates the user interface from it
Now override the remaining lifecycle methods 1. Right-click in the class (just before the final closing brace) 2. Choose 'Source' 3. Choose 'Override/ Implement methods' 4. Select the methods to override 5. Choose OK
Add a debug message to each method 1. Add a constant value TAG to label each message 2. Add an import for android.util.log 3. Write a log message for each life-cycle method 4. Run your application again
The debug log can be viewed in Eclipse 1. Open the DDMS perspective: try the 'Open Perspective' button 2. Select the Android instance you want to connect to 3. Find the LogCat tab 4. Scroll to the bottom of the log 5. Look for 'GeoTutorial' events
Experiment to see when the lifecycle methods are called Press the 'Home' button to leave your application (You can start it again from the application menu on the phone) Use the 'Back' button Rotate the screen
Think carefully about what you do in each lifecycle method oncreate() Setup static variables, create the user interface, register event handlers onstart() Register for events (e.g. GPS) onrestart() onresume() Start animations onpause() Commit unsaved data, stop animations, stop consuming CPU onstop() Deregister for any events ondestroy()
Add a handler to respond to presses of the photo button
To capture an image we use an Intent Intents are events passed to move between parts of an application and between applications Explicit intent say exactly which class you wish to be invoked the runtime locates it (starts an application if needed) Normally used to move within an application Implicit intent say what kind of action you want to take place the runtime determines the best way to service it e.g dial a number could be serviced by built-in Dialler or a VOIP client Normally used to move between applications
Change the onclicklistener to request a photo Now test your application
Many Intents need to return a result You specify a requestcode This code is returned back so you know what the information was for The resultintent contains any returned data
Override the onactivityresult method
Extract the Bitmap from the returned data 1. Add a field to your class to store the Bitmap object (we need it later to send to the server) 2. Extract the bitmap from the result 3. Add import statement for android.graphics.bitmap
We need a reference to the button and its container 1. Create two new field variables to hold the references 2. Make sure you assign to the field and not a local variable 3. Find the container in the layout 4. Add suitable import statements
Remove the ImageButton and replace it with an ImageView Now test your application
GeoTutorial Overview 1. Creating the project 2. Building the user interface 3. Taking and storing a photo 4. Collecting a GPS location 5. Uploading message to the server
We request location updates and wait for a callback oncreate Find the LocationManager Create a LocationListener to handle new location events onstart Register for GPS location updates from the LocationListener. This will start the GPS. onstop Unregister for location updates. This will let the GPS switch off.
Create the LocationListener in the oncreate method 1. Add new field variables for the LocationManager and LocationListener 2. Get a reference to the system service LocationManager 3. Create a new LocationListener object 4. (Add appropriate import statements)
Register in the onstart method and unregister in the onstop method Now test your application (it should crash)
'Force close' means that your application threw an exception
We need permission to use the GPS Android uses a coarse grained permission system The application describes which permissions it needs in its manifest file The user is asked if this is OK when the application is installed Runtime checks are used to check whether the application has the permissions it needs You can see in the exception report which permission was missing
We request the permission in the Manifest file 1. Open AndroidManifest. xml 2. Choose the Permissions tab 3. Click Add... 4. Choose 'Uses Permission' 5. Click OK 6. Choose ACCESS_FINE_LOCATION 7. Save the changes Now test your application
We need some extra permissions for later on too... add INTERNET and WRITE_EXTERNAL_STORAGE permissions to your application
Use the DDMS view to inject a location event
Change the LocationListener to store the location we receive 1. Add a new field 'lastlocation' to hold the saved value 2. When the location changes, save the value in lastlocation
GeoTutorial Overview 1. Creating the project 2. Building the user interface 3. Taking and storing a photo 4. Collecting a GPS location 5. Uploading message to the server
The GeoMessagingServer receives your messages The server is implemented in Java Servlets Source code is available on the website Follow the link on the website and view the current set of messages
We upload our new message to the server using an HTTP POST request Download additional libraries to include in your application from the website apache-mime4j-0.6.jar httpmime-4.0.jar servertools.jar Save these files in the project directory inside your eclipse workspace Right click on the project and choose Refresh to make them show up
Add the libraries to the build path of your application 1. Select the three library files 2. Right-click and choose Build path -> Add to Build path
Porting a library to Android is straightforward Android supports a subset of the Java class libraries Swing or AWT are of course omitted If your library doesn't use any classes outside this then you can just add the jar file to your application as before If some unsupported parts of Java are required then you'll have to make modifications
1. Create a method stub 'postmessage' 2. Get a reference to the sendmessagebutton 3. Add an onclicklistener to call postmessage()
We use a Toast to show the error messages 1. Add two new constant strings for error messages if 1. there is no location available 2. there is no photograph taken yet 2. Add code to postmessage to test these conditions and Toast the error
Get a reference to the EditText object which holds the message
Collect the details of the message together
The application runs using a single thread A 'Looper' runs a Thread's message queue A 'Handler' is used to put messages on the queue and receive messages when they come off the head 1. Application starts 2. Create the message queue 3. Create a Handler for processing UI events (like touchscreen events) 4. Loop indefinitely taking an event off the queue and invoking handlemessage on the Handler which put it there 5. Whenever a UI event occurs (asynchronously) use sendmessage on the Handler to add an event to the queue
Applications have a single thread for the user interface Don't perform long running actions (such as uploading data to a server) in the user interface thread Watch out for concurrency problems when you add another thread For example: don't change anything in the user interface from a different thread Instead, add another Handler and use it to post events to the message queue and deal with them
Create our new Handler in the postmessage method 1. Add two more string constants for success or failure of message sending 2. Create two constants for our two message types 3. Create the Handler and override the handlemessage method 4. Use a toast to indicate what happened
Now use a new Thread to do the upload
Your basic application is complete The full version of the application uses a Service to notify you of new messages which are nearby Source code is on the website For bonus points see if you can add a ProgressDialog