Android for Ubiquitous Computing ResearchersThis tutorial uses Version 2.1 Platform Codename API...
Transcript of Android for Ubiquitous Computing ResearchersThis tutorial uses Version 2.1 Platform Codename API...
Android for Ubiquitous Computing Researchers
Andrew RiceUniversity 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 applicationsAvailable for free for Windows, Linux and Mac 1) target libraries for different android versions2) extra versions with Google API (like maps)3) emulator4) tools for building apks5) proguard for code obfuscation6) 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.66GHz, 1GB RAM
The emulator supports a wide range ofconfigurations
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 project2. Building the user interface3. Taking and storing a photo4. Collecting a GPS location5. Uploading message to the server
Create a newprojectFile -> New -> Other... -> Android project
Launch your project
Right-click on GeoTutorialRun As -> Android Application
GeoTutorial Overview
1. Creating the project2. Building the user interface3. Taking and storing a photo4. Collecting a GPS location5. Uploading message to the server
Now we will design the user interfaceDouble click on GeoTutorial -> res -> main.xml
Make sure that the 'Outline' and 'Properties' views are visibleYou 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 phone4. Click the Properties view5. Change the id to
@+id/takePhotoContainer6. Save your changes
The Android plugin automatically generates ID's to use in your code
Double click onGeoTutorial -> gen -> R.java
We entered an id of@+id/takePhotoButton
@ entry in R.java+ auto-generate itid/ the 'id' section
Set the size of the LinearLayout
1. Click back to main.xml2. Open the Misc Properties
section3. Set Layout height to
'150dp'4. Set Layout width to
'fill_parent'
The size of a View can be 'relative' or 'absolute'
Relative size Absolute size
fill_parent View will grow to fill as much space as is available
wrap_content View will shrink to be as small as possible for the content it contains
dp Size will be exactly this number of Density Independent Pixels (dp).
One dp is 0.15875 millimeters on 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 phone4. Popup dialog, choose
System resources5. Choose
ic_menu_camera6. Click OK7. 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 file1. Open GeoTutorial -> res
-> values -> strings.xml2. Click Add...3. In dialog, choose String4. 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 interface1. Drag the Button view from the Form Widgets palette2. Drop it on the phone screen under the text box3. Set it to fill the width of the screen4. 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 string7. Save your changes8. 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
● Complete list of qualifiers is here: http://developer.android.com/guide/topics/resources/providing-resources.html
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
GeoTutorial Overview
1. Creating the project2. Building the user interface3. Taking and storing a photo4. Collecting a GPS location5. Uploading message to the server
Android calls onCreate() first
1. Open GeoTutorialActivity.java2. The onCreate() method gets called when your app is starting3. The call to setContentView(...) finds the XML defining the
layout 'main' and creates the user interface from it
Now override the remaining life-cycle 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
override5. 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 tab4. Scroll to the bottom
of the log5. 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 IntentIntents are events passed to move between parts of an application and between applications
Explicit intent Implicit intent● say exactly which class
you wish to be invoked● the runtime locates it
(starts an application if needed)
● 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 within an application
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 data1. 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 container1. 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 project2. Building the user interface3. Taking and storing a photo4. Collecting a GPS location5. Uploading message to the server
We request location updates and wait for a callbackonCreate ● 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 method1. 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 file1. Open AndroidManifest.
xml2. Choose the
Permissions tab3. Click Add...4. Choose 'Uses
Permission'5. Click OK6. Choose
ACCESS_FINE_LOCATION7. 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 receive1. 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 project2. Building the user interface3. Taking and storing a photo4. Collecting a GPS location5. 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 application1. Select the three
library files2. Right-click and
choose Build path -> Add to Build path
Porting a library to Android is straight-forward
● 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 sendMessageButton3. Add an onClickListener to call postMessage()
We use a Toast to show the error messages1. Add two new constant strings for error messages if
1. there is no location available2. 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 starts2. Create the message queue3. 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 there5. 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 method1. 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