This class contains a project assignment that is divided into eight parts. This assignment consists in developing a small phone-book to the Android platform. This is an incremental project, divided into eigth parts. Some parts depend on others. The dependence graph is given below. Notice that this is not a linear dependence graph:
Number of partners: students are allowed to work in pairs. Bigger groups are not accepted.
Grading: the whole project is worth 50 points. Each part of the homework is worth 7.5 points. Only the seven biggest grades will be computed; thus, you can make up to 52.5 points. If you turn in all the parts, then you will automatically get the 2.5 extra points, or as much as it takes for you to fill up your quota of extra points. Notice that you can accumulate a total of 2.5 extra points in this assignment.
Delays: delays are penalized according to the following formula, where
n is the number of late days:
static int computePenalty(int n) {
int penalty = 0;
for (int i = 1; i <= n; i++) {
penalty += i*i
}
return penalty;
}
Notice that if you are three days late, you lose 14 points, which is more than
the 7.5 points that each home-work is worth.
Objectives: the academic objectives of this assignment are twofold:
Android is an operating system that runs on top of cell phones and other small mobile computers. This platform is sponsored by an international consortium, the Open Handset Alliance. Android provides to application developers a Java based programming API. The best and quickest way to get into Android is through the tutorials, available in the platform website. In particular, you should try the Hello, World! and the Notepad tutorials.
Android applications have entry points called
activities.
Each part of this homework will have a main activity called
TPX, where X is the homework number.
For instance, here is the
Eclipse dialog box right before creating the project for the sixth part of the
homework.
Each assignment must be developed as an
eclipse project.
In order to enforce good coding practices, you must use the
checkstyle
plug-in for Eclipse.
The project must be sent throw e-mail, as an attached zip file.
The e-mail must be sent to rodrigosol+dcc052@gmail.com.
The e-mail must have the following subject:
[DCC052]:[Num]:[XXXXXXXXX_YYYYYYYY], where NUM is the
part number, i.e, 1, 2, 3, ..., 8, and XXXXXXXXX_YYYYYYYY are the
IDs of the group members. Example:
[DCC052]:[2]:[2008457623_2008189732].
You should not send any written documentation other than the comments in
the Java code. To turn the project in, follow these instructions:
File
Export
hw(number)_(studentName1)_(studentName2).zip. For instance: hw1_Juan_Alejandro.zip.
Save in ZIP format.
Create directory structure.
OK.
This project is divided into eigth parts. At the end of the eighth step, you will have developed a full-blown Android application. We will be developing a phone-book, that associates names to phone numbers. You can also assign one or more labels to each entry, like gmail does, for instance. Each part of the homework is described below:
The objective of this first part of the homework is to get the student
acquainted with Android.
To accomplish this, the student will have to show the contents of a list
into the screen of the cell phone device.
Each element of the screen is an instance of the Entry class.
Entries encode a person's name, and a telephone.
Entries contain, also, a list of labels, that are related to that person.
Labels are strings, used to group people who are somehow related. This is
similar to the labels that we can use in gmail to group our friends, and
separate them from our work-mates, club-mates, theater-mates, etc, etc.
To make things easier, I have prepared some classes for you:
Entry interface.
Now, all that you must do is to code an android
activity to display the list that you obtain through the
call EntryMaker.getEntries().
If you did the right job, your application will show the screen below:
|
|
Screenshot of the solution of the first part of the assignment. Click on the image to see the larger version. |
The objective of the second part of this homework is to develop the data
structure that will be the back-bone of our application.
This data structure, that you will implement in a class called
NameDirectory, is a directory of entries that keeps track of the list of labels
associated to each entry. This class must implement this
API.
In order to test your class, augment it with a simple initialization
method, such as the one below:
private void stubInit() {
add("Person A", "12223330000");
add("Person B", "12223330001");
add("Person C", "12223330002");
try {
addLabel("Person A", "work");
addLabel("Person B", "school");
addLabel("Person B", "work");
removeLabel("Person A", "work");
addLabel("Person A", "club");
} catch (NameNotFoundException nnf) {
nnf.printStackTrace();
} catch (LabelNotFoundException lnf) {
lnf.printStackTrace();
}
}
One important aspect of any implementation of a data structure is how it handles errors. Our name directory should be able to handle three possible errors. Each of the following conditions should raise an exception. You are free to define any exceptions that you need:
addLabel.
removeLabel.
removeLabel, but the label did not exist.
In the third part of the assignment, you will code a way for the user to add entries into the phone book. In order to do this, you must perform a number of tasks:
TP3, and add a menu to this
activity. This menu should have two items:
+addr: to insert a new entry into the phone book.
view: to display the list of entries stored in the phone book.
AddrActivity, that handles the creation of
new entries. This activity should have an interface that allows the user to
enter a name and a telephone to be stored into the phone list.
Important: when creating a new activity, you must add a tag to define
it in the AndroidManifest.xml file. My file, for instance,
looks like this.
One important issue that you must sort out is how to allow communication
between the two activities that make up your application.
Names are collected by the activity AddrActivity, but they
are shown by the TP3 activity. So, some way to pass data from
one activity to the other is in order here.
I recommend the following: re-code the class NameDirectory so
that it will be a singleton.
By making it completely static, all its methods are visible across the
whole application. You can insert data directly on this class inside the
AddrActivity, and you can read this class inside the
TP3 activity.
Of course, this is just a suggestion. You do not have to necessarily listen
to me.
In the fourth part of the project you will have to code a way to allow the user to manipulate labels. There are two possible things that the user should be able to do:
Notice that an Entry will need to know how to manipulate
labels.
You will have to change its interface to something more like
this.
We are going to add this new function to our application via a context menu. A context menu is that kind of menu that appears when you select some particular item of your interface. In our case, the context menu will pop up if we click on some entry in the list, and hold the mouse button for a while. Our context menu will have two items:
+label: to insert a new label to a name.
-label: to remove a label from a name.
You know: some people have more than one telephone. The boss may have a home phone, and an office phone, plus a cell phone, and so forth. But, it would be a pain if we had to re-type all the data of someone, every time we want to add a new telephone for that person. In this part of the homework we will be fixing this. Starting from the fourth part of the project, do the following:
Entry
interface, that now looks like
this:
String getDescription()
String getAddr()
GregorianCalendar getDateOfBirth()
The main objective of this part of the homework is to be able to avoid the replication of redundant data. After the additions above, we can have many entries sharing the same address and date of birth. An efficient use of resources would avoid creating a bunch of data that represent the same information. One way of doing this is by using the flyweight design pattern. Of course, in computer science, just like in any other science, the limit is our creativity. Perhaps it is possible to avoid the replication using other strategy. Your TP5 activity should have a header comment describing what is the strategy that you have used to avoid the replication of redundant data.
|
|
Continuing with our example, let's assume that we start with a name
directory containing the following entries, produced by
this initialization code. Click on the image to see the larger version. |
|
|
If you click on some name in the list, and hold the mouse down, then a context
menu should pop up. Notice that it will only come out if you click
on the list. The context will refer to the list item where you
just clicked. Now, we have two more entries in our pop-up. The entry
+phone adds a new telephone to an existing entry. The entry
view visualize all the data of the selected entry.Click on the image to see the larger version. |
|
|
Clicking the view pop-up item you will be able to see all the
information related to a particular entry. If you click the
ok button, then you should be taken back to the main list
view, which shows all the entries.Click on the image to see the larger version. |
|
|
Clicking on the +phone pop-up item, you should go to an
interface like this, where you can add a new telephone, as well as a new
brief description to the existing entry. Notice that you must also add a new
name to this entry, as names are used as keys in the implementation of
NameDirectory.Click on the image to see the larger version. |
|
|
After clicking the Confirm button you go back to the main
activity, that shows you the list of entry names.
As you can see, the new entry has been added.
In order to test if you did the right thing, try visualizing all the
information about Person A office.
You will see that, even though you did not enter any address or date of
birth, the same address and DoB of the original entry (Person A) is
used in the new one.Click on the image to see the larger version. |
|
|
Notice that we keep the same menu view as in the fourth part of the
homework. The +addrs item takes you to an interface where
you can create new entries, and the view item takes you to the
main list view, where you can visualize an abridged version of all the
entries.Click on the image to see the larger version. |
|
|
Differently from the fourth part, now, the creation of an entry includes
many more items. In this simple interface I am assuming for the
Birth item the Brazilian date format:
day, month, year.
Of course, you can be nicer, and label the boxes with the date divisions.Click on the image to see the larger version. |
If you came up to this point, then you did a good job, but there is still a lot to do! You may be wondering what are those labels good for. So, let me tell you: they help the user to organize their phone list, and, more important, they help the young Fernando Magno to play the devil in the homework. So, in this part of the project we will be coding a search engine that operates on the labels. This part of the homework does not depend on the fifth part, but it depends on the fourth. You can start from either part. I will start from the fourth. If you want to have a really functional application, start from the fifth. A modular design should make it easy to choose either approach.
Let's start by creating a GUI to read query strings. A query string is a description of the pattern of labels that must be searched for. For instance:
work: this query tells the search engine to look for all the
entries that contain the work label.
work | school: this query tells the search engine to look for
all the entries that contain either the work label or the
school label. The pipe symbol (|) stands for "or".
work & school: this query tells the search engine to look
for all the entries that contain both the work label or the
school label. The ampersand symbol (&) stands for "and".
work & school | army & club: this query tells the search
engine to look for all the entries that contain either both the labels
work and school, or both the label
army and club. Notice that the "and" has
greater preference than the "and". So, the query is equivalent to
(work & school) | (army & club).
The main objective of this part of the homework is to code a simple and elegant program that handles the searches. It is important to keep the Single Responsibility Principle in mind in this part of the homework. The class that does the parsing, breaking a query string into some simpler, more understandable units, should not be the same class that does the search itself, and, ideally, none of these classes should have anything to do with the GUI that receives the queries.
Another question to bear in mind is how to do the search.
Queries are somehow composable, e.g, we can combine two sub-queries into
a bigger OR query, and then we can combine this query with
another one, and so on.
Notice, however, that in this case, the patter of queries is very
simple: if we think in a query as a tree, we will see that it has only
two levels:
Some use cases of this homework are listed below:
You may have realized that there are many ways to optimize queries.
That is, if we try to search for a pattern of labels like
L0 & L1 & L0 or if we search for L0 & L1 we are
getting the same answer.
In this assignment you will optimize this; however, we must implement a way
to test our optimization first.
The optimization works if optimized queries run faster than the non-optimized
stuff.
Thus, we need a way to test the timing of our optimizations.
With this purpose, you will have to implement a random entry
generator.
There are many ways of doing this.
For instance, you can produce entries which have numbers for names, and
labels chosen from a random set of pre-defined labels.
A name, in this case, my be something like:
"229851062 5. 7192718331", and Mr. 7192718331"
might be associated to the set of labels
{L0, L2, L3, L6, L8, L9}.
We just need a way to produce many, many, many different entries, with the
property that these entries may share a substantial amount of labels.
Once you have a generator of random entries, use it to populate your
name directory.
Try using different quantities of entries.
The Android emulator is not very robust performancewise, and you will see
that as you grow the number of entries, and the size of the pool of
labels, the machine will take longer and longer to start up.
Once you have coded the random entry generator, it is time to implement an optimizer. Your optimizer will perform only two kinds of optimizations:
L0 & L1 & L0, you should be able to
produce L0 & L1.
L0 & L1 | L0 & L2 | L0 & L1 | L0 & L2, you should be
able to deduce L0 & L1 | L0 & L2.
Notice that I want something very simple here.
For instance, from L0 & L1 & L2 | L0 & L1 we could deduce
L0 & L1 (but not L0 & L1 & L2!).
However, you do not have to implement this kind of optimization.
I mean, it will be nice if you do, but you can stick to the old and good
"remove expressions only if they are the same" rule.
Yet, from L0 & L1 | L1 & L0 you should be able to find
L0 & L1, in spite of the different ordering of the labels.
One important question is: how to tell the application that it must optimize the query? Well, you could add something in the interface of the query activity to indicate this, but we can make it simpler. We only want to test our optimizer, so we can use a stub in this case. Thus, let's use the following convention: if the query starts with a star (*), then it should be optimized.
Use the Log class to dump time reports. You can get timing information via the System.currentTimeMillis method.
You must code your implementation with some concerns in mind:
L0 & (L1 | L2).
Would it be possible to reuse your optimizer to implement factorization,
i.g L0 & L1 | L0 & L2 = L0 & (L1 | L2)?
Make sure that your TP7.java file contains a header comment
providing answer to all the questions above.
Additionally, the header comment should contain time reports for the following
queries, in optimized and non-optimized mode, given labels from the
set {L0, L1, L2, L3, L4, L5, L6, L7}, and a pool of 2000 random
entries:
L0 & L1 & L2 & L3 & L4 & L5
L0 & L1 & L0 & L1
L0 & L1 & L2 & L0 & L1 & L2
L0 & L1 | L0 & L2 | L0 & L3
L0 & L1 | L0 & L1 | L0 & L1
Below I have listed some use cases of this application:
So, if you came till this part, you may enjoy yourself: this is the last part of our homework. No worries, it is one of the easiest too! You will start from Part Five of the homework. So, to be done with this part, you will need the entries augmented with address, birthdate and description. In this phase, we will give the user the possibility of sorting the entries according to three criteria:
You will have to implement an interface where the user can choose one of the sorting criteria. Use a spinner to build the interface. You can learn about spinners in the tutorial. Once the user chooses a criterion, you must exhibit the list of entries according to the chosen ordering.
As you see, this part of the homework is very easy, but you must code your implementation with two concerns in mind:
TP8.java file should contain a header comment
describing how to add a new sorting criterion to the application.
TP8.java file describing the
mechanisms that you have employed to reuse the sorting algorithm.
Below I have listed some use cases of this application: