Archive‎ > ‎Fall 2009‎ > ‎Course Project‎ > ‎Buddy Suite‎ > ‎

Milestone 1: FriendFinder

Please mind the Collaboration Policy. If you have any questions regarding the assignment, do ask the course staff. For this milestone, we will select 5 teams with which we will discuss the design in more detail. The team members should both know the design, the reasons behind the design decisions and the high-level details about every class.

The total number of points for this milestone is 100.
The points are awarded as follows:

  • 10 points - functional ant build file. If the build fails, the functionality will not be tested further.
  • 60 points - implementation completeness
  • 12 points - test cases
  • 16 points - design documentation
  • 2 points - filling in an online form
  • 20 points - optional extra functionality

For this milestone, you will implement the FriendFinder. The functionality that is required is the following:

  • Login - in order to use the FriendFinder, a user has to specify a username and a password (you have all received 5 username/password combinations; one of these must be used in order to successfully log in) - 10 points
  • Place the phone's position on a map - using the Google Maps, the user's current location will be displayed on a MapView. - 7 points
  • Upload the phone's position to the server - whenever the position is changed, FriendFinder has to upload the new location to the server. - 10 points
  • Retrieve the user's friends' positions - A friend is defined as a entry in the Contacts list. The server does not push location changes. In order to update the user's friends' positions, you have to periodically query the server for the friends' locations. Friends are identified by the Email field in the corresponding Contacts entry - 14 points
    Note:  If the Email field has the [a-z0-9]+ format, then you should use the field as is.
              If the Email field has the ([a-z0-9]+)@domain format, then you should discard the @domain part, and use the rest ([a-z0-9]+) as the identifier for your friend
  • Place the user's friends that are within 50m of the user's position on the map and display their status, i.e. "logged in" or "not logged in" on the phone's screen (e.g. using a TextView)- 12 points
  • Logout - when the user exits the application, FriendFinder will send the server a message specifying that the user is no longer present. - 7 points
  • Extra-functionality:
    • Send a message to all the user's friends notifying them that the user has logged-in (a)- 4 points
    • Add zoom controls for the MapView (b) - 1 point
    • Add the option for the user to select the perimeter within which friends are displayed (c). Currently, the perimeter is fixed at 50m - 5 points
    • Add an alert that notifies the user, visually and through sound, when a friend within the perimeter has logged in (d) - 5 points
    • Automatically zoom the map so as to show the closest logged-in friend. When the closest logged-in friend leaves, the map should be zoomed out to show the position of the next closest, but logged-in friend.  (e) - 5 points

    Note: The points for the extra functionality are awarded if and only if all other points have been awarded, that is if the team has 100 points for the required functionality. These potential extra points can be toward future milestones where you do less well.

Remember, we are aiming for a realistic software development process. The requirements are not final, and whenever you are in doubt of what is actually required, do ask on the discussion list.

1. Deliverables

Each team will develop a JavaDoc-produced design document containing the following:

  • Two usage scenarios for the FriendFinder. Describe, in your own words, how you envision the FriendFinder to work. The description should be placed within the code of the main application class.
  • For each class in program, provide:
    • Each class' responsibility. The responsibility should be a single concept, e.g. "communicating with the server"
    • For each public method, explain:
      • How the method helps the class fulfill its responsibility
      • What is the method supposed to do
      • What the parameters are, what their input value range should be and how each of them is used to achieve the method's goal
      • Why is the method not private
      • The list of classes with which the method communicates.
    • For each public field, explain:
      • The reason why the class contains that field. Explain the field's purpose and argue why defining a method to retrieve the desired value is not a better choice.
  • The classes that are prone to change. FriendFinder is the entry point to the Buddy Suite. As you will implement more and more functionality, this part of the system is bound to change. Design for change. Identify which classes you believe will be most influenced by subsequent changes and also estimate the effort required to make the changes. Describe how you designed for change. Write the required details for the classes prone to change within the code of the respective classes.
  • Class diagram. The diagram should be a PDF file. You can find a tutorial about class diagrams here.
  • An explanation of how you make sure the program works as required. Describe two usage scenario tests. Each of the usage scenario tests must exercise each of the required functionality. You will have to implement these two test cases. The description should be put within the code for the respective test cases.
The design document must be generated automatically using javadoc (Javadoc examples). The design of your program will be assessed against the following properties:
  • Minimal complexity - 4 points
  • Ease of maintenance - 1 points
  • Loose coupling - Every class should communicate with as few other classes as possible - 3 points
  • Extensibility - This is of great importance, as the FriendFinder represents the entry point to the Buddy Suite - 3 points
  • Reusability - 1 point
  • High fan-in/Low fan-out - 2 points
  • Leanness - 1 point
  • Stratification - 1 point
Assessing the quality of a program design is subjective. The maximum number of points a team can receive is 16.

You will have to hand in:
  • The code for FriendFinder
  • Test cases for the two usage scenarios described in the design document. Each test case will be awarded 6 points if it completes without failing. The test cases must be the ones you described in the design document. These amount up to 12 points.
  • You are allowed to use either Android 1.5 or Android 1.6. You have to provide a file called startEmulators.bat that has to run on the BC07/O8 machines and that starts the emulators with the version you want.
  • ant build file that
    • compiles the code
    • creates the apk file
    • installs FriendFinder on the two running emulators
    • executes the two test cases you described in the design document
    • generates the design documentation by running javadoc
    • A functionally complete build file will be rewarded with 10 points. If your build file does not do all of the required actions, you will get 0 points. Furthermore, your project will not be evaluated.
One of the usage scenarios that will be used to test your implementation is:
  • Log in with a TA account, say Silviu, on one emulator. All other friends, including TAs should be labelled as "not logged in"
  • Simulate movement of the phone. The position of the user should change and the server should receive GPS position modification messages
  • Log in with a second TA account, say Cristi, on the second emulator. The first emulator should show the change in Cristi's status to "logged-in", and Silviu should appear as "logged-in" as well on Cristi's phone.
  • Change Cristi's phone position to be outside of the 50m perimeter with respect to Silviu's current position.
Write a class that implements this interface. This class should not be an Activity or a component of the UI. The test cases you write have to use the same interface.
Please, keep the interface in a package called epfl.sweng.friendfinder with the same name (FriendFinderTestInterface). You can find more details about this interface here.

2. Using Google Maps

You will integrate Google Maps to allow users to see each other's locations. An introduction to the Google Maps API can be found here.

The first steps describe how to create an Android project with Eclipse and enable the Google Maps API. You can find a detailed tutorial on how to use the maps API here.

The trickiest part of setting up Google Maps is obtaining an API Key. Without it, it will not work. Here is the step-by-step procedure to get the key:

  • keytool -list -alias androiddebugkey -keystore "c:\Documents and Settings\user\.android\debug.keystore" -storepass android -keypass android. Change the path according to your system.
  • This command outputs the MD5 key fingerprint. Copy it.
  • Go to sign-up.
  • Sign-up to your Google account
  • Paste the fingerprint and click on Generate API Key
  • The generated key should go in the /res/layout/map.xml file of your project

3. Simulating the GPS coordinates

Since you work with an emulator, you cannot get real GPS coordinates. However, you can simulate them using the Eclipse environment. Once you launched the application, open the DDMS perspective (Window->Open Perspective->Other->DDMS). In the "Emulator Control" tab, in the "Location Controls" part, choose the "Manual" tab, specify your coordinates, and click "Send".

4. Communicating with the server

This project is based on a client/server architecture. The server centralizes the position of all the phones. Your task is to implement the communication protocol to upload your position to the server as well as retrieve the position of your friends. You don't need to implement the server itself, we provide it for you at the address dslabpc28.epfl.ch. The port number is 12345. If you work from home, you must use VPN.

The protocol used to communicate with the server can be found here.

5. Libraries you might find useful

You will need to handle XML and SHA1 cryptographic functions. You do not need to use any third-party library, since everything is included by default in the Android SDK.

  • For XML, you can use the org.xml.sax.* package, in particular the XMLReader class. However, you are not required to use SAX to parse the messages received from the server. If you use a third-party library, i.e. not part of the Android SDK, be sure to include it in your deliverable, in the libs/ folder
  • SHA1 hashing is provided by the java.security.MessageDigest class.

You will also need to handle network connections. For this, you will need to use client sockets. There is no need for server sockets. Use the JDK documentation for details (especially the java.net.* package and the Socket class).

6. Setting up the build.xml Files

Step 1:

Create a new project from command line using "android create project" command that we explained in first tutorial.
When projects are created from command line, a default tests folder is created, with its own build.xml and a default testcase.
If you created the project from Eclipse, we strongly advise you to:
  Create a new project from command line having the same name as the project you are working on.
  Copy the files from "res" and "src" folders to the new project, then import the new project in Eclipse, as explained in tutorial 1.

Step 2:

Create two AVDs (e.g., AVD1 and AVD2) and start two emulators on the two AVDs (e.g., first emulator on AVD1 and second one on AVD2), as explained in tutorial 1.

Step 3:

Copy the build.xml file below to the root folder of your project (I am talking from now on about the new project you created from command line).

<?xml version="1.0" encoding="UTF-8"?>
<project name="TestAndroid" default="help">
 
    <property file="local.properties"/>
 
    <property file="build.properties"/>
 
    <property file="default.properties"/>
 
    <path id="android.antlibs">
        <pathelement path="${sdk-location}/tools/lib/anttasks.jar" />
        <pathelement path="${sdk-location}/tools/lib/sdklib.jar" />
        <pathelement path="${sdk-location}/tools/lib/androidprefs.jar" />
        <pathelement path="${sdk-location}/tools/lib/apkbuilder.jar" />
        <pathelement path="${sdk-location}/tools/lib/jarutils.jar" />
    </path>
 
    <taskdef name="setup"
        classname="com.android.ant.SetupTask"
        classpathref="android.antlibs"/>
 
    <setup />
    
    <target name="run" depends="debug">
      <echo>Compile and run deliverable 1</echo>        
        <exec executable="${adb}" failonerror="true">
            <arg value="-s" />
            <arg value="emulator-5554"/>
            <arg value="install" />
            <arg value="-r" />
            <arg path="${out-debug-package}" />
        </exec>
        <exec executable="${adb}" failonerror="true">
            <arg value="-s" />
            <arg value="emulator-5556"/>
            <arg value="install" />
            <arg value="-r" />
            <arg path="${out-debug-package}" />
        </exec>
        <javadoc sourcepath="src"
                 destdir="javadoc"
                 packagenames="epfl.sweng.*" >
          <classpath>
            <pathelement path="${sdk-location}/platforms/android-1.5/android.jar"/>
          </classpath>
        </javadoc>   
    </target>
</project>

In the above build.xml file, change "TestAndroid" to "<name of your project>" and all occurrences of "epfl.sweng" to "<your package>".
If you run "ant run" in the root folder, the project is compiled and installed on the two emulators, and the javadoc documentation is generated for the project.

Step 4:

Copy the build.xml file below to the "tests" folder of your project.

<?xml version="1.0" encoding="UTF-8"?>
<project name="TestAndroid" default="help">
 
    <property file="local.properties"/>
 
    <property file="build.properties"/>
 
    <property file="default.properties"/>
 
    <path id="android.antlibs">
        <pathelement path="${sdk-location}/tools/lib/anttasks.jar" />
        <pathelement path="${sdk-location}/tools/lib/sdklib.jar" />
        <pathelement path="${sdk-location}/tools/lib/androidprefs.jar" />
        <pathelement path="${sdk-location}/tools/lib/apkbuilder.jar" />
        <pathelement path="${sdk-location}/tools/lib/jarutils.jar" />
    </path>
 
    <taskdef name="setup"
        classname="com.android.ant.SetupTask"
        classpathref="android.antlibs"/>
 
    <setup />
    
    <target name="tests" depends="debug">
      <echo>Compile and run deliverable 1</echo>        
        <exec executable="${adb}" failonerror="true">
            <arg value="-s" />
            <arg value="emulator-5554"/>
            <arg value="install" />
            <arg value="-r" />
            <arg path="${out-debug-package}" />
        </exec>
        <exec executable="${adb}" failonerror="true">
            <arg value="-s" />
            <arg value="emulator-5556"/>
            <arg value="install" />
            <arg value="-r" />
            <arg path="${out-debug-package}" />
        </exec>
        <exec executable="${android-tools}/adb">
            <arg value="-s" />
            <arg value="emulator-5554"/>
            <arg line="shell am instrument" />
            <arg value="-w" />
            <arg line="epfl.sweng.tests/android.test.InstrumentationTestRunner" />
        </exec>    
        <exec executable="${android-tools}/adb">
            <arg value="-s" />
            <arg value="emulator-5556"/>
            <arg line="shell am instrument" />
            <arg value="-w" />
            <arg line="epfl.sweng.tests/android.test.InstrumentationTestRunner" />
        </exec>    
    </target>
</project>

In the above build.xml file, change "TestAndroid" to "<name of your project>" and all occurrences of "epfl.sweng" to "<your package>".
If you run "ant tests" in the "tests" folder, the tests from "tests/src/<your package>" are compiled and installed on the two emulators, and the tests are run on the two emulators by android.test.InstrumentationTestRunner.

Step 5:
For your project classes to be seen by your tests, add the following line to local.properties file from "tests" folder:
main-out-folder=../bin/classes

7. FAQ

  • Q: How to set the Google Maps key when submitting the milesone?
A: it is ok if you leave your key in, we will replace it manually with our own key. It would be nice if you can take the key from an environment variable: SWENG_GOOGLE_MAPS_KEY but that is entirely optional. Here is how you can get the value of an environment variable: <property environment="env"/> This provides all environment variables as Ant properties prefixed by "env.". For example, CLASSPATH would be accessible in Ant as ${env.CLASSPATH}.
  • Q: How to run an AndroidTestCase from an Ant file?
A:     You can add something similar to this code to your build.xml:
    <exec executable="${android-tools}/adb"><arg line="shell am instrument" />
        <arg value="-w" />
        <arg line="your_test_package/android.test.InstrumentationTestRunner" />
    </exec>


More details are here:
  • Q: Implementing getUserScreenCoordinates and getFriendsScreenCoordinates from the testing interface.
  •    A: Implementing getUserScreenCoordinates and getFriendsScreenCoordinates will be optional. These were added when we planned to run automated UI tests,which we finally will not do. So, if you wish to implement them, we'll probably give you a few bonus points. Otherwise, you can just ignore them (i.e. return null). Please note however that we will test your UI manually.
  • Q: Using telnet and geo fix to track GPS updates yields wrong coordinates being used, how do I test my program?
    A: This is a know issue. One of the discussions you can find here .
    Furthermore, this is the reason why the setCurrentLocation method was introduced in the FriendFinderTestInterface. You can use that method to request your application to change its GPS position. To change your friends' positions you should call the receiveFromServer method from the test interface with a message like the one the server would send.
  • Q: Having a single class implement the FriendFinderTestInterface destroys my design. How should I handle that?
    A: It is mandatory that you have a class that implements the FriendFinderTestInterface. This being said, you can use the Facade Design Pattern to alleviate your problem. The functionality required by the test interface can be split among multiple classes, but the FriendFinderTestInterface aggregates their functionality. Thus, the FriendFinderTestInterface acts as a "manager": when a method of the test interface is invoked, it delegates the respective operation to the actual class implementing the functionality.
  • Q: What does the SVN address have to point to?
    A: The SVN address on this page has to point to a folder that contains your project, your test project and the startEmulators.bat file. The project folders should be in their own folders. 
    The structure ca be graphically represented as follows:
    |-SVN Address
    |------MyProject
    |------MyProjectTest
    |------startEmulators.bat
  • Q: How to submit the milestone code?
  • A: We will check out your milestone from the SVN repository at the date of the deadline. You can have in progress classes and you can also
    tag milestone 1 in the repository, but that is optional.