Android Assignmesnts

128
Assignment 1 Intro The goal of this lab is to learn the fundamentals of developing Android Applications, from project creation to installation on a physical device. More specifically you should gain the knowledge of how to use basic development tools to support the application development process, as well as the key components of an Android application itself. Objectives • Setup the Development Environment • Create a "Hello World" Android Application • Understand the various parts of an Android Project • Use the Android Emulator • Install and run the application on a physical device • Create a simple User Interface Activities 1. Setting Up the Development Environment 1.1 Download/Install the SDK For in-depth instructions, visit Android Installation Documentation. Otherwise perform the following steps.

Transcript of Android Assignmesnts

Page 1: Android Assignmesnts

 Assignment 1

Intro

The goal of this lab is to learn the fundamentals of developing Android

Applications, from project creation to installation on a physical device. More

specifically you should gain the knowledge of how to use basic development tools

to support the application development process, as well as the key components of

an Android application itself.

Objectives

• Setup the Development Environment

• Create a "Hello World" Android Application

• Understand the various parts of an Android Project

• Use the Android Emulator

• Install and run the application on a physical device

• Create a simple User Interface

Activities

1. Setting Up the Development Environment

1.1 Download/Install the SDK

For in-depth instructions, visit Android Installation Documentation. Otherwise perform the following

steps.

• Go to http://developer.android.com/sdk/index.html.

• Unpack to a convenient location - Remember the full path to this location,

we will refer to it as <android_sdk_dir> for the rest of the lab.

o For example, on Linux your home directory is a convenient location.

Page 2: Android Assignmesnts

o <android_sdk_dir> would then be /home/<username>/android_dir.

• Add the path to the <android_sdk_dir>/tools directory to your system PATH

o Linux:

1. Using your favorite text editor, open the .mycshrc file in your

home directory.

2. Add the following text to the end of the file:

set path=($path <android_sdk_dir>/tools)

3. Open up a terminal, navigate to your home directory and

execute the following command:

source .mycshrc

o Windows:

1. Right-click My Computer.

2. Click Properties.

3. Click Advanced tab.

4. Click Environment Variables button.

5. Double Click Path under System Variables.

6. Add ;<android_sdk_dir>/tools to the end of the Variable

Values text field.

• Test your installation by running adb from the command line. If you did

everything right, you should get a long list of help instructions.

1.2 Download/Install the Eclipse Plugin

• It is recommended that you use Eclipse 3.4 or later

o UNIX - Fedora Eclipse based on 3.4.2

Page 3: Android Assignmesnts

This version of Eclipse is missing a vital component and requires

adding an additional Eclipse plugin in order to use the Android

plugin:

1. Click the menu Help -> Software Updates.

2. Click the tab Available Software -> Add Site button.

3. Enter http://download.eclipse.org/releases/ganymede into

the Location field.

4. Click OK button.

5. Enter WST Common UI into the search/text box at the top of

the window (give it a second, it tries to search as you type

and its kind of slow).

6. Click the checkbox next to WST Common UI.

7. Click the Install button.

8. Click the Next button.

9. Accept the terms, click Finish.

10. Restart Eclipse.

11. Follow the steps in the next bullet 3.4 Ganymede.

o 3.4 Ganymede:

1. Click the menu Help -> Software Updates.

2. Click Available Software tab -> Add Site button.

3. Enter https://dl-ssl.google.com/android/eclipse/ into the

"Location" field.

4. Click OK button.

Page 4: Android Assignmesnts

5. Click the checkbox next to Developer Tools.

6. Click the Install button.

7. Click the Next button.

8. Accept the terms, click Finish.

9. Restart Eclipse.

o 3.5 Galileo:

1. Click Help -> Install New Software .

2. Click Add... button.

3. Enter a name for the site into the Name field.

4. Enter https://dl-ssl.google.com/android/eclipse/ into the

Location field.

5. Click OK button.

6. Click the checkbox next to Developer Tools.

7. Click the Next button.

8. Accept the terms, click Finish.

9. Restart Eclipse.

• Point Eclipse to <android_sdk_dir>:

1. Click the menu Window -> Preferences.

2. Click Android from the Hierarchy view on the left hand side.

3. Enter <android_sdk_dir> into the SDK Location field.

4. Click the Apply button.

5. Click the OK button.

1.3 Download/Install the SDK Platform Components

Page 5: Android Assignmesnts

At the time of writing this lab there are eight different versions of the Android

Platform available, ranging from 1.1 to 2.2. It is best practice to develop for the

oldest platform available that still provides the functionality you need. This way

you can be assured that your application will be supported by as many devices as

possible. However, you will still want to download newer versions of the platforms

so that you can test your applications against these as well. Due to the size of

each platform component you will only be required to download and develop on

one platform for the whole class. We will target the highest platform that the G1

phones support, Android 1.6 (API 4). Before we can begin developing we must

download and install this platform:

• Select the menu Window -> "Android SDK and AVD Manager", or click

on the black phone shaped icon in the toolbar.

• Select Available Packages on the left hand side.

• Expand the Google Android site in the "Site, Packages, and Archives"

Tree.

• Check the following items:

o SDK Plaform Android 1.6, API 4 Revision 3

o Google APIs by Google Inc., Android API 4, Revision 2

o NOTE: Those of you using linux should follow these

instructions: http://sites.google.com/site/androidhowto/how-to-1/set-up-the-sdk-onlab-

machines-linux.

• Click Install Selected.

• Accept the Terms for all packages and click Install Accepted.

Page 6: Android Assignmesnts

We're now ready to develop our application.

2. Create "Hello World" Application

2.1 Create a new Android Project

• Open Eclipse.

• Click the menu File -> New -> Project.

• Expand the Android folder and select Android Project.

• Name the project lab1<userID>

o For instance, if you userID is jsmith, you would name your

project lab1jsmith .

• You can change the location of where you would like to save the project by

un-selecting the "Default Location" check box, and supplying your own

location.

• Check "Android 1.6" from the Build Target List.

o This identifies that the project is being built to be compatible with

Android versions 1.6 and later.

o Its generally preferred that you choose the lowest build number

possible, so as to be compatible with the largest number of existing

systems in place.

o This build target can be changed any time later on through the

Project Properties menu.

• Fill in the Properties:

o Application Name = Hello World!

This is the friendly name of the application, that shows up on

Page 7: Android Assignmesnts

the device.

o Package Name = edu.itu.android.lab1<userID>

This is the namespace for the project, follows standard Java

conventions.

o Create Activity = HelloWorld

This optional field will automatically create a "Main Activity"

class for the project. You can think of the Main Activity as the

Home Page for your application.

o Min SDK Version = 4

This specifies the minimum API Level on which your

application can run. By default this is set to the API Level of

the Build Target Platform. As new API's are added to newer

Versions, their API levels increase as well. A Program that

uses an API Level of four won't be able to run on a platform

that has a lower API Level.

• Click "Finish".

3. Take a Tour of the Application

The application you've just created is very similar to other java applications you

may have created in Eclipse. Look in the Package Explorer side bar. Notice that

the Android Development Toolkit(ADT) has generated a number of folders and

files for you:

• src: If you expand this out you'll see the package hierarchy you previously

entered. This is where your source code files will go.

Page 8: Android Assignmesnts

o HelloWorld.java: This is the auto-generated stub Activity Class with

the name you entered into the project creation wizard. We'll add

some code to this later.

• Android 1.6: This is the version of the library you had chosen in the project

creation wizard. The application will be built using this version of

'android.jar'

• res: This folder will contain all of the resources (a.k.a. external data files)

that your application may need. There are three main types of resources

that you will be using and the ADT has created a subdirectory for each.

o drawable: This folder will hold image and animation files that you

can use in you application.

It already contains a file called icon.png which represents the

icon that Android will use for your application once it is

installed

o layout: This folder will hold xml layout files that the application can

use to construct user interfaces. You will learn more about this later,

but using a layout resource file is the preferred way to layout your

UI.

It already contains a file called main.xml which defines the

user interface for your 'HelloWorld.java' Activity class. Double

clicking on this file will open up the Android UI Editor that you

can use to help generate the xml layout files.

o values: This folder will hold files that contain value type resources,

Page 9: Android Assignmesnts

such as string and integer constants.

It already contains a file called strings.xml. Double clicking on

this file will open up the Android Resource Editor. Notice that

there are two strings in there already, one of which is named

'app_name'. If you select this value, on the right hand side of

the editor you should see the Application Name you entered

in the project creation wizard. You can use this editor to add

new resources to your application.

• gen: This folder will contain Java files that get auto-generated by ADT.

Notice that it already contains one file called "R.java".

o R.java: This is a special static class that is used for referencing the

data contained in your resource files. If you open this file you will

see a number of static inner classes for each of the resource types,

as well as static constant integers within them. Notice that the

names of the member variables are the same as the names of the

values in your resource files. Each value in a resource file is

associated with an integer ID, and that ID is stored in a member

variable of the same name, within a static class named after its data

type.

The 'app_name' resource value has an ID and is of value type

'string'. The ADT automatically adds an integer constant to

the R.string class and names it 'app_name'.

A debugging hint: Occasionally, an Android project will report

Page 10: Android Assignmesnts

errors in Eclipse that do not show up in any source code

file. Sometimes you can fix this by deleting R.java. When

you rebuild your project, R.java gets generated, and perhaps

your mysterious errors will disappear.

A second hint: I encourage you to turn on build automatically

in Eclipse (Project menu).

• assets: This folder is for asset files, which are quite similar to resources.

The main difference being that anything stored in the 'assets' folder has to

be accessed in the classic 'file' manipulation style. For instance, you would

have to use the AssetManager class to open the file, read in a stream of

bytes, and process the data. You will not be using assets quite as

extensively as you will be using resources.

• AndroidManifest.xml: Every project has a file with this exact name in the

root directory. It contains all the information about the application that

Android will need to run it:

o Package name used to identify the application.

o List of Activities, Services, Broadcast Recievers, and Content

Provider classes and all of their necessary information, including

permissions.

o System Permissions the application must define in order to make

use of various system resources, like GPS.

o Application defined permissions that other applications must have in

order to interact with this application.

Page 11: Android Assignmesnts

o Application profiling information.

o Libraries and API levels that the application will use.

• default.properties: Ths file contains all of the project settings, such as the

build target you chose in the project creation wizard. If you open the file,

you should see 'target=4', which is your build target. You should never edit

this file manually. If you wish to edit the project properties, do so by rightclicking

the project in the 'Package Explorer' panel, and selecting

'Properties'.

The project creation wizard has written the 'Hello World' application for you

already. A string resource containing the display text has been placed into the

res\values\strings.xml file. The value is named 'hello'.

The xml UI layout has been added to res\layout\main.xml. While you can use the

Android Layout Editor to create your xml layout, you can also code them manually

yourself. Lets take a look at this file:

• Right-Click on the file.

• Select Open With -> Text Editor.

Notice the Top Level node, Linear Layout, which defines the style of layout this

file will be using. This 'Linear Layout' is perhaps the most basic, and specifies that

UI elements will be laid out in a continuous line. It has three properties:

orientation, width, and height.

Notice the Second Level node, TextView, which defines a UI element for

displaying text. It has three properties: width, height, and the text to display.

Notice that the text property is not set to "Hello World!". Instead it is set to

Page 12: Android Assignmesnts

reference the resource value which contains the text we want to display. In this

case we are choosing to display the contents of the 'hello' value. We do this by

using the '@' symbol, followed by the value type of the resource (which is a

'string'), followed by the name of the value (which is 'hello').

4. Run "Hello World" on the Emulator

4.1 On the Emulator

Before we can run the application, we need to setup an Android Vitual

Device(AVD), or emulator, to run it on:

• Select the menu Window -> "Android SDK and AVD Manager", or click

on the black phone shaped icon in the toolbar.

• Select Virtual Devices on the left hand side.

• Click the New... button.

• Give your AVD a name.

• Select the target build that we would like to run the application on,

"Android 1.6 - API Level 4".

• Click Create AVD and close out the SDK/AVD Manager.

We're now ready to run our application.

• Select the menu Run -> Run.

o Note: The emulator may take a long time to start up.

o Note: Another way to run your application is to right-click on the

project in the Package Explorer, then select Run As -> Android

Application.

• You can interact with the emulator using the mouse just like you would with

Page 13: Android Assignmesnts

a device. To get started, press the Menu key to see the home screen.

Congratulations! You've just created and an Android Application.

4.2 On a Physical Device

Before we can run the application on a physical device we need to modify the

project, make a configuration change on the phone, and install some drivers for

the phone on our development machine. We begin by making your project declare

itself as debuggable. It's possible to do this through the Android Manifest Editor

that the ADT provides, however doing this manually helps you understand the

manifest better:

• Project Modifications

o From the Package Explorer, double-click the file

AndroidManifest.xml.

o Select the tab labeled AndroidManifest.xml along the bottom.

o Add android:debuggable="true" to the inside of the opening

<application> tag.

o Save the file and close it.

• Phone Modifications

o Turn the phone on.

o Navigate to the Home screen.

o Press MENU (the physical button on the device).

o Select Settings -> Applications -> Development.

o Enable the USB debugging option.

• Installing the Android USB drivers

Page 14: Android Assignmesnts

o Mac OS X: Don't need to install drivers, it should just work.

o Windows and Unix – Follow these instructions:

http://developer.android.com/guide/developing/device.html

Ensure the device is properly connected. Run the application as you would

normally. The "Hello World!" app should start on the phone.

5. Simple Activity Classes

There are four major types of component classes in any Android application:

• Activities: Much like a Form for a web page, activities display a user

interface for the purpose of performing a single task. An example of an

Activity class would be one which displays a Login Screen to the user.

• Services: These differ from Activities in that they have no user interface.

Services run in the background to perform some sort of task. An example

of a Service class would be one which fetches your email from a web

server.

• Broadcast Receivers: The sole purpose of components of this type is to

receive and react to broadcast announcements which are either initiated by

system code or other applications. If you've ever done any work with Java

Swing, you can think of these like Event Handlers. For example, a

broadcast announcement may be made to signal that a WiFi connection

has been established. A Broadcast Receiver for an email

application listening for that broadcast may then trigger a Service to fetch

your email.

• Content Providers: Components of this type function to provide data from

Page 15: Android Assignmesnts

their application to other applications. Components of this type would allow

an email application to use the phone's existing contact list application for

looking up and retrieving an email address.

In this lab, we will be focusing on what Activities are and how they are used. We

will cover the other components in later labs. If you would like more information

on these components, visit the Android overview page for Application

Components.

In case you haven't figured it out by now, you have already created one of these

component classes. That's right, the HelloWorld class is an Activity Class. It's a

simple user interface designed to greet the user. In the section that follows, we'll

make our application more personal by adding a new Activity class to ask for the

user's name. We'll then update the existing HelloWorld greeting Activity to display

that name.

Note: If you ever have problems getting things to compile in Eclipse, you might try

Project -> Clean. You can also try to delete R.java under res, then Project ->

Build Project.

5.1 Getting the User's Name

To get the user's name, you will be creating an Activity class which will allow the

user to enter their name into a text field and press a button when finished to

proceed to the HelloWorld greeting Activity. There are three separate steps to

accomplish here. You must first layout your user interface in XML. Then you must

create the Activity class to parse the input from the user and initiate the

HelloWorld Activity. Finally, you will have to reconfigure the application to use

Page 16: Android Assignmesnts

your new name retrieval Activity on startup.

5.1.1 Create the User Interface

Android allows you to layout your user interfaces using a simple XML

specification. We will go into more depth on this topic in the next lab, so for now

you will be setting up a basic interface using four different GUI elements. Begin by

creating a new Android XML file:

• Select the menu File -> New -> Android XML File.

If Android XML File does not appear in the menu:

o Select Other.

o Expand the Android folder.

o Select Android XML File and click Next.

• Ensure the Project matches the name of your project and that the folder

is /res/layout.

o Layout files should always go in this folder.

• Enter "name_getter.xml" as the file name

o The name of your layout files must only contain lower case letters,

the numbers 0-9, underscores '_', or periods '.'

o [a-z0-9_.]

• Select the Layout radio button.

• Select LinearLayout from the "Select the root element..." drop down and

click Finish.

• By default, the file will be opened to the Layout Editor tab. Select the tab

labeled name_getter.xml to switch to the XML Editor.

Page 17: Android Assignmesnts

o This should be located in the bottom left corner of the Layout Editor.

Each GUI element derives from the View base class. The first element was added

for you when you created the XML layout file and selected LinearLayout from the

dropdown menu. You should be able to see an XML opening and closing tag

labeled LinearLayout in the editor. Each XML layout file must have a single root

view tag, inside which all other view tags are nested. The LinearLayout tag tells

Android to arrange elements contained inside it in a straight line in the order in

which they appear. Let's make a few modifications to the LinearLayout by editing

the attributes contained in the opening LinearLayout tag:

• Set the attributes

labeled android:layout_width and android:layout_height to "fill_parent" (

Include the quotes).

o This tells Android that the LinearLayout should take up all the

available width and height on the screen.

• Add an attribute labeled android:orientation and set it to "vertical" .

o This tells Android that elements nested inside the LinearLayout

should be laid out in a column, as opposed to a single row as

indicated by "horizontal".

Lets add the other three UI elements to our XML layout file:

• Switch back to the Layout Editor tab.

o The three elements we will add all reside under the folder icon

labeled "Views"

o This can be seen along the left hand side of the previous figure,

Page 18: Android Assignmesnts

about halfway down

• Scroll down to the item labeled TextView.

o Click and drag the TextView onto the black canvas.

o The Layout Editor will pre-populate the label with its auto-generated id, which may

look somewhat strange.

• Repeat the previous step for the EditText and Button labels.

Assignment 2

Intro

In this lab we will be learning how to use and extend the Android user

interface library. In a number of ways it is very similar to the Java Swing

library, and in perhaps just as many ways it is different. While being familiar

with Swing may help in some situations, it is not necessary. It is important to

note that this lab is meant to be done in order, from start to finish. Each

activity builds on the previous one, so skipping over earlier activities in the

lab may cause you to miss an important lesson that you should be using in

later activities.

Objectives

At the end of this lab you will be expected to know:

• What Views, View Groups, Layouts, and Widgets are and how they relate to each

other.

• How to declare layouts dynamically at runtime.

• How to reference resources in code and from other resource layout files.

Page 19: Android Assignmesnts

• How to use Events and Event Listeners.

Activities

For this lab we will be creating a "Joke List" application. It is a simple app

that allows a user to view and edit a list of jokes. All tasks for this lab will be

based off of this application. Over the course of the lab you will be iteratively

refining and adding functionality to the Joke List app. With each iteration you

will be either improving upon the previous iteration's functionality, or you will

be implementing the same functionality in a different way.

IMPORTANT:

You will be given a Skeleton Project to work with. This project contains all of

the java and resource files you will need to complete the lab. Some method

stubs, member variables, and resource values and ids have been added as

well. It is important that you not change the names of these methods,

variables, and resource values and ids. These are given to you because there

are unit tests included in this project as well that depend on these items

being declared exactly as they are.

1. Setting Up...

1.1 Creating the Project

To begin, you will need to download and extract the skeleton project for the

JokeList application.

• Download the skeleton project that is included with this lab description.

• Extract the project, making sure to preserve the folder structure.

o Take note of the path to the root folder of the skeleton project.

Page 20: Android Assignmesnts

o You may prefer to extract it to your Eclipse workspace directory.

Next you will need to setup a "Joke List" Android project for this app. Since

the skeleton project was created in Eclipse, the easiest thing is to import this

project into Eclipse.

• Select File -> Import.

• In the Import Wizard, expand General and select Existing Projects

into Workspace. Click Next.

• In the Import Project wizard, click select root directory and click

Browse. Select the root directory of the skeleton project that you

extracted. Click Open and then Finish.

• Click on the project name in the Package Explorer. Select File ->

Rename and change the name of your project to lab2<userid> where

<userid> is your user id (e.g. jsmith).

1.2 Fill in the Joke Class

Throughout the lab you will be working with the Joke object class. This class

will be used to encapsulate two items pertaining to jokes.

1. m_strJoke: This represents the actual text of the joke.

2. m_nRating: This represents a rating that can be assigned to a joke.

There are three possible values that the rating can take:

o UNRATED: indicates no rating has been assigned to this joke by

the user.

o LIKE: indicates the user liked this joke.

o DISLIKE: indicates the user did not like this joke.

Page 21: Android Assignmesnts

Begin by filling in this class:

• Open the Joke.java file

o Under the src/ folder in the edu.calpoly.android.lab2 package.

• Fill in all methods marked //TODO.

o Read the comments if you are confused as to the purpose of any

of the methods.

• Run the JokeTest.java Unit Tests to ensure that you have properly filled

in this class.

o Locate the JokeTest.java file under the test/ folder in the

edu.calpoly.android.lab2 package.

o Right click the file, select Run as -> Android JUnit Test.

o This should open up a JUnit Tab and if you see the Green bar,

you've passed all the tests and you can continue on to the next

section:

o If you see a red bar, this means that you've failed one or more

tests. The tab should show how many tests failed, and which

tests you failed (circled in yellow):

o Feel free to open up the JokeTest.java file to look at what

exactly is being tested. Make the appropriate corrections and

rerun the tests until you've passed all the tests.

o There are additional tests in the SimpleJokeListTest.java file, but

don't run those until later (see section 3.2.3).

1.3 Retrieving the Joke Resources Strings

Page 22: Android Assignmesnts

The skeleton project has been pre-populated with an array of three different

String resources you can use as sample jokes. For a complete background on

Resources and how to properly use them you can see the Android Developer

Guide on Resources. For an overview:

• Open up res/values/strings.xml in the XML editor to view the joke

resources.

o Notice the <string-array name="jokeList"> element.

o This is how you declare an array of strings.

o Notice the name attribute.

When you add an element to a resource file, the Android

Development Toolkit will automatically add a static constant

with this variable name to the R.java file.

You can then use this constant as an identifier for retrieving

the resource element through a Resource Object.

• Open up the R.java file under the gen/ folder in the

edu.calpoly.android.lab2 package.

o Notice that R is a static class with a static subclass for each type

of resource element.

o If you add a string resource element and give it a

name attribute, a static constant with this name gets added to

the R.string class. Arrays get added to the R.array class,

drawables get added to the R.drawable class, etc.

The constant has the same name as the name

Page 23: Android Assignmesnts

attribute. Layouts are slightly different in that you don't

have to specify a name attribute; the name of the constant

will be the name of the XML layout file.

The constant contains the resource id that you can use to

retrieve the resource.

You need to display these jokes when the application starts up. When an

Activity first starts up, its "public void onCreate(Bundle

savedInstance)" method is always called. This method allows you to

initialize the Activity. Right now you will only be initializing local variables to

hold the jokes that you just entered:

• Open SimpleJokeList.java.

• In the public void onCreate(Bundle savedInstance) method:

o Notice the super.onCreate(savedInstance) call. This is crucial,

never forget to make this call. If you don't your Activity won't

work.

o Make a call to this.getResources() , which will return a Resources

object.

The Resources class provides an interface for retrieving

resources by their resourceID.

resourceID's can be found in the static R class, under

their respective resource subclasses (which are named after

their resource type), under the name given to them in the

resource file:

Page 24: Android Assignmesnts

R.array.jokeList

o Create an instance of the Joke ArrayList.

o Retrieve the array of joke strings by

calling getStringArray(R.array.jokeList) on the resource object.

o For each of these strings make a call to addJoke(...), which

will initialize Joke objects and place them in m_arrJokeList.

• Fill in the addJoke(...) method.

When creating a new Activity you will almost always override the onCreate

method. The onCreate method, as you will see later, is the place where you

will be creating your User Interfaces, binding data to different UI controls,

and starting helper threads (this will not be covered in this lab). Also, take

note of the "Bundle savedInstance" parameter that gets passed in. This

variable contains information on the previous state of the UI. As you may

have assumed, this means that you are able to save the state of the UI

before it closes so that it can be initialized to the same state the next time it

is created.

2. Brief Backgound on View Classes

In Android, a user interface is a hierarchy composed of different View objects.

The View class serves as the base class for all graphical elements, of which

there are two main types:

• Widgets: Can either be individual, or groups of UI elements. These are

things like buttons, text fields, and labels. Widgets directly extend the

View class.

Page 25: Android Assignmesnts

• Layouts: Provide a means of arranging UI elements on the screen.

These are things like a table layout or a linear layout. Layouts extend

the ViewGroup class, which in turn extends the View class.

Layouts are all subclasses of the ViewGroup class and their main purpose is

to control the position of all the child views they contain. Layouts can be

nested within other layouts as well, to create complex user interfaces. Some

of the common layout objects you will use are:

• FrameLayout: Takes a single view object and simply pins it to the

upper left hand corner of the screen. Each child view that is added is

drawn on top of the previous one, causing it to be completely or

partially obscured.

• LinearLayout: Has a list of child views and draws them sequentially in

a single direction, either horizontally or vertically. You have the option

of assigning a weight value for each child view which determines how

much it is allowed to grow if there is extra space.

• TableLayout: Positions it's child views in a grid of rows and columns. A

row is a child view specified by the TableRow class. TableRows can have

zero or more cells and can contain empty cells. However, a cell cannot

span multiple columns. Each cell is itself another view, like a Button,

and can be set to shrink or grow.

• RelativeLayout: Positions it's child views relative to other child views

or the parent view. For example, two child views can be left-justified in

the parent, or one child view can be made to be below another.

Page 26: Android Assignmesnts

• AbsoluteLayout: Has an absolute coordinate position for each child

view. This is a rigid layout that pins all child views down exactly where

they are specified. Using this does not allow the user interface to adjust

for different screen sizes and resolutions.

• See Common Layout Objects for more information...

Declaring the layouts for your user interface can be done dynamically (in

code), statically (via an XML resource file), or any combination of the two. In

the following subsection you will build a set of user interfaces in code. In a

future lab, you will build a set of user interfaces in XML.

3. SimpleJokeList

Work done in this section will be limited to the SimpleJokeList.java file.

SimpleJokeList is an Activity class which displays a vertical scrollable list of all

the Jokes in m_arrJokeList. Additionally, it has the ability to add jokes

to m_arrJokeList via a text field and add a button that floats at the top of

the screen.

3.1 Declaring Dynamic Layouts in Code

If you've ever built UIs in Java using Swing, this should be somewhat

familiar. You generally want to try to define the layouts for your interface

using XML when possible, but there are plenty of instances where it is still

necessary to do it at run-time in code. For instance, you may want to

dynamically change the layout based on some type of user input. Never the

less, working with the actual code is good practice for understanding how the

different Layout classes work and what sorts of interfaces all the various

Page 27: Android Assignmesnts

controls offer.

3.1.1 Display a Scrollable Vertical List

Your first Task is to simply display each of the jokes in

the strings.xml resource file in a scrollable vertical list. When finished

your application should look something like this:

• Fill in the initLayout() method in SimpleJokeList.java:

o Initialize the m_vwJokeLayout LinearLayout member

variable.

When constructing View objects, you generally have to

pass a Context object into the constructor. A Context

object provides the functionality for accessing

resources (like our jokeList), databases, and

preferences. The Activity class inherits from Context

which is how we were able to retrieve our jokeList by

calling this.getResources().

o The LinearLayout class displays its child views horizontally by

default. Make sure to change this to vertical using

the setOrientation() method, passing in

the LinearLayout.VERTICAL constant.

LinearLayout: [Docs]

o Create a local ScrollView object.

A ScrollView is merely a FrameLayout that becomes

scrollable when its child views are larger than the

Page 28: Android Assignmesnts

screen area.

It generally has a single child view, which in our case

will be another layout manager

o Add the LinearLayout to the ScrollView by calling

its addView(...) method.

o Make a call setContentView(...), passing in your ScrollView.

setContentView provides the content which the Activity

is supposed to display. Our UI is a hierarchical

structure of nested components. We want to pass in

the top-level, or root, element to this method. In our

case this is the ScrollView.

• Make a call to initLayout() in your onCreate(...) method and

place it above your retrieval and initialization of the jokes in

the strings.xml resource file.

• Update the addJoke(...) method.

o Add the joke text to a new TextView object by calling

its setText(...) method.

A TextView is used for displaying text on the screen.

o Add the TextView to m_vwJokeLayout.

• Your AndroidManifest.xml is currently setup so that

SimpleJokeList Activity will launch on startup. Create a Run

Configuration to specifically launch the SimpleJokeListActivity:

o Select Run -> Run Configurations from the menu.

Page 29: Android Assignmesnts

o Select the Android Application item from the list.

o Click the New Launch Configuration icon

o Give the configuration a name and the name of your android

project.

o Select the Launch radio button and select the

SimpleJokeList activity from the dropdown list. (Click on

the image for a larger view)

• Now run your application to verify that your list of jokes shows up.

• The text is a little small, so use setTextSize(...) to increase the

size of all jokes to 16 font.

• It's somewhat hard to distinguish where one joke ends and

another begins, so let's alternate the background colors of each

joke. We'll store the color values as resources:

o Create a new XML Resource file under /res/values like you

did in Lab 1 and call it colors.xml

Hint: File->New->Android XML File

o You can use either the Resource Editor or you can directly

add the following XML to the file:

<color name="dark">#3D3D3D</color>

<color name="light">#1F1F1F</color>

If adding the XML yourself, make sure to nest the color

tags inside the <resource> tags.

o Modify the background color of the TextViews by

Page 30: Android Assignmesnts

calling setBackgroundColor as you create them in your

addJoke(...) method.

Alternate between setting the background color

to dark and light.

Hint: Retrieve the colors in the same way you retrieved

the joke strings.

3.1.2 Adding Your Own Jokes

In this next task we will give the user the ability to enter their own jokes

by adding a text field and a button to the UI. The text field and button

should float at the top of the screen, above the list of jokes. When you

scroll through the jokes, the text field and button should not scroll, but

remain at the top of the screen.

In order to accomplish this we will walk through a process of nesting

LinearLayouts within each other to achieve the desired effect. However,

feel free to experiment and use whatever type of ViewGroup Layout you

want, so long as the functionality and appearance remains the same. In

the figure shown below, you can see how a root vertically-oriented-

LinearLayout containing a horizontally-oriented-LinearLayout and the

ScrollView of jokes can be combined to achieve the effect we want.

In this step you will only be updating your Layout. The new "Add Joke"

button and text field won't work yet. You will add code to hook-up those

controls in section 3.2 Simple Event Listeners.

• All of the work here, will be done in the initLayout() method.

Page 31: Android Assignmesnts

Additionally, all but a few lines of that code should be written

above the code you wrote in 3.1.1.

• Declare a local vertically-oriented LinearLayout object, this will be

your root ViewGroup (displayed in green in the figure above).

• Declare a local horizontally-oriented LinearLayout object, this will

be the ViewGroup containing the "Add Joke" button and text field.

o Initialize your m_vwJokeButton member variable, setting

its text to "Add Joke".

o Add the Button to the horizontal LinearLayout.

o Initialize your m_vwJokeEditText member variable.

o call m_vwJokeEditText.setLayoutParams(...), passing in

an appropriately initialized LinearLayout.LayoutParams

object so that the EditText will take up all of the extra

available width and height.

o For more information see the Android Developer Guide and

Documentation on:

Layout Parameters

How Android Draws Views

LinearLayout.LayoutParams

o Add the EditText to the horizontal LinearLayout.

• Add your horizontal LinearLayout to your root ViewGroup.

• After your declaration and initialization of your ScrollView

ViewGroup, add the ScrollView to your root ViewGroup.

Page 32: Android Assignmesnts

• Change your call to setContentView(...) to pass in your new root

ViewGroup.

• Run your application to test that you have properly setup your

layout.

3.2 Simple UI Event Listeners

Now that your UI has the components necessary to allow users to enter new

jokes, you need to hook these components up. In this section you will define

and register event listeners to handle adding new jokes.

Read the Android Developers Guide on Handling UI Events to get a detailed

background on event handlers and listeners. In short, you use event listeners

to respond to user interaction with your UI. There are two general steps for

doing this. The first is to define an object that implements an interface for the

type of interaction you want to respond. The second step is to register that

object with the UI control you want to respond to. For example, to react to a

particular Button being clicked, you have to register an object that

implements the OnClickListener interface with the Button you want to listen

to.

3.2.1 Adding a Button Listener

Setup the onClickListener for the "Add Joke" Button. When the user

hits the "Add Joke" Button a new Joke object should be initialized with

the text from the EditText field and added to your joke list. If the

EditText is empty, then the Button should do

nothing. In initAddJokeListeners():

Page 33: Android Assignmesnts

• Call setOnClickListener method for you

m_vwJokeButton member variable. Pass in a reference to what's

called an Anonymous Inner Class that implements the

OnClickListener interface.

o If you are unfamiliar with anonymous inner classes that's

alright. Essentially, its an inline way of creating a one-timeuse

class that implements some interface. You declare the

class and instantiate it in one motion. You can read more

about them from Sun's Java Tutorials on Anonymous Inner

Classes.

o Copy the following code:

m_vwJokeButton.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View view) {

//Implement code to add a new joke here...

}

});

o Fill in the onClick method in the anonymous inner class that

you created to add a new joke to the list.

Retrieve the text entered by the user into the EditText

by calling getText().toString() (Check for empty

strings here).

Clear the EditText.

Page 34: Android Assignmesnts

Call your addJoke method

Add the following two lines of code to hide the Soft

Keyboard that appears when the EditText has focus:

o InputMethodManager imm = (InputMethodManager)

getSystemService(Context.INPUT_METHOD_SERVICE);

imm.hideSoftInputFromWindow(m_vwJokeEditText.getWindowToken(),

0);

o Call initAddJokeListeners from onCreate.

• Run your application to ensure that the "Add Joke" Button

functions properly now. (Click on the image for a larger view)

• In this situation you had two options for where you could

implement the code to handle the "Add Joke" button's onClick

event. Each has its drawbacks:

o Use an Anonymous Inner Class:

This option is a little cleaner and more readable since

the event handling logic for different elements is self

contained and referenced where it is used.

Since this event listener is only being used for one UI

control, you are free to make certain assumptions

when implementing it. For instance, you know exactly

which View generated the event.

However, this will consume more resources because

this instantiates a new object, and class information

Page 35: Android Assignmesnts

for the object will need to be stored as well.

o Make SimpleJokeList implement the OnClickListener

interface:

In this option you would be able to register

SimpleJokeList to respond to Click events from many

different UI Controls. However, you would have to add

conditional logic for determining which view fired the

onClick event.

This has a clear performance benefit in that you don't

have to load extra classes, which reduces your

memory footprint and load time.

This is actually very common in Android applications

due to the need to design for performance imposed by

Assignment 3

Intro

This lab will be a continuation of Lab 2. You will expand on your knowledge of

the Android user interface library. It is important to note that this lab is meant

to be done in order, from start to finish. Each activity builds on the previous one,

so skipping over earlier activities in the lab may cause you to miss an important

lesson that you should be using in later activities.

Objectives

At the end of this lab you will be expected to know:

Page 36: Android Assignmesnts

• How to declare layouts statically as an xml resource.

• How to create custom Views from scratch to suit a specific need.

• How to create Options and Context Menus.

• How to use Adapters and AdapterViews to bind a View class to data.

• How to establish Http connections.

• How to create Toast Notifications.

Activities

For this lab we will be extending the "Joke List" application that you created in

Lab2. This version of the app will be more advanced. It will allow the user to

give ratings to Jokes, delete Jokes, upload Jokes to a server, and download

Jokes from a server. All tasks for this lab will be based off of this

application. Over the course of the lab you will be iteratively refining and adding

functionality to the Joke List app. With each iteration you will be either

improving upon the previous iteration's functionality, or you will be

implementing the same functionality in a different way.

IMPORTANT:

You will be given a Skeleton Project to work with. This project contains all of the

java and resource files you will need to complete the lab. Some method stubs,

member variables, and resource values and ids have been added as well. It is

important that you not change the names of these methods, variables, and

resource values and ids. These are given to you because there are unit tests

included in this project as well that depend on these items being declared

exactly as they are. You have complete access to these test cases during

Page 37: Android Assignmesnts

development, which gives you the ability to run these tests yourself. In fact, you

are encouraged to run these tests to ensure that your application is functioning

properly.

1. Setting Up...

1.1 Creating the Project

To begin, you will need to download and extract the skeleton project for the

JokeList application.

• Download the skeleton project and is included with this lab description.

• Extract the project, making sure to preserve the folder structure.

o Take note of the path to the root folder of the skeleton project.

o You may prefer to extract it to your Eclipse workspace directory.

Next you will need to setup a "Joke List" Android project for this app. Since the

skeleton project was created in Eclipse, the easiest thing is to import this project

into Eclipse.

• Select File -> Import.

• In the Import Wizard, expand General and select Existing Projects into

Workspace. Click Next.

• In the Import Project wizard, click select root directory and

click Browse. Select the root directory of the skeleton project that you

extracted. Click Open and then Finish.

• Click on the project name in the Package Explorer. Select File ->

Rename and change the name of your project to lab3<userid> where

<userid> is your user id (e.g. jsmith).

Page 38: Android Assignmesnts

1.2 Fill in the Joke Class

You may fill in the Joke Class using the functionality that you implemented for

this class in Lab2. However, there is one key difference. A

member variable named m_strAuthorName has been added to the class which

will contain the name of the Joke's Author. In particular:

• You must update the constructors. You are required to pass in an Author

name for all the Constructors except for the default constructor.

• The equals(...) method now requires that the names of the Authors of the

two Jokes being compared must match as well, in addition to their text.

• There is a getter and setter that needs to be filled in.

Run the JokeTest.java Unit Tests to ensure that you have properly filled in this

class.

1.3 Use SimpleJokeList as a Starting Point

You may fill in the AdvancedJokeList class using some of the code that you

implemented for SimpleJokelist in Lab2:

• Fill in the addJoke(...) method using the code

from SimpleJokeList.addJoke(...).

o Note that the signature on the method has changed to accept a Joke

object instead of a string. You will have to modify

the SimpleJokeList.addJoke(...) code to use this new interface.

• Fill in the initAddJokeListeners(...) method using the code

from SimpleJokeList.initAddJokeListeners(...).

o Remember that the signature on the addJoke(...) method has

Page 39: Android Assignmesnts

changed to accept a Joke object instead of a string. You will have to

modify some of the code here to use this new interface.

• Fill in the onCreate(...) method using the code

from SimpleJokeList.onCreate(...).

o Remember that the signature on the addJoke(...) method has

changed to accept a Joke object instead of a string. You will have to

modify some of the code here to use this new interface.

• Fill in the initLayout(...) method using the code from

SimpleJokeList.initLayout(...).

• Run the AdvancedJokeListAcceptanceTest.java Tests to ensure that you

have properly filled in this class. Note that other classes test classes are

also provided, but these tests should fail at this point. They will be used

later in other sections.

• Run your application to ensure that it performs the way it did in Lab2.

2 Declaring Static Layouts in XML

Read the Android Developer Guide on Declaring Layout for complete background

on declaring layouts. Declaring your user interface in XML is the preferred

method of implementation. By declaring your UI in an XML resource file it gives

you better separation between the presentation layer of your application and the

code controlling things underneath. One benefit of this is that modifications to

your UI can be made without having to change any source code or recompile.

This allows you to define different views for different screen sizes, resolutions,

and scenarios while using the same code to control everything.

Page 40: Android Assignmesnts

2.1 Porting Your Dynamic Layout Into Static XML

In order to get some practice with setting up layouts in XML, you will begin by

converting the layout you setup dynamically in SimpleJokeList to an XML layout

file. You will then inflate this layout in AdvancedJokeList and set it as your

ContentView.

• Fill in the /res/layout/advanced.xml layout file:

o Make your advanced.xml layout file produce the exact same UI as

the one you declared dynamically in SimpleJokeList.

o advanced.xml has been stubbed out for you already. It contains a

FrameLayout as the root ViewGroup to prevent compilation errors,

you will need to replace this with an appropriate root ViewGroup

element.

o IMPORTANT: You must use the following resource id's for each of

the UI Components listed. These UI Components are defined as

member variables in AdvancedJokeList.java the same way they were

defined in SimpleJokeList.java:

EditText m_vwJokeEditText: use "newJokeEditText" as the

resource id

Button m_vwJokeButton: use "addJokeButton" as the resource

id

LinearLayout m_vwJokeLayout: use "jokeListViewGroup" as

the resource id

• Edit your initLayout() method to use the advanced.xml layout file:

Page 41: Android Assignmesnts

o Remove all the code from this method. It should be an empty

method when you start.

o You must make your call to setContentView be the first thing that

you do.

o Instead of passing in a view, pass in the Layout Resource Id

for advanced.xml.

Hint: You did this in Lab1, you can find it in the Static R class.

You won't be able to retrieve references to your UI Controls

until the layout has been inflated from the XML file.

o Initialize your view class member variables by retrieving references

to them, instead of constructing new ones:

m_vwJokeLayout

m_vwJokeEditText

m_vwJokeButton

Hint: You did this in Lab1, remember

the findViewById method?

• Try running your AdvancedJokeListTest.java Unit Tests again. They should

still pass.

• Try running your application. The UI should appear and function exactly as

it did for SimpleJokeList.

2.2 Building Custom UI Components

Sometimes the standard View library will not supply the functionality that you

need. In situations like this it is completely acceptable to define your own UI

Page 42: Android Assignmesnts

Components. There are three general approaches to creating custom UI

components:

1. Creating a custom component from scratch.

2. Modifying an existing component to serve your needs.

3. Combining existing components to create a compound component.

In this section you will be using the third approach to develop a custom

component. You will combine a number of different existing View classes to

create a coherent Widget for displaying Jokes. For a complete background on

this approach, as well as the other two approaches, read the Android Developer

Guide on Compound Controls.

The custom component that you are going to implement will have two states, an

expanded and a collapsed state. It will look something like this:

In the collapsed state there is an expand/collapse Button that displays a "+" and

a joke TextView displaying the first two lines of the joke. If the joke is longer

than two lines, it will only display two lines and append to the displayed text an

ellipsis.

In the expanded state there exist the exact same components that existed in the

collapsed state. Additionally, there will exist a RadioGroup containing two

RadioButtons, that will appear horizontally centered underneath the

expand/collapse Button and joke EditText. In the expanded state, the

expand/collapse Button will display a "-" and the joke EditText will no longer

display an ellipsis, but rather display the entire text of the joke (no matter how

long it is). The expand/collapse button should remain anchored to the top left

Page 43: Android Assignmesnts

corner; it should not be centered vertically.

2.2.1 Declare a Custom JokeView XML Layout

The first step is to create the XML layout file that the custom component will use. You have

to implement this custom component using a single XML layout file. Switching between the

collapsed and expanded states is only a matter of hiding the RadioGroup, changing the

Button text, and changing settings on the TextView.

• Fill in the res/layouts/joke_view.xml layout file:

o When writing the layout, write the file as though you were

writing it for the expanded state. Don't worry about the

collapsed state until the next section.

o jokeview.xml has been stubbed out for you already. It

contains a FrameLayout as the root ViewGroup to prevent

compilation errors. You will need to replace this with an

appropriate root ViewGroup element.

o IMPORTANT: You must use the following id's for this list of UI

Components defined in AdvancedJokeList.java

Button m_vwExpandButton: use "expandButton" as the

resource id

RadioButton m_vwLikeButton: use "likeButton" as the

resource id

RadioButton m_vwDislikeButton: use "dislikeButton" as

the resource id

Page 44: Android Assignmesnts

RadioGroup m_vwLikeGroup: use "ratingRadioGroup" as

the resource id

TextView m_vwJokeText: use "jokeTextView" as the

resource id

• Hints:

o You can test your UI without having to run your application by

switching back and forth between the LayoutEditor and the XML

Editor.

Make changes in the XML Editor.

The LayoutEditor will render your UI.

Test your layout by setting the text of your TextView in

the XML Editor to a really long string.

o If TextView keeps cutting the bottom off of really long text, try

adding padding to the top and bottom.

See the Android Documentation on

the paddingTop/paddingBottom XML attributes.

o Experiment with Relative Layout as your root ViewGroup, you

can then nest LinearLayouts as you see fit.

o Empty LinearLayouts can also be used as spacers between

components to help center things or provide adequate spacing.

See the Android Developer Guide on LinearLayout for a

discussion of weight.

Look into the layout_weight XML attribute in the Android

Page 45: Android Assignmesnts

Documentation

2.2.2 Create a Custom JokeView Widget

The next step is to implement your custom component class. This class will be the

JokeView class. It is your task to fill in JokeView.java that has been stubbed out for you. In

general when creating a compound component, after you have established your layout,

you want your component class to extend the class of the root ViewGroup in your layout.

Your component class then becomes a special subclass of that ViewGroup.

Open up JokeView.java:

• Make the JokeView class extend the root ViewGroup of your layout.

o It currently extends the View base class, you will have to

change this to whatever class your root ViewGroup is.

• Fill in the JokeView(Context context, Joke joke) constructor:

o Inflate joke_view.xml:

This will be done differently than the way you've been

doing it. In this particular context, after the layout is

inflated, we want this JokeView object to be the root

ViewGroup of the inflated layout.

Copy the following code:

LayoutInflater inflater

= (LayoutInflater)context.getSystemService(

Context.LAYOUT_INFLATER_SERVICE);

inflater.inflate(R.layout.joke_view, this, true);

Page 46: Android Assignmesnts

Instead of returning an inflated hierarchy of Views, this

JokeView object will become the root of that hierarchy.

o Initialize all the View component member variables by

retrieving references to them as you would normally do for a

layout declared in XML:

m_vwLikeButton

m_vwDislikeButton

m_vwLikeGroup

m_vwJokeText

m_vwExpandButton

• Fill in the setJoke(...) method:

o Update your m_joke reference with the joke was passed.

o Update m_vwJokeText with the text for the new joke.

o Set the checked state to true on the appropriate RadioButton to

reflect the rating for the new joke. If the joke is unrated then

neither RadioButton should be checked.

Hint: You can use the RadioGroup to clear the checked

state of all RadioButtons in the group.

o Make sure to call setJoke(...) from the constructor.

• Fill in the collapseJokeView() method:

o Set the m_vwJokeText to ellipsize the text of the joke. If the

joke is too long to fit in the TextView, the text should be

truncated to fit, and an ellipsis should be appended to the end

Page 47: Android Assignmesnts

of the joke.

Hint: There is a single method call to handle this. See the

Android Documentation on TextView.

o Set the text on m_vwExpandButton to display

the JokeView.EXPAND string constant.

o Set the visibility on m_vwLikeGroup so that it disappears, and

does not take up any space in the layout.

Read the the documention on Using Views, specifically the

part about setting visibility, and the View.setVisisbility(...)

method.

o Make a call to requestLayout().

By ellipsizing the joke TextView and making the rating

RadioGroup disappear we have changed the size of the

JokeView. This has caused the JokeView to

become invalidated. Whenever a view becomes

invalidated it should request to be laid out again.

Failing to make this call will result in the view not being

updated properly.

o Make sure to call collapseJokeView() from the constructor.

• Fill in the expandJokeView() method so that it performs the inverse

functionality of collapseView().

• Setup the m_vwExpandButton to respond to OnClick events:

o Make the JokeView class implement the OnClickListener

Page 48: Android Assignmesnts

interface.

fill in the onClick(...) method so that if the JokeView is in

its Expanded state, it calls collapseJokeView(). If the

JokeView is in its CollapsedState, it calls

expandJokeView().

In the constructor, set the OnClickListener

for m_vwExpandButton to this JokeView object.

• Setup the m_vwLikeGroup to respond to OnCheckedChange events:

o Make the JokeView class implement the

RadioGroup.OnCheckedChangeListener interface.

You can read the details for this interface method in the

Android Documentation

for RadioGroup.OnCheckedChangeListener.

Fill in the onCheckedChanged(...) method so that when

the state of the rating changes in the UI, the internal

state of the joke is updated to properly reflect this change

as well.

o In the constructor, set the OnCheckedChangeListener

for m_vwLikeGroup to this JokeView object.

2.2.3 Make AdvancedJokeList use the JokeView class

The last step is to update AdvancedJokeList to make use of your new JokeView custom

component.

• Edit the AdvancedJokeList.addJoke(...):

Page 49: Android Assignmesnts

o Remove the code that initializes and adds a new TextView

to m_vwJokeLayout.

o Add code to initialize and add a new JokeView to m_vwJokeLayout.

• Run your Application to ensure that your changes to AdvancedJokeList and your

new JokeView custom component are functioning properly.

o Your application should load with all of the jokes in the collapsed state.

o Test that your jokes expand properly by clicking one of the expand Buttons:

3. Adapters & AdapterViews

The purpose of this next section is to introduce you to the concept of

AdapterViews. An AdapterView is a View class that allows us to bind it to a

dataset. This binding then takes care of responding to user selections as well as

populating the AdapterView with data. The binding is performed by a third

intermediate class, called an Adapter. It is the Adapter that is responsible for

keeping track of the selection and supplying the AdapterView with a View object

representation of each item in the dataset. Read the Android Developer Guide

on Binding to Data with AdapterViews for a complete background on the topic.

In the context of this section, the AdapterView is a scrollable vertical ViewGroup

called a ListView. The dataset is then our ArrayList of Joke objects. The Adapter

class is the JokeListAdapter, which follows the standard Object Adapter Design

Pattern; read the wiki on Object Adapter for more information. JokeListAdapter

contains a reference to our list of Joke objects and supplies ListView with a

JokeView for each them.

3.1 Implement JokeListAdapter.java

Page 50: Android Assignmesnts

Begin by filling in the constructor and the stubbed getSelection() method:

• Set m_context and m_jokelist appropriately.

• Selection should be initialized to the Adapter.NO_SELECTION static

constant.

• NOTE: The selection functionality won't be used until later on when you

add the ability to "Remove" a joke.

Make the JokeListAdapter class extend the BaseAdapter class. Check the Android

Documentation on BaseAdapter for details. You will have to add and implement

the following abstract methods:

• public int getCount()

o Returns the number of items in the dataset (m_jokeList).

• public Object getItem(int position)

o Returns the Joke object from the dataset at the specified position.

• public long getItemId(int position)

o If a Joke had a unique Id this would return it. However, you can use

the Joke's position as its unique Id.

• public View getView(int position, View convertView, ViewGroup

parent)

o This method returns a JokeView object for the Joke object at the

position in the dataset specified by position.

o The convertView object allows you to re-use a previously

constructed view for better performance. Since convertView is a

View object that was previously returned

Page 51: Android Assignmesnts

by JokeListAdapter.getView(...), then you can safely assume it is

JokeView.

Check to see if this value is null.

If it is null, then create a new JokeView object for the Joke

at position.

If it is not null, then change this JokeView to use the Joke

at position.

o The parent parameter represents the container the returned

JokeView will get added to. You won't need to use this, but in some

cases it can provide useful information.

3.2 Make AdvancedJokeList Activity Use ListView

You will now make the AdvancedJokeList Activity class use the ListView and the

JokeListAdapter classes to maintain your list of Jokes. You can read the Android

Documentation on ListView for details on the class.

• Update advanced.xml to use a ListView instead of a vertically oriented

LinearLayout nested inside a ScrollView. The ListView will replace both the

ScrollView and the LinearLayout.

o IMPORTANT: You must set the id attribute for the ListView element

to be "jokeListViewGroup".

• Update AdvancedJokeList.java:

o Change the type on m_vwJokeLayout to ListView and update its

initialization in initLayout.

o Initialize your m_jokeAdapter member variable with your ArrayList

Page 52: Android Assignmesnts

of jokes.

Do this in the onCreate method immediately

after m_arrJokeList has been initialized, but before you

populate it with the joke's string resource values.

o Set m_vwJokeLayout's adapter to be m_jokeAdapter.

Do this in

the onCreate method immediately after m_jokeAdapter has

been initialized.

o Update the addJoke(...) method to notify m_jokeAdapter that the

dataset has changed.

Make a call to

JokeListAdapter's notifyDataSetChanged() method after

adding the joke to m_arrJokeList.

If you don't make this call after changing the dataset, the

ListView will not be updated to reflect the new state of your list

of Jokes. You can read the Android Documentation

on BaseAdapter.notifyDataSetChanged() for a complete

description of the method.

Remove the lines of code that explicitly initialize a new

JokeView and add it to m_vwJokeLayout. You don't need

these anymore.

Remove the lines of code that alternate the background colors.

Page 53: Android Assignmesnts

Assignment 4

Intro

For this lab you will be developing a new GPS recording application called

WalkAbout. The purpose of the application is to allow users to record their

GPS location information as they travel. While the application records the

user’s GPS data, it displays it back to the user in the form of a path drawn on

top of a Google Map. While recording data, the user can launch a Camera

activity that will capture and store pictures on an SD-Card. When finished

recording, the application gives the user the option of storing the current GPS

data as a private application file to be loaded and displayed at a later time.

Objectives

At the end of this lab you will be expected to know:

• How to incorporate Google Maps into an application.

• How to register for and receive GPS location information.

• How to draw graphics on the screen using the Canvas class.

• How to create Google Maps Overlays.

• How to use the Camera.

• How to write data to the SD card.

• How to create and delete private application files.

• How to launch and receive results from Activities.

Activities

For this lab you will be working with a brand new application, completely

independent of the previous labs. Over the course of the lab, you will be

Page 54: Android Assignmesnts

iteratively refining and adding functionality to the WalkAbout app. With each

iteration you will be improving upon the previous iteration's functionality.

You'll start by setting up and familiarizing yourself with the Eclipse project.

You will then register for a Google Maps API key and begin incrementally

developing the main map-viewing Activity. These first few exercises will have

you display a map and the user's current position. Next, you will add

functionality to record the user's GPS location by registering for and receiving

data from what is known as the GPS Location Provider. After that, you will

implement a Camera activity for taking pictures and saving them to the SDCard.

In the final section, you will save a user's GPS path to a file that is

private to the application, and allow the application to restore itself from the

file as well.

IMPORTANT:

You will be given a Skeleton Project to work with. This project contains all of

the java and resource files you will need to complete the lab. Some method

stubs, member variables, and resource values and ids have been added as

well. It is important that you not change the names of these methods,

variables, and resource values and ids. These are given to you because there

are unit tests included in this project as well that depend on these items

being declared exactly as they are. You have complete access to these test

cases during development, which gives you the ability to run these tests

yourself. In fact, you are encouraged to run these tests to ensure that your

application is functioning properly.

Page 55: Android Assignmesnts

1. Setting Up...

1.1 Creating the Project

To begin, you will need to download and extract the skeleton project for the

WalkAbout application.

Extract the project, making sure to preserve the directory structure.

Take note of the path to the root folder of the skeleton project.

Next you will need to setup an Android project for this app. Since the

skeleton project was created in Eclipse, the easiest thing is to import this

project into Eclipse

• Select File -> Import.

• In the Import Wizard, expand General and select Existing Projects

into Workspace. Click Next.

• In the Import Project wizard, click select root directory and

click Browse. Select the root directory of the skeleton project that you

extracted. Click Open and then Finish.

• Click on the project name in the Package Explorer. Select File ->

Rename and change the name of your project to lab4<userid> where

<userid> is your user id (e.g. jsmith).

Next you will need to set the correct build target. In the Android SDK and

AVD Manager (available from Windows menu in Eclipse), ensure that you

have Google APIs for API 4. If you don't click on Available Packages (see:

http://code.google.com/android/add-ons/google-apis/installing.html ).

Once you have the Google APIs add-on install, you need to use it as the

Page 56: Android Assignmesnts

target for your project. Right-click on the lab4<userid> project, the select

Properties. Select Android and select Google APIs for 1.6 (API 4) as the

Project Build Target.

1.2 Familiarize Yourself with the Project

The project contains three java class files and a single XML layout file which

you will have to implement. WalkAbout.java will contain the definition for

the main WalkAbout Activity class. This is the class that will display the map

and the user's recorded path. The WalkAbout class makes use of a very

simple XML layout file called map_layout.xml which you will have to fill in.

From the WalkAbout Activity you will be able to launch the CameraPreview

Activity, which will be defined in the CameraPreview.java file. The

CameraPreview Activity class displays a live camera preview on the screen

and will allow the user to capture and save a picture to the SD-Card. This file

was borrowed from the Google API's Demo application and the logic to display

the camera preview is already implemented for you. You will have to fill in the

rest.

The WalkAbout Activity class will rely on the PathOverlay class to draw the

user's traveled path on its map. You will implement the logic needed for

drawing the path in the PathOverlay.java file.

A general class diagram for the project is depicted below. Classes you will be

implementing are colored yellow, the Google Maps API classes that you will be

working with are colored in blue, and the standard Android classes you should

be familiar with are colored in white.

Page 57: Android Assignmesnts

2. Using Google Maps

In this section of the lab you will be working extensively with the Google Maps

package. The Google Maps package allows you to include and manipulate

Maps in your Android Applications. The general strategy for displaying a map

in your application is to have an entire Activity dedicated to viewing a map.

This activity must extend the com.google.android.maps.MapActivity class,

which takes care of all the intricacies involved in setting up and tearing down

the services required to support displaying a map.

The actual map that gets displayed is an instance of

the com.google.android.maps.MapView class, which extends the standard

Android ViewGroup class. This class encapsulates all the gesture logic

necessary for handling panning, zooming, and touching objects on the map.

The map is just a Google map and can be displayed in three different modes:

satellite, street, and traffic. In order to use this class you will need a Google

Maps API Key. We will go over how to do this later.

By making use of the com.google.android.maps.Overlay class you

can overlay interesting data on top of your map. By either extending this base

class or using other overlay classes you can add another interaction layer

onto your map. The com.google.android.maps.MyLocationOverlay class is one

such example; it can draw a beacon on the map to display the device's

current position, and it can draw a compass on the map to display the

device's current heading.

2.1 Displaying a Map

Page 58: Android Assignmesnts

You will begin by implementing the functionality necessary to display a fullscreen

map in the WalkAbout Activity class. The layout for the WalkAbout

Activity should be specified in the res/layout/map_layout.xml file, which you

will have to fill in. This will require you to use the

com.google.android.maps.MapView class. In order to do this, you will have to

register the debug keystore (that Eclipse uses to run your applications) with

Google in order to receive a Maps API Key. When finished, your application

should appear as depicted in the figure below:

For more information and examples on working with the Google Maps

Package see the documentation site and/or visit the Android Developer

Tutorial on the Google Maps Package.

2.1.1 Get a Google Maps API Key.

In order to use the Google Maps API's and classes you will have to

register the keystore you use to sign your application with the Google

Maps Service. Once your keystore is registered, you will be provided with

a Google Maps API key that can be used with any application signed by

your keystore.

Every distribution of the Android Development Toolkit comes with a

debug keystore that is used to sign your application when it is launched

and run from Eclipse. This is how you are able to run your application on

a device or emulator without signing it yourself. For the purposes of this

lab, you need only to register your debug keystore. If you end up

releasing an application to the market you will need to register an actual

Page 59: Android Assignmesnts

keystore.

• Retrieve the MD5 Fingerprint of your debug.keystore file:

o Follow the instructions here:

http://code.google.com/android/add-ons/googleapis/

mapkey.html#getdebugfingerprint

• Register the Fingerprint with Google Maps Service:

o Follow the instructions here:

http://code.google.com/android/add-ons/googleapis/

mapkey.html#registering

• Save the API Key as a resource string in your Application:

o Copy and Paste the API Key into the res/values/strings.xml

file in between the mapApiKey string tags:

<string name="mapApiKey">INSERT_YOUR_API_KEY_HERE</string>

o Storing the API Key as a resource allows you to more easily

change it in the future.

• Your application must declare that it uses the Google Maps Library

in its manifest. Do so by adding the the following <useslibrary

... /> line to your AndroidManifest.xml file. This line

should be nested inside of

the <application></application> tags:

<application ...>

<uses-library android:name="com.google.android.maps" />

</application>

Page 60: Android Assignmesnts

• Your application must use an internet connection to retrieve map

data so it must also declare that it uses the Internet in its

manifest. Do so by adding the following <uses-permission ... />

line to your AndroidManifest.xml file. This line should be nested

inside of the <manifest></manifest> tags:

<manifest ...>

<uses-permission android:name="android.permission.INTERNET"/>

</manifest>

2.1.2 Fill in the MapView XML Layout File

The main WalkAbout MapActivity class uses a very simple layout

consisting of a root ViewGroup that contains only a single MapView

element. Implement this layout by filling in the map_layout.xml file:

• Use whatever root ViewGroup you like to contain the MapView

element.

• When adding the MapView element, you need to use the fully

qualified class name:

<com.google.android.maps.MapView ... />

• IMPORTANT: You must give the MapView element an id of

"m_vwMap".

• The MapView should fill the entire contents of the screen.

• When using a MapView element you must give it your API Key. You

do this by inserting a special android:apiKey attribute into the

MapView element declaration.

Page 61: Android Assignmesnts

o Set the attribute equal to the string resource that contains

the API Key.

android:apiKey="@string/mapApiKey"

o This is how you reference resources from within a resource

file.

• Set the MapView to clickable by adding

an android:clickable attribute with a value of true.

2.1.3 Display the Map

The WalkAbout MapActivity will display the MapView. All initialization

relating to the layout should be done in WalkAbout.initLayout(), which

gets called by onCreate():

• Inflate your map_layout.xml file.

• Initialize the MapView m_vwMap member variable by retrieving a

reference to the MapView element in the XML layout file.

• Force the Zoom Controls to be displayed in by making a call to

MapView.setBuiltInZoomControls(...) (hint: you don't actually type

MapView).

You should be able to run your application and see a Google Map. When

you touch the map, the Zoom Controls should be displayed centered

along the bottom of the screen.

2.2 Adding Map Overlays

As stated before, Overlays are used when you want to draw objects on top of

a MapView. Such objects could represent pin points for restaurant locations, a

Page 62: Android Assignmesnts

route for displaying directions, or a simple logo. Each MapView instance is

responsible for drawing the overlays that get displayed on top of it. As such,

each MapView instance has a list of all Overlays that it should draw. When

you want to add an Overlay to a MapView, you simply retrieve the MapView's

list of Overlays and add to it.

The Overlay objects are different from regular View objects in that they are

not requested to be drawn by the system. Instead they are requested to be

drawn by the MapView when the system requests that the MapView draw

itself. As such, when you make changes to an Overlay, you cannot explicitly

request that the overlay be re-drawn by calling a method like

View.invalidate() or View.postInvalidate(). In order to get the Overlay objects

to be redrawn you must call View.invalidate() or View.postInvalidate() on the

MapView that owns the Overlay objects.

You will now add an Overlay to your current MapView which will display the

device's current location and heading on top of the MapView. When finished,

your application should appear as depicted in the figure below:

2.2.1 Display Your Location

In order for your application to display your location, it must access

Positioning data from a Location Provider. In order to do this, it must

declare that it uses the ACCESS_FINE_LOCATION permission in its

manifest.

• Do so by adding the following <uses-permission ... /> line to your

AndroidManifest.xml file. This line should be nested inside of the

Page 63: Android Assignmesnts

<manifest></manifest> tags:

<manifest ...>

<uses-permission

android:name="android.permission.ACCESS_FINE_LOCATION"/>

</manifest>

Enable the map to display your current location and heading by

initializing and adding a com.google.android.maps.MyLocationOverlay to

your MapView. This should be done in the WalkAbout.initLayout()

method:

• Initialize m_locationOverlay with a new MyLocationOverlay object.

• Enable the MyLocationOverlay object's Compass and MyLocation

beacon by using the MyLocationOverlay.enableCompass() and

MyLocationOVerlay.enableMyLocation() methods.

o It is important to note that the MyLocationOverlay depends

on the GPS or Network Location settings being enabled.

These methods will do nothing if you do not have either the

Network or GPS Location setting enabled.

• Retrieve m_vwMap's list of attached Overlay objects by calling its

getOverlays() method.

• Add the m_locationOverlay to the list of Overlay objects.

You should be able to run your application and see a Google Map

containing a beacon pointing out your current location and a compass

displaying your current heading.

Page 64: Android Assignmesnts

2.3 Initialize the WalkAbout Options Menu

The WalkAbout Activity has an Options Menu that will display five different

MenuItems. Create the Options Menu as follows: Do not worry about setting

OnMenuItemClickListeners yet, you will do that later.

• "Start/Stop": This MenuItem acts as a toggle for either starting or

stopping GPS Location recording. This recording is a record of the path

that you have traveled. While recording, the MenuItem should display

"Stop." While stopped, the MenuItem should display "Start."

o Initialize the text for the MenuItem with R.string.startRecording

resource string.

Later on, you will dynamically update the text to reflect the

current recording state.

o Use WalkAbout.STARTSTOP_MENU_ITEM constant as the Id for

the MenuItem.

• "Save": This MenuItem will save the current recorded path.

o Initialize the text for the MenuItem with R.string.save.

o Use the WalkAbout.SAVE_MENU_ITEM constant as the Id for the

MenuItem.

• "Load": This MenuItem loads the last saved path.

o Initialize the text for the MenuItem with R.string.load.

o Use the WalkAbout.LOAD_MENU_ITEM constant as the Id for the

MenuItem.

• "Take Picture": This MenuItem launches a Camera Activity that allows

Page 65: Android Assignmesnts

you to take pictures.

o Initialize the text for the MenuItem with R.string.takePicture.

o Use the WalkAbout.PICTURE_MENU_ITEM constant as the Id for

the MenuItem.

• "Enable GPS": This MenuItem launches the Device Settings Activity that

allows you to enable the GPS Provider.

o Initialize the text for the MenuItem with R.string.enableGPS.

o Use the WalkAbout.ENABLEGPS_MENU_ITEM constant as the Id

for the MenuItem.

3. Using Location Services

The Android System provides services for determining the current location of

the device. The framework for working with these location based services

lives under the android.location package. A number of useful classes live

inside this package:

• LocationManager: Provides an interface for the location based

services. You will be interacting with this class most of the time when

trying to obtain location information.

• LocationProvider: LocationProviders are classes that provide updates

on the current location of the device. There exists a LocationProvider for

each different technology that determines location. There exists a GPS

LocationProvider and a Network LocationProvider. Each LocationProvider

specifies criteria that must be satisfied in order for it to be used. For

example, the GPS LocationProvider requires that the device have GPS

Page 66: Android Assignmesnts

hardware and that it be enabled.

• Criteria: This class allows you to programmatically outline criteria you

would like from a LocationProvider. Such criteria may include accuracy,

power consumption, altitude reporting, speed reporting, monetary cost,

etc. You can then setup and give an instance of this class to the

LocationManager and allow it to choose the LocationProvider that best

matches your criteria.

• LocationListener: This is an interface that defines call backs for

different events that are generated by LocationProviders. These can be

registered with a particular LocationProvider to receive updates when

the location changes or the state of the LocationProvider changes.

• Location:A data object containing location based information.

Generally contains latitude and longitude, as well as a date and

timestamp containing the time at which the location was determined.

Might also contain elevation, speed, and heading information.

• Location based utility classes: A utility class for Geo-Coding which

transforms addresses to GPS Coordinates and back, a data object class

for addresses, and some classes for monitoring the status of the GPS

satellites the device is locked onto.

In general, you usually query the LocationManager for the information you

are seeking. You can check the current status of a LocationProvider, you can

check the last known location reported by a LocationProvider, and you can

register to receive updates from a LocationProvider all through the

Page 67: Android Assignmesnts

LocationManager (just to name a few). To receive updates on location

information directly from a LocationProvider, you need to implement the

LocationListener interface and register yourself with the LocationProvider.

In the subsections that follow, you add functionality to monitor and enable

the GPS LocationProvider in the WalkAbout Activity class. You will record

changes in location as the user's path. You will then implement an Overlay

class that will draw this path onto the WalkAbout Activity's MapView object.

3.1 Testing & Enabling the GPS LocationProvider

It is entirely possible that the user has disabled the GPS hardware. Before

you can monitor and record data from the GPS LocationProvider, the GPS

hardware must be enabled. In this particular subsection, you will begin by

querying the LocationManager for whether the GPS hardware is enabled on

the device. If GPS is not enabled, you will allow the user to launch the

Location Settings Activity to enable it from the "Enable GPS" Options

MenuItem. After the user is done editing the Location Settings, they can

return to the WalkAbout Activity by hitting the back button. When the GPS

hardware is enabled the "Enable GPS" MenuItem will no longer be visible in

the Options Menu.

The following diagram depicts two use cases (Click on the image to view it at

full size). Both use cases have the application starting up without GPS

hardware enabled and without the Network LocationProvider enabled. The

first use case follows the dark green arrows along the top of the figure. The

User clicks the menu button, then clicks the "Enable GPS" MenuItem. The

Page 68: Android Assignmesnts

Location Settings Activity launches, the user then decides not to enable the

GPS. The user clicks the back button and is returned to the Walkabout

Activity. The user clicks the Menu button, and the "Enable GPS" MenuItem is

still visible. Notice that the Network and GPS Location Providers are disabled,

that the MyLocationOverlay's Current Location Beacon is not present, and

Compass heading location is inaccurate. This is because the MyLocation

Overlay relies on the LocationProvider for displaying this information.

The second use case follows the golden arrows along the bottom of the figure.

The User clicks the menu button, then clicks the "Enable GPS" MenuItem. The

Location Settings Activity launches, the user then decides to enable the

GPS. The user checks the "Enable GPS satellites" check box (Note that this

option may be labeled different in different version of Android). The user

clicks the back button and is returned to the Walkabout Activity. The user

clicks the Menu button, and the "Enable GPS" MenuItem is no longer visible.

Notice that when the user returns to the WalkAbout Activity after enabling the

GPS hardware, that the MyLocationOverlay's current Location Beacon is now

present, and Compass heading location is now accurate. It is also important

to note that if the GPS Hardware is enabled when the application starts, then

the "Enable GPS" MenuItem should not be visible.

3.1.1 Initialize LocationManager

In various parts of the WalkAbout class, you will request location

information from the LocationManager attached to this application

context. The WalkAbout class will store a reference to this

Page 69: Android Assignmesnts

LocationManager object in the m_locManager member variable for

convenience. Initialize this member variable in the

WalkAbout.initLocationData() method:

• Retrieve the LocationManager by calling the

Activity.getSystemService(...) method, passing in the

Context.LOCATION_SERVICE constant.

o Remember that this instance of the WalkAbout class is an

Activity and therefore all public and protected Activity

methods are members of this object.

• set m_locManager to the object returned to you. You will have to

cast the return value, because getSystemService(...) returns an

object of type Object.

3.1.2 Dynamically Update Options Menu

The Options menu should display the "Start/Stop" MenuItem as disabled

if the GPS Location Provider is disabled. Additionally, the Options menu

should NOT display the "Enable GPS" MenuItem at all if the GPS Location

Provider is enabled.

Each time the Options menu is displayed, you should check to see if the

GPS Location Provider is enabled and update the "Start/Stop" and

"Enable GPS" MenuItems accordingly.

• You must do this from the Activity.onPrepareOptionsMenu(...). If

this is done from the Activity.onCreateOptionsMenu(...) it will only

be done the first time the menu is shown. See the Android

Page 70: Android Assignmesnts

Documentation on this method for more details.

• You can determine whether a Location Provider is enabled by

calling the LocationManager.isProviderEnabled(...) method and

passing in the name of the Provider. See the Android

Documentation on this method for more details.

• The names of the different Providers are stored as string constants

in the LocationManager class. Check the LocationManager

Constants Documentation to determine which string to pass in.

You should be able to run your application and test that the "Start/Stop"

and "Enable GPS" MenuItems are enabled and invisible respectively

when the GPS Provider is enabled. They should also be disabled and

visible respectively when the GPS Provider is disabled.

3.1.3 Implement "Enable GPS" MenuItem

When the GPS Location Provider is disabled, the user will be able to

launch the settings activity to enable the GPS Location Provider from the

"Enable GPS" Options MenuItem. Set and fill in the

OnMenuItemClickListener for the "Enable GPS" MenuItem:

• Instantiate a new Intent object, passing in the

Settings.ACTION_LOCATION_SOURCE_SETTINGS Action String

constant.

• Call the Activity.startActivityForResult() method passing in the

intent you just created and the

WalkAbout.ENABLE_GPS_REQUEST_CODE static constant.

Page 71: Android Assignmesnts

o We pass in the Request Code so that when we handle the

result, we know which request generated the result. The

result of any Activity that we launch gets processed by the

same method and the Request Code mechanism lets us know

which result is coming from which Activity.

You should be able to run your application and test that you can launch

the settings activity to enable the GPS provider from the "Enable GPS"

MenuItem. When you hit the Back button you should return to the

WalkAbout Activity. However, you should note that the

MyLocationOverlay still won't be working.

3.1.4 Handle the Location Settings Activity Result

After the user is done with the Location Settings Activity and returns to the

WalkAbout Activity, you need to try re-enabling the MyLocationOverlay. Since you

called the Activity.startActivityForResult(...) method to launch the Location Settings

Activity, the WalkAbout Activity.onActivityResult(...) method will be called. The

requestCode parameter in this method will contain the value that you passed into

the startActivityForResult(...) method. You should test this requestCode parameter

to see if it matches the WalkAbout.EBABLE_GPS_REQUEST_CODE constant.

You test the requestCode because this same method will be called when any

Activity that you launch returns a result (You must test this value because you will

be launching another activity later and you want to be able to identify which Activity

Page 72: Android Assignmesnts

is returning a result).

Do this by overriding and filling in the Activity.onActivityResult(...) method:

• Make sure to call super.onActivityResult(...).

• Test the requestCode argument to ensure that it matches the request code

Assignment 5

Intro

For this lab you will be developing a new Application named AppRater that

suggests other Applications for users to download and try. The purpose of

the application is to share fun and interesting applications with other

users. The users can then rate the applications.

Objectives

At the end of this lab you will be expected to know:

• How to create and use ContentProviders.

• How to create and use Services.

• How to broadcast Intents.

• How to post notifications in the Notification Bar.

• How to respond to Intent broadcasts by creating and using BroadcastRecievers.

• How to perform work in a Background thread.

Activities

For this lab you will be working with a brand new application, completely

independent of the previous labs. Once you have a general understanding

of the components of the application you will begin implementing it. You

Page 73: Android Assignmesnts

will be given more general instructions in some sections. We think you

should be comfortable enough with Android by now that you can figure

more out on your own.

IMPORTANT:

You will be given a Skeleton Project to work with. This project contains all

of the java and resource files you will need to complete the lab. Some

method stubs, member variables, and resource values and ids have been

added as well. It is important that you not change the names of these

methods, variables, and resource values and ids. These are given to you

because there are unit tests included in this project as well that depend

on these items being declared exactly as they are. You have complete

access to these test cases during development, which gives you the ability

to run these tests yourself. In fact, you are encouraged to run these tests

to ensure that your application is functioning properly.

1. Setting Up...

1.1 Creating the Project

To begin, you will need to download and extract the skeleton project for

the AppRater application found with this description.

Extract the project, making sure to preserve the directory structure.

Take note of the path to the root folder of the skeleton project.

Next you will need to setup an Android project for this app. Since the

skeleton project was created in Eclipse, the easiest thing is to import this

project into Eclipse

Page 74: Android Assignmesnts

• Select File -> Import.

• In the Import Wizard, expand General and select Existing

Projects into Workspace. Click Next.

• In the Import Project wizard, click select root directory and

click Browse. Select the root directory of the skeleton project that

you extracted. Click Open and then Finish.

• Click on the project name in the Package Explorer. Select File ->

Rename and change the name of your project to lab5<userid>

where <userid> is your user id (e.g. jsmith).

1.2 Familiarize Yourself with the Project

The project contains seven java files and two XML layout

files. AppRater.java will contain the definition for the main AppRater

Activity class. This is the class that will display the list of applications the

user is supposed to test and rate. The AppRater class makes use of a very

simple XML layout file called app_list.xml which has been completed for

you. It is composed of a ListView that displays a list of applications that a

user is supposed to try out.

Applications that users are supposed to try out and rate are represented

by the App model class, defined in App.java. This is a simple class that

encapsulates the name of the application, a rating for it, the Market-URI

from which the app can be downloaded (we'll discuss this later but think

of it as a link to install it from the Market application), a boolean used to

flag the application as installed, and a unique integer ID.

Page 75: Android Assignmesnts

The AppView class is a custom class that is used for visualizing the state

of an App object. The AppView class has an App member variable on

which it bases the state of its display. It's layout is defined in

the app_view.xml XML layout file, which has already been completed for

you. This is a very simple layout file, composed of a LinearLayout

containing a single TextView. The TextView merely displays the name of

the App object that the AppView is visualizing.

The AppView class has three different states:

• If the AppView's App member has not been installed yet, then it's

background color is red.

• If the AppView's App member has been installed but hasn't been

rated yet, then it's background color is yellow.

• If the AppView's App member has been rated, then it's background

color is green.

The AppRater Activity gets the Apps it will display from

the AppContentProvider class as a Cursor of Apps. This is quite similar

to how the JokeList Activity got a Cursor of Jokes from the

JokeDBAdapter. The AppRater Activity's ListView then uses

the AppCursorAdapter class to bind AppViews to the cursor of Apps.

The AppRater Activity starts the AppDownloadService in order to add

new Apps to the underlying database. The new Apps are retrieved from a

web site. This is kind of like launching a new Activity except that there is

no User Interface for the Service. The AppDownloadService then

Page 76: Android Assignmesnts

downloads and inserts new Apps into the database. In order to insert new

Apps into the database the AppDownloadService must use the

AppContentProvider's insert method. This is quite similar to how the

JokeList Activity (in previous labs) downloads and inserts new Jokes by

using JokeDBAdapter.

Once the AppDownloadService has successfully added a new App, it

broadcasts a special Intent. The AppRater Activity will use its

internal NewAppReceiver class to listen for that special Intent. When it

hears the Intent it knows that it has to update its cursor of Apps.

Lastly, once a user has downloaded, installed, and tested an App they can

give it a rating. The user can apply a rating to an App via a ContextMenu

in the AppRater Activity. The AppRater Activity then saves the changes to

the App through the AppContentProvider.

A general class diagram for the project is depicted below. Classes you will

be implementing are colored yellow, the new Android classes that you will

be working with are colored in blue, and the standard Android classes you

should be familiar with are colored in white.

2. AppRater Activity

In this section of the lab you will be learning how to use ContentProviders

to retrieve and update persistant data, how to use Services to perform

work in the background, and how to respond to system-wide notifications

by using BroadcastReceivers. All of the work done in the following

subsections should be performed in the AppRater.java file. The file has

Page 77: Android Assignmesnts

been setup to import the already completed versions of the

AppContentProvider and AppDownloadService classes.

2.1 Querying a ContentProvider

You can interact with a ContentProvider in much the same way that you

interacted with the JokeDBAdapter. You can execute a query which will

return a Cursor, you can delete data, you can update data, and you can

insert data. The main difference is that ContentProviders offer a way to

share data between applications. Where your previous Joke database was

only visible to the JokeList application, the AppContentProvider that you

will implement later on will make your database usable by any

Application.

ContentProviders also abstract away how the underlying data is persisted.

While in this application you will be using an SQLiteDatabase, you could

just as easily store the data in files, on a remote server, or whatever else

you can come up with. For a complete background on ContentProviders

see the Android Developer Guide on ContentProviders.

For this section you must Query the AppContentProvider for a cursor of

Apps that the AppRater Activity will display. When a user clicks on one of

the listed apps, the Market application will be launched to display the

App's info page. The AppContentProvider you are using is currently prepopulated

with a single App so that you can test your implementation.

2.1.1 Fill in onCreate(...)

Start by initializing the AppRater Activity. You should query the

Page 78: Android Assignmesnts

AppContentProvider to retrieve a Cursor containing all of the Apps it

contains. Use this cursor to initialize your AppCursorAdapter and

ListView members.

• The Android Developer Guide offers instructions on how

to Query a ContentProvider.

• The URI for the AppContentProvider is defined in the

AppContentProvider.CONTENT_URI constant String.

You should be able to run your application and view a list of Apps.

2.1.2 Launch the Market Activity

When a user clicks on an AppView, you should start the Market

Activity implicitly, meaning that you should not use an Intent that

explicitly launches the Market Application. Instead, you should use

an Intent object that should cause the Market application to be

launched. You do this by specifying an Intent action-string and the

data to be acted upon. When the Market application starts, it

immediately displays the info page for the App that was

clicked. Note that the Market app is not included in the

emulator. You will need to attach a phone to test this portion of your

app. You should handle the exception that gets thrown if you are

unable to launch the Market for an App - post a Toast message

"Unable to get App from Market" when this happens.

If you are confused on how to implicitly start an Activity or for more

details on Intents, see either the Android Documentation or

Page 79: Android Assignmesnts

the Android Developer Guide on Intents:

• You should use the App.m_strInstallURI as the data which

should be acted upon.

• You should use the Intent.ACTION_VIEW as the action to be

performed.

You should be able to run your application, click on an App, and have

the Market application display the selected App's info page.

2.2 Starting & Stopping Services

Services are application components that run in the background and do

not have User Interfaces. Any time that there is some type of code that

needs to be run regularly but does not need a user interface you could

probably implement it as a Service. Services can be started from your

application's Activities that are currently visible, or they can be awoken by

System Notifications when your Activities are all closed. The AppRater

application will use a Service to update its ContentProvider with new data.

For a more detailed description, read the Android Developer Guide

on Service Application Components.

The AppContentProvider is currently only storing a single App. In this next

section you will have the AppRater Activity start the AppDownloadService

class. The AppDownloadService will download more Apps from a server

and add them to the AppContentProvider. Most importantly, the

AppDownloadService will execute in a background thread to keep the

main AppRater Activity responsive. The AppDownloadService will be

Page 80: Android Assignmesnts

controlled through the AppRater Activity's Options Menu.

2.2.1 Create the Options Menu

The AppDownloadService needs to be started and stopped from the AppRater's Options Menu.

Additionally, you may want to remove all the Apps from the ContentProvider in order to repeatedly test

the AppDownloadService, so you will need to create a MenuItem for this as well. Implement the

AppRater Activity's Options Menu as follows:

• Consider overriding the Activity.onOptionsItemSelected(...) method instead

of implementing and setting OnMenuItemClickListeners.

• The "Start Downloading" MenuItem should use

AppRater.MENU_ITEM_STARTDOWNLOAD as its ID and should

start the AppDownloadService:

o Use the Context.startService(...) method with

an explicit Intent.

• The "Stop Downloading" MenuItem should use

AppRater.MENU_ITEM_STOPDOWNLOAD as its ID and should

stop the AppDownloadService:

o Use the Context.stopService(...) method.

• The "Remove All Apps" MenuItem should use

AppRater.MENU_ITEM_REMOVEALL as its ID and should delete

all Apps from the ContentProvider:

o See Android Developer Guide on Modifying

ContentProviders for information on how to delete rows

Page 81: Android Assignmesnts

from a ContentProvider if you're confused.

Passing in null for

the where and selectionArgs parameters will

cause all rows in the ContentProvider to be deleted.

Run your application and you should see the pre-populated Apps.

Click the "Start Downloading" MenuItem, and wait a few seconds for

the Apps to download and appear in your ListView. You should see a

notification in the Notification Bar. Click the "Remove All" MenuItem

and all the Apps should disappear.

It is important to note that your AppDownloadService will continue to

run. If you wait a few more seconds the ListView should repopulate

itself with the Apps. The AppDownloadService will run even after you

have closed the AppRater Activity. You must explicitly stop it by

using the "Stop Downloading" MenuItem in order to shut it down.

2.3 Responding to Broadcasts

Intents are used as a System-level message passing system. They can be

used to start application components, or they can be used to send

messages between components. In order to listen for a message, you

need to use a Broadcast Receiver.

In the AppRater Application, the AppDownloadService will broadcast an

Intent containing the AppDownloadService.NEW_APP_TO_REVIEW action

string constant after it successfully downloads and saves a new App to the

database. Since the AppDownloadService runs in the background as a

Page 82: Android Assignmesnts

Service, this could happen whether the AppRater Activity is running or

not. If the AppRater Activity is running, it should display a Toast

notification telling the user that a new App was downloaded.

In this section, you will implement the AppReceiver class, which extends

BroadcastReceiver. AppReceiver will listen for

AppDownloadService.NEW_APP_TO_REVIEW Intents and display a Toast

notification when it hears them.

2.3.1 Implement the AppRater.AppReceiver Class

Fill in the AppReceiver.onReceive(...) method so that the AppRater

Activity displays a Toast notification telling the user that a new app

was downloaded:

• You should test the Intent argument to ensure it has

AppDownloadService.NEW_APP_TO_REVIEW as its Action-

String.

• Your Toast notification should use the R.string.newAppToast

String resource.

2.3.1 Register & Un-Register for Broadcasts

In order for your AppReceiver to be notified

when AppDownloadService.NEW_APP_TO_REVIEW action Intents are

broadcast, you must register an instance of it with your Activity.

Likewise, when the Activity moves out of the foreground, you need to

unregister the AppReciever.

• Override and fill in Activity.onResume(...).

Page 83: Android Assignmesnts

o Initialize AppRater.m_receiver.

o Construct a new IntentFilter that only listens for the

AppDownloadService.NEW_APP_TO_REVIEW action string

constant.

Intents can be broadcast from any android

component to any android component. Declaring

an IntentFilter allows you to specify which Intents

you want to listen for by specifying certain Intent

characteristics. In this case we're only interested in

Intents that have an action string

of AppDownloadService.NEW_APP_TO_REVIEW.

o Use the Activity.registerReceiver(BroadcastReceiver

receiver, IntentFilter filter) method to register

m_receiver for Intents containing the

AppDownloadService.NEW_APP_TO_REVIEW action

string.

• Override and fill in Activity.onPause(...).

o Use the Activity.unregisterReceiver(...) method to

unregister m_receiver.

Run your application and click the "Remove All Apps" MenuItem to

clear the AppContentProvider. Then click the "Start Downloading"

MenuItem. After a few seconds the AppRaterActivity should display

the new app Toast notification as new Apps are added to the

Page 84: Android Assignmesnts

ListView.

2.4 Updating Data in ContentProviders

It is sometimes necessary to modify the data contained in a

ContentProvider. In this next section you will add functionality to persist

changes to App objects in the ContentProvider. In particular, you will

enable the user to edit whether they have installed an App, as well as

apply a rating to it. Both of these actions should be performed through a

ContextMenu that gets generated by Long-Clicking on an AppView. The

main use case is pictured below.

2.4.1 Create the ContextMenu

The Context menu should use a CheckBox MenuItem for selecting whether the App has been

installed, and a group of four RadioButtons for selecting the rating to apply to an App.

Implementation Requirements:

• The "Installed" CheckBox should use AppRater.MENU_ITEM_INSTALLED as its

MenuItem ID.

• The "X Stars" Rating RadioButtons should use AppRater.MENU_RATING_GROUP as

their Group ID, and should use the AppRater MENU_ITEM_RATING1,

MENU_ITEM_RATING2, MENU_ITEM_RATING3, MENU_ITEM_RATING4 constants

as their individual MenItemID's.

Functional Requirements:

• If the App has not been installed you should not be able to give it a rating and all the

RadioButtons should be disabled (but still visible).

• Once an App has installed, the RadioButtons should be enabled to allow the user to

Page 85: Android Assignmesnts

edit the rating.

• If the user has installed and rated an app, then the ContextMenu should have the

proper CheckBox and proper RadioButton selected respectively.

• If the App has not been rated, then no RadioButton should be selected.

2.4.2 Persist App Changes

The tricky part here is figuring out which App to make the changes

to. You need to identify the AppView that was clicked when the

ContextMenu was generated. From the AppView you can retrieve the

App. Follow these instructions to retrieve the AppView and its App:

• When the onCreateContextMenu(...) was called, your ListView

that generated the ContextMenu provided the method with

an AdapterView.AdapterContextMenuInfo parameter.

o When you add a MenuItem to a ContextMenu the

ContextMenuInfo gets added to the MenuItem.

o The AdapterContextMenuInfo has a public member

variable that references the AppView that was clicked.

• Retrieve the ContextMenuInfo from the MenuItem.

o You'll need to cast it to an

AdapterView.AdapterContextMenuInfo.

• Retrieve the targetView member from the

AdapterContextMenuInfo object.

o You'll need to Cast it to an AppView.

• Retrieve the App from the AppView.

Page 86: Android Assignmesnts

o This is the App that was clicked. So simple right :)

Here are the Functional/Implementation Requirements you should

statisfy:

• When the user clicks the "Installed" MenuItem, you should

toggle the App's m_bInstalled member variable and reset its

m_nRating to App.UNRATED.

• When the user clicks a "X Stars" Radio Button, you should set

the App's m_nRating to the ID of the clicked MenuItem.

• When the user clicks any MenuItem you should update the

ContentProvider with the new data for the App.

• When the user clicks any MenuItem this should cause the

background color of the AppView to change.

o Should change to red if the app has been uninstalled.

o Should change to yellow if the app has been installed.

o Should change to green if that app has been rated.

An additional use case for uninstalling a previously installed and

rated App is pictured in the screenshots below. Notice that the rating

should be reset to App.UNRATED if it is re-installed.

Hints:

• You've changed your underlying data, don't forget to update

your Cursor & Adapter.

• The Android Developer Guide offers instructions on how

to Update a ContentProvider.

Page 87: Android Assignmesnts

• The URI for the AppContentProvider is defined in the

AppContentProvider.CONTENT_URI constant String.

• IMPORTANT: You must restrict your update to a single App

row in the ContentProvider or you will end up persisting your

change to all the Apps. The section on Querying a

ContentProvider offers advice on how to restrict your URI to

affect only a single record.

o If you create your URI correctly you can pass in null for

the where and selectionArgs parameters.

3. Implementing Background Services

3.1 AppDownloadService

For this section of the Lab you will implement your own version of the

AppDownloadService that you used in the AppRater Activity. For a

complete Background on the Service class you should probably read the

Android Developer Guide on the Service Lifecycle and the Android

Documentation on the Service Class.

3.1.1 Handle Initialization and Destruction of the Service

When the Service is first started, the onCreate() method is called.

You should initialize your Timer and TimerTask.

• You should read the Documentation on the java.util.TimerTask

Class. A TimerTask represents a java.util.Runnable object that

your Timer will execute.

o Your TimerTask should only call the

Page 88: Android Assignmesnts

AppDownloadService.getAppsFromServer() method.

• You should read the Documentation on the java.util.Timer

Class. Timer's are essentially threads which can be scheduled

to execute TimerTasks at specified rates.

o Your Timer should schedule your TimerTask for "fixeddelay"

execution.

o Your TimerTask should be scheduled at a period of

AppDownloadService.UPDATE_FREQUENCY milliseconds.

Feel free to adjust this number for testing

purposes.

o You shouldn't create a daemon Timer.

When the Service is stopped, its onDestroy() method is called. You

should free up any resources that you have allocated in this method,

including threads.

• If you don't explicitly cancel your Timer and TimerTask, they

will continue to run indefinitely.

3.1.2 Fill In the getAppsFromServer() Method

This method should download a list of Application Name and

InstallURI pairs from a server. For each Application Name and

InstallURI pair, the method should construct an App object and hand

it over to the AppDownloadService.addNewApp(...) method.

• You should use the two argument App constructor.

• The method should download from the URL that is stored in the

Page 89: Android Assignmesnts

AppDownloadService.GET_APPS_URL String constant.

• If you visit the URL, you will see the format the data comes in:

o The individual Application Name and InstallURI's data

pieces, which correspond to the same App, are separated

by a comma ',' character .

o Application Name and InstallURI pairs, which represent

 Assignment 6

Intro

For this lab you will be filling in a new Application that simply demonstrates a few

key features of the Android framework. In particular, the application demonstrates

how to send SMS text messages and how to monitor motion of the device through

the Accelerometer. The purpose of the application is simply to demonstrate

functionality. When the application starts up, the user is presented with an Activity

that allows them to choose which feature they would like to demo by pressing one of

two buttons, either SMS or Accelerometer monitoring. When the user hits one of the

buttons, it launches the Activity for the selected demo.

Objectives

At the end of this lab you will be expected to know:

• How to send SMS text messages.

• How to listen for changes in the status of a sent SMS text message.

• How to register to receive information from a device's available sensors.

• How to monitor the motion of a physical device.

Page 90: Android Assignmesnts

Activities

For this lab you will be working with a brand new application, completely independent

of the previous labs. Once you have a general understanding of the components of

the application, you will begin implementing it.

IMPORTANT:

You will be given a Skeleton Project to work with. This project contains all of the java

and resource files you will need to complete the lab. Some method stubs, member

variables, and resource values and ids have been added as well. It is important that

you not change the names of these methods, variables, and resource values and ids.

These are given to you because there are unit tests included in this project as well

that depend on these items being declared exactly as they are. These units test will

be used to evaluate the correctness of your lab. You have complete access to these

test cases during development, which gives you the ability to run these tests

yourself. In fact, you are encouraged to run these tests to ensure that your

application is functioning properly.

1. Setting Up...

1.1 Creating the Project

To begin, you will need to download and extract the skeleton project for the Lab

6 application. Extract the project, making sure to preserve the directory

structure. Take note of the path to the root folder of the skeleton project.

Next you will need to setup an Android project for this app. Use the settings listed

below for the remaining fields:

• Project Name: lab6<userid>

Page 91: Android Assignmesnts

• Build Target: Android 1.6

• Application Name: Lab6

1.2 Familiarize Yourself with the Project

The project contains three java files and three XML layout files. Please note:

Although for the purposes of this class this is assignment 6, the lab is actually

referred to as Lab 7 in terms of how the files are labeled in the downloaded project

stub. Lab7.java defines a simple Activity that allows you to choose which demo you

want to start. The Lab7 class makes use of a very simple XML layout file

called main.xml. Both Lab7.java and main.xml have been completed for you.

SMSActivity.java defines a simple SMS text messaging Activity. It allows the user

to enter a phone number, a textual message, and send the an SMS text message. It

also listens to the status of the sent SMS text message and updates the UI to display

changes to the status. The SMSActivity class makes use of an XML layout file

called sms.xml which has been completed for you. SMSActivity.java has been

partially completed. The UI components have been hooked up and initialized. It will

be your job to implement functionality for sending the text message and responding

to status changes.

When the device moves, the Accelerometer sensor in the device measures that

movement. AccelActivity.java defines a simple Accelerometer monitoring Activity.

It only displays measurements from the device's Accelerometer to the user. It makes

use of a simple XML layout file called accel.xml which has been completed for you.

AccelActivity.java has been partially completed for you. It is your job to fill in the

code necessary to listen for measurements from the Accelerometer and update the

Page 92: Android Assignmesnts

display.

2. SMS Activity

In this section of the lab, you will be learning how to send an SMS text message and

listen for changes in its delivery status. All the work done in this section will be

performed in the SMSActivity.java file. Access to SMS is done through the

android.telephony.SmsManager class. It provides an interface for sending both text

and data messages, as well as listening for status changes of sent messages and

delivery of incoming messages. For this lab, we will only be concerned with sending

text messages and monitoring the status of those messages. These exercises should

give you enough information to start working with SMS on your own. Data messages

are sent in almost the same way as text messages, and monitoring of incoming

messages is done through BroadcastReceivers. Both should be fairly straightforward

to figure out on your own.

2.1 Sending an SMS Text Message

For this subsection, you must simply send an SMS text message.

2.1.1 Fill in sendSMS()

When the send button is pressed, the sendSMS() method is called. This method

should send an SMS text message to the phone number contained in the

EditText with the Id of R.id.messageNumber. The text of the message should be

retrieved from the EditText with the Id of R.id.messageText.

• You need to retrieve an instance of SMSManager by calling its static

getDefault() method.

• You can then use one of its send methods to send a text message.

Page 93: Android Assignmesnts

o Don't worry about the PendingIntent arguments just yet, you can

pass in null. In the next section you will set these up so that you can

respond to status changes.

• Read the Android Documentation on SMSManager for more details on

these methods.

2.1.2 Testing SMS with the Emulator

If you don't have a SIM card for your device, or if you don't have a device you

can test sending a text message on the Emulator. You will need to start two

separate emulator instances. From there, you can specify the port number of

the recipient Emulator as the phone number. The ADB will then deliver the text

message to the other Emulator:

• For more details on this, see the Android Developer Guide on Sending

SMS to Another Emulator and Emulating SMS

You should be able to run your application, and verify that it can send a text

message.

2.2 Listening for SMS Status Changes

For this subsection, you will implement the functionality necessary to monitor and

respond to changes to the status of your sent text message.

2.2.1 Fill in BroadcastReceivers

Status changes of a sent SMS message are reported through Intent broadcasts. Therefore, in order to respond to

these changes you will need a BroadcastReceiver, two in fact. There are two separate status changes that get

broadcasted. The first status change gets broadcast once the message has been sent. The second is broadcast once

Page 94: Android Assignmesnts

the message has been delivered.

• Fill in the MessageSentReceiver.onReceive(...) method so that it updates the text of the

TextView with the Id of R.id.statusText:

o Check the result code.

If it represents success then set the text to R.string.sent.

If it represents failure then set the text to R.string.error.

o Read the documentation on SMSManager.sendTextMessage(...) for

details on how to interpret the result code.

• Fill in the MessageDeliveredReceiver.onReceive(...) method so that it sets the text of the

R.id.statusText TextView to R.string.delivered.

2.2.2 Fill in initStatusReceivers()

The initStatusReceivers() method is called from onCreate(...). You need to

register your new receivers to listen for status change broadcasts in this

method.

• You will have to create IntentFilters to listen for SMSActivity.SMS_SENT

and SMSActivity.SMS_DELIVERED action strings.

• Read the Android Documenation on Context.registerReceiver(...) if you

forgot how to do this from the last lab.

2.2.3 Setup PendingIntents

The following is to be performed in the sendSMS() method. You will need to

create two PendingIntent objects and pass them into your

SMSManager.sendTextMessage(...) method call. PendingIntents are a way of

Page 95: Android Assignmesnts

creating an Intent to execute at a later time. They can either start a service,

start an activity, or send a broadcast.

• Read the static PendingIntent.getBroadcast(...) method for details on how

to obtain a PendingIntent.

• You will need to initialize both SMSActivity.pendingSent and

SMSActivity.pendingDelivered.

o pendingSent should be initialized with an Intent containing the

SMSActivity.SMS_SENT action string.

o pendingDelivered should be initialized with an Intent containing the

SMSActivity.SMS_DELIVERED action string.

2.2.4 Cancel PendingIntents

When the user hits the reset button, the UI will be reset and the SMSActivity

should no longer receive udpates from the message it has previously sent.

When the reset button is pressed the cancelPendingIntents() method is called.

Fill in this method so that it cancels the SMSActivity's PendingIntents.

You should now be able to run your application, send a text message and verify

that the TextView displaying the status gets updated properly.

Note: You may not get notified when the message is delivered if you're sending

texts through the emulator, don't worry about this.

3. Accelerometer

In this section of the lab, you will be learning how to monitor changes to the

Accelerometer sensor. All work in this section will be performed in the

AccelActivity.java file. As is usually the case, you will not be interacting with the

Page 96: Android Assignmesnts

Accelerometer sensor directly, but will instead be using the

android.hardware.SensorManager class. This class provides you with a set of API's

for retrieving Sensor objects, querying Sensors for measurements, and registering

listeners with Sensors. The Sensor objects themselves do not provide you with

measurements. Sensor objects only provide hardware information like vendor,

resolution, and range.

There are a number of different types of Sensors from which data can be obtained.

Examples include Magnetic, Light, and Temperature. The ones that you can access

depend entirely on which Sensors the device actually has. For this lab you will only

be interacting with the Accelerometer Sensor. Interaction with other sensors is

performed in the same manner and this will give you a good starting point to learn

the rest on your own.

3.1 Monitoring Device Motion

In the subsections that follow, you register the AccelActivity to be notified of any

changes to the Accelerometer. When notified of changes you will simply display the

raw data to the screen. There Android SDK does not currently provide a method for

simulating the Accelerometer on the Emulator, so the following section must be

tested on a physical device to ensure that it is working properly.

3.1.1 Fill in registerWithSensor()

Retrieve an instance of the SensorManager and use it to register this instance of

AccelActivity as a SensorEventListener for the Accelerometer Sensor.

• The SensorManager can be obtained by

calling getSystemService(Context.SENSOR_SERVICE) and casting.

Page 97: Android Assignmesnts

• Read the Android Documentation

on SensorManager.registerListener(...) for information on how to register

a SensorEventListener.

o You will need to obtain an instance of the Sensor you want to

register with. You will need to use one of the SensorManger's get

methods to do this as you cannot instantiate one directly.

3.1.2 Fill In onSensorChanged(...)

When a sensor changes, and thus has a new measurement, the SensorManager

will call SensorChangeListener.onSensorChanged(...) on all listeners that have

registered with Sensor. It will pass in a SensorEvent object which contains data

about the change. You need to fill in the onSensorChanged(...) method so that

the new data is displayed on the screen:

• Read the AndroidDocumentation on the SensorEvent.values field to learn

how to get the new data.

• Update the R.id.accelerationX, R.id.accelerationY, and R.id.accelerationZ

TextFields to display the new data.

Run your application to ensure that the Accelerometer values are properly

updated on the screen. Remember, you have to do this on a physical device.

4. Deliverables

To complete this lab, you will be required to:

1. Put your entire project directory into a .zip or .tar file, similar to the stub you

were given. Submit the archive to the ITU Database (EMS). The name of your

archive should be lab6<username>.zip|tar. So if your username

Page 98: Android Assignmesnts

is jsmith and you created a zip file, then your file would be

named lab6jsmith.zip.