Lab 1 (Reading Sensors & The Android API) : 1 Objective
Lab 1 (Reading Sensors & The Android API) : 1 Objective
Winter 2015
version 1.5
Deadline: You must submit the lab to the SVN repository by the submission deadline (see the syllabus) and be prepared to demonstrate Lab 1 to a TA at the start of your assigned Lab 2 session. The
best way to demo is during a lab session, but any earlier time where you can convince a TA to watch
is OK too.
Objective
Deliverables.
Create a system that will let you display each sensors current value when the event is received
using an event handler. (See Figure 1, eld Acceleration (linear) (m/s2 ).)
Since the reading from the sensors will change quickly, you must also display the all-time
highest or lowest (depending on which is greater in absolute value) readings from each sensor
so that we can see concrete numbers. (Field Record Acceleration (linear) (m/s2 ) in Figure 1.)
Ensure that the data you display is readable, accessible to the user, and that it does not vanish
off the edge of the screen. How you do this is up to you. For instance, you can enable scrolling,
or simply format the data effectively. Any functional system is acceptable.
Before we continue, well explain the structure of an Android application and about JavaDoc.
3.1
Even the empty Android project (e.g. from Lab 0) contains folders and les. Heres what they do.
The src folder contains all of your .java les for the project. Here you will add the code
youll write. The empty project already contains a Hello World activity, MainActivity.
The gen folder contains automatically generated .java les. Of particular interest is the
R.java le which mirrors the constants and ids you will dene in the projects xml. Do not edit
these les directly. Your changes will be lost when you build your code next.
The bin folder is the output directory for the project. Compiled les appear here.
The libs folder contains your private libraries. (You can ignore this.)
2
The res folder contains application resources, such as drawable les, layout les, and string
values. The res/layout folder is important. Each xml le in that folder describes the layout
of controls in a single activity in your application.
About Activities. The fundamental building block of an Android application is the Activity. Activities represent screens in your application. When a screen gains focus, Android activates the
appropriate activity, which may then interact with the user. When the user switches to a different
screen, Android disables the activity, preserving the program state.
The new Android application wizard will create a blank MainActivity for you. You can work exclusively with that activity, and you wont need to create any new activities for these labs.
Random testing-related tip. If you did not change anything in your code since the last time you
launched your application, Eclipse will not re-upload or restart your application when you click
Run. Instead, it will just make your application active again. If you are trying to reset your applications state, you will either need to build that option in yourself, or force Eclipse to recompile your
application.
3.2
For the next step, the rest of the labs, and life in general, you need to learn how to navigate
JavaDocs. JavaDoc is documentation automatically extracted from Java programswhile these programs were being developed, developers and technical writers added JavaDoc documentation in the
form of specially formatted comments in their source code.
Androids JavaDoc documentation is thorough and easy to read. It is at http://developer.android.
com/reference/packages.html. If you installed the documentation when you installed the Android
SDK, you can also reach the documentation from Eclipse. To do this, hover the mouse over something that you want documentation about. A yellow box will pop up; click on it. Finally, click the
right-most button that appears at the bottom of this box. See gure 2 for an example. Keep in mind
that you can only hover over something that is dened by the Android SDK. If you try to hover over
one of your own classes or variables, Eclipse will look for the JavaDoc attached to your code, and
will not nd it (unless you add it yourself.)
3.3
The immediate goal of this exercise is to display information to the user. The best way to do that is
by creating labels and modifying their contents programmatically. Well walk you through changing
the content of the Hello World label from Lab 0.
The Main activity contains the Hello World label. To reference this label from your code, you need
to give it an ID (identier). Or, in other words, we need a way to refer to that label. Heres how.
1. Create a new Android project and in the "Create Activity" window choose "Blank Activity with
fragment".
2. Open the fragment_main.xml le located in [your project] > res > layout.
3. Switch to the xml tab at the bottom of the editor.
4. Look for the xml tag <TextView> and add the attribute android:id="@+id/label1".
In the Android API, all user-visible controls are sub-classes of android.view.View. You can get a
reference to the Hello World label by calling findViewById() in your Activity with the label id
(which you just added) as a parameter. The return value of this function will be the View object that has the ID provided as an argument to the function. The Android compilation system
will add the ids to the R class. For instance, to nd the label you just added above, you might call
findViewById(R.id.label1).
Labels are TextView objects. You can change the text of a label by calling TextView.setText(). You
can just pass any String to TextView.setText(), and Android will automatically redraw the label
with the new value.
In particular, heres how to modify the Hello World label, after youve followed the steps above.
1. Open MainActivity.java in [your project] > src > ca.uwaterloo.[your project].
2. Write the following PlaceholderFragment() class:
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
TextView tv = (TextView) rootView.findViewById(R.id.label1);
tv.setText("Ive replaced the label!");
return rootView;
}
}
Non-deliverable. You should now have an Android application where you can change the label.
We are, however, going to take a step back and remove that label, replacing it with automaticallygenerated labels.
3.4
Youll need to create additional labels to display all the needed data. Of course, you could do this by
hand: modify the layout xml for your activity directly, or use the graphical layout tool (double-click
on the layout xml). This lab requires creating a lot of labels, and doing that by hand is tedious. Engineers ruthlessly automate. Conveniently, the Android API lets you create views programmatically.
Heres how to create one label and add it to a view. First, assign an id to the parent:
1. In the layout XML, nd the <RelativeLayout> tag and assign it an id like you did the label.
2. In the onCreateView() method of the PlaceHolderFragment class, declare and initialize a new
TextView object as follows:
TextView tv1 = new TextView(rootView.getContext());
3. Then, set the text as above: tv1.setText("Example Text");
4. In the onCreateView() method of your PlaceholderFragment class, get a reference to the RelativeView
object that we assigned an id to by using findViewByID().
5. Add the TextView to the layout by using the addView() method: layout.addView(tv1)
6. Repeat steps 2 through 5 as necessary to add more labels as needed.
Then, in your PlaceholderFragments onCreateView() method:
1. Get a reference to the top-level layout (which you just assigned an id to) by using findViewByIdwith
the parameter of the ID of the layout (usually starts with R.id.. Cast the result to RelativeLayout.
2. Create a new TextView, e.g. TextView tv1 = new TextView(rootView.getContext())
3. Set the text of tv1, as above.
4. Add tv1 to the layout by calling addView(tv1) on the top-level layout.
You can do this several times. You will nd that you can save some effort if you write a method to
create a new label, add it to the layout and return a reference to the new label.
Common Problems At this stage or very soon afterwards, youll need to create member variables
to contain your TextViews. You can not call getApplicationContext() or findViewById() before the
onCreate() method is executed. For example, the following will cause an null pointer exception:
public class MyActivity extends ActionBarActivity {
TextView globalView = new TextView(getApplicationContext()); // Error
TextView anotherGlobalView = findViewById(R.id.view1); // Another Error
}
Do this instead:
public class MyActivity extends ActionBarActivity {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
LinearLayout lmain = (LinearLayout) rootView.findViewById(R.id.Label1);
TextView tv1 = new TextView(rootView.getContext());
5
tv1.setText(Example);
lmain.addView(tv1);
return rootView;
}
}
RelativeLayout versus LinearLayout. Youll nd that after you follow the above directions and
add a number of labels, your TextViews all run into each other. It is possible to congure the
TextView objects to not step over each other. But its easier to change RelativeLayout for LinearLayout,
which automatically puts its contents in non-overlapping positions.
1. In frament_main.xml, change RelativeLayout to LinearLayout. You have to do that in both the
<RelativeLayout> and </RelativeLayout> tags.
2. In MainActivity.java, change the line
RelativeLayout l = (RelativeLayout)findViewById(R.id.fragment_main);
to
LinearLayout l = (LinearLayout)findViewById(R.id.fragment_main);
3. Add the line
l.setOrientation(LinearLayout.VERTICAL);
which will stack all of the TextView objects vertically rather than horizontally.
Deliverable. Add labels for all of the sensors that well record in the next stage. Your Android app
should now have a number of labels on the screen, which you should have created programmatically. But you might be displaying more labels than will t on the screen.
3.5
Scrolling
It is easy to implement a scrollbar so that the user can look at all of the labels that youve added.
This will not be necessary on a device with a suciently-sized screen, but not all devices are large.
1. Go back to fragment_main.xml, where you should currently have a top-level LinearLayout. Before the LinearLayout, introduce a ScrollView:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scroll" android:layout_width="fill_parent"
android:layout_height="wrap_content">
and close the tag after the LinearLayout:
</ScrollView>
2. Change the attribute android:layout_heights value from match_parent to wrap_content.
Deliverable. If you have more content than ts on the screen, make sure that all of the content is
somehow viewable.
Tip.
You saw the C# syntax String.Format in ECE150. The corresponding Java syntax is:
Sensor lightSensor =
sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
4. In your Fragment create an instance of your new SensorEventListener and register it.
SensorEventListener l = new LightSensorEventListener();
sensorManager.registerListener(l, lightSensor,
SensorManager.SENSOR_DELAY_NORMAL);
This should now display the value of the light sensor, if you ll in the TODO line appropriately.
Cleaning up after yourself. For many applications, it is appropriate to unregister sensor event listeners in the onPause() method of the main activity and reregister them in the onResume() method.
Unregistering event listeners helps the phone conserve battery power. Unregistering event listeners is perhaps a good idea for this lab, but will cause havoc for Labs 2 and onward unless you stop
the phone from going to sleep. Were not requiring that you unregister your event listeners.
Deliverables. Your solution must display current sensor information for these sensors, as well as
record values for all sensors but the light sensor.
(TYPE_LIGHT): The readings from the light intensity sensor.
(TYPE_ACCELEROMETER): The three components of linear acceleration from the accelerometer.
(You may also display TYPE_LINEAR_ACCELERATION data as an alternative.)
(TYPE_MAGNETIC_FIELD): The three components of the magnetic eld sensor.
(TYPE_ROTATION_VECTOR): The three components of phones rotation vector.
The record value is the highest absolute value.
4.1
You will notice that when the phone is at rest, the accelerometer reports an z-acceleration of approximately 9.81 m/s2 . Surprisingly, this is not the acceleration due to gravity, but rather the acceleration due to the normal force. To understand why this is, we need to look at what exactly an
accelerometer measures.
A simple one-axis accelerometer consists of a test mass on a spring. When a force is applied to the
case of the accelerometer, the mass moves until the force of the spring matches the force applied
to the case. The degree to which the spring is stretched or compressed tells us how much force the
case is experiencing.
Now, if we imagine this device in free-fall (dont drop your phones!), we can see that the spring will
be at its rest position, while if the device was resting on the ground, the spring would be compressed
under the weight of the test mass. Thus, an accelerometer measures acceleration relative to freefall. In relativity theory, this acceleration is called proper acceleration.
In Lab 2, youll process the data from the accelerometer to measure footsteps. To get the absolute
acceleration experienced by your phone, you will need to apply a low-pass lter to the acceleration
data. Stay tuned for more information!
8
Graphing
For the next labs, it is enormously useful to be able to see how the accelerometer reacts when you
manipulate the phone in various ways. We have provided an implementation of a line graph view
that will display sets of data points. You will nd LineGraphView.java in the materials directory
of the course repository. Figure 1 shows what the graph view looks like. There is a bit of tearing in
the screenshot of the graph because the process of taking a screenshot takes longer than one graph
update.
Using the LineGraphView The following sample code shows how to set up the LineGraphView
that weve provided. You are under no obligation to use this code; you can provide your own, if you
want, or modify the code as you feel best, but chances are you will just want to stick with the code
we provided.
Note that youll have to include an import statement for this class, since it belongs to the ca.uwaterloo.sensortoy
package. Imports are like using statements in C#1 . Hitting Ctrl-Shift-O in Eclipse often xes your imports.
class MainActivity {
LineGraphView graph;
public void onCreate(Bundle savedInstanceState) {
// ... code was already here ...
LinearLayout layout = ((LinearLayout)findViewById(R.id.layout));
graph = new LineGraphView(getApplicationContext(),
100,
Arrays.asList("x", "y", "z"));
layout.addView(graph);
graph.setVisibility(View.VISIBLE);
1 http://www.harding.edu/fmccown/java_csharp_comparison.html
Now you have code to handle sensor changes. You can hook up
Test
Your application should now display the current values of the sensors. You must display sensor
values showing the three components of each sensor along with the lifetime maximum reading for
these components. Also, you must display a graph of the accelerometer sensor readings over time.
Your application should not crash or throw exceptions.
Demonstration
Once you are satised that your design and implementation are working correctly, arrange a demonstration with a teaching assistant. You will need to have the TA complete an assessment form. All
of the members of your laboratory group must sign the completed assessment form. Your grade
will be based on the results of the project demonstration at the end of the laboratory session and
an evaluation of how well your code follows engineering design principles. (We will run plagiarism detection software on the source code, which may subsequently lower your grade and trigger
a Policy 71 case. Dont plagiarize!)
10
Writing Good Code. Your application must follow good engineering design principles. You should
therefore avoid: unnecessary code duplication; excessive use of variables the state of which you
keep synchronized manually; forgetting to deallocate (free up) resources like les you have requested from the Android OS; and any other such design failures that make your application difcult to maintain or that step on the toes of other applications you share the device with.
Commit the Lab1_SSS_XX les to your Subversion repository. The TAs will not mark labs that have
not been submitted to SVN. The address is
https://ecesvn.uwaterloo.ca/courses/ece155/w15/groups/group-NNN-MM
Email Sanjay Singh if you cant commit to that address.
If you just want to cut to the chase and get an exact listing of what to do, check the lab 1 assessment
form and you will see exactly what we are looking for in the deliverables for this lab.
11