Importing the project template
we have strict requirements for the UI as well as a few other components. In order to provide you more help in meeting these requirements, we have a project template you can import to Android Studio.
1. Download the project template zip file to a temporary directory.
2. Extract the template zip file and copy it to your Android Studio projects directory.
a. Make sure that you copy the correct directory. After unzipping, the directory name should be “GroupMessenger1”, and right underneath, it should contain a number of directories and files such as “app”, “build”, “gradle”, “build.gradle”, “gradlew”, etc.
3. After copying, delete the downloaded template zip file and unzipped directories and files. This is to make sure that you do not submit the template you just downloaded. (There were many people who did this before.)
4. Open the project template you just copied in Android Studio.
5. Use the project template for implementing all the components for this assignment.
Step 1: Writing a Content Provider
Your first task is to write a content provider. This provider should be used to store all messages, but the abstraction it provides should be a general key-value table. Before you start, please read the following to understand the basics of a content provider: http://developer.android.com/guide/topics/providers/content-providers.html
Typically, a content provider supports basic SQL statements. However, you do not need to do it for this course. You will use a content provider as a table storage that stores (key, value) pairs.
The following are the requirements for your provider:
1. You should not set any permission to access your provider. This is very important since if you set a permission to access your content provider, then our testing program cannot test your app. The current template takes care of this; so as long as you do not change the template, you will be fine.
2. Your provider’s URI should be
“content://edu.buffalo.cse.cse486586.groupmessenger1.provider”, which means that any app should be able to access your provider using that URI. To simplify your implementation, your provider does not need to match/support any other URI pattern. This is already declared in the project template’s AndroidManifest.xml.
3. Your provider should have two columns.
a. The first column should be named as “key” (an all lowercase string without the quotation marks). This column is used to store all keys.
b. The second column should be named as “value” (an all lowercase string without the quotation marks). This column is used to store all values.
c. All keys and values that your provider stores should use the string data type.
4. Your provider should only implement insert() and query(). All other operations are not necessary.
5. Since the column names are “key” and “value”, any app should be able to insert a <key, value pair as in the following example:
ContentValues keyValueToInsert = new ContentValues();
// inserting <”key-to-insert”, “value-to-insert” keyValueToInsert.put(“key”, “key-to-insert”); keyValueToInsert.put(“value”, “value-to-insert”);
Uri newUri = getContentResolver().insert(
providerUri, // assume we already created a Uri object with our provider URI keyValueToInsert
);
6. If there’s a new value inserted using an existing key, you need to keep only the most
recent value. You should not preserve the history of values under the same key.
7. Similarly, any app should be able to read a <key, value pair from your provider with query(). Since your provider is a simple <key, value table, we are not going to follow the Android convention; your provider should be able to answer queries as in the following example:
Cursor resultCursor = getContentResolver().query(
providerUri, // assume we already created a Uri object with our provider URI
null, // no need to support the projection parameter
“key-to-read”, // we provide the key directly as the selection parameter null, // no need to support the selectionArgs parameter null // no need to support the sortOrder parameter
);
Thus, your query() implementation should read the selection parameter and use it as the key to retrieve from your table. In turn, the Cursor returned by your query() implementation should include only one row with two columns using your provider’s column names, i.e., “key” and “value”. You probably want to use android.database.MatrixCursor instead of implementing your own Cursor.
8. Your provider should store the <key, value pairs using one of the data storage options. The details of possible data storage options are in
http://developer.android.com/guide/topics/data/data-storage.html. You can choose any option; however, the easiest way to do this is probably use the internal storage with the key as the file name and the value stored in the file.
9. After implementing your provider, you can verify whether or not you are meeting the requirements by clicking “PTest” provided in the template. You can take a look at OnPTestClickListener.java to see what tests it does.
10. If your provider does not pass PTest, there will be no point for this portion of the assignment.
Step 2: Implementing Multicast
The final step is implementing multicast, i.e., sending messages to multiple AVDs. The requirements are the following.
1. Your app should multicast every user-entered message to all app instances (including the one that is sending the message). In the rest of the description, “multicast” always means sending a message to all app instances.
2. Your app should be able to send/receive multiple times.
3. Your app should be able to handle concurrent messages.
4. As with PA1, we have fixed the ports & sockets.
a. Your app should open one server socket that listens on 10000.
b. You need to use run_avd.py and set_redir.py to set up the testing environment.
i. python run_avd.py 5
ii. python set_redir.py 10000
c. The grading will use 5 AVDs. The redirection ports are 11108, 11112, 11116, 11120, and 11124.
d. You should just hard-code the above 5 ports and use them to set up connections.
e. Please use the code snippet provided in PA1 on how to determine your local AVD.
i. emulator-5554: “5554” ii. emulator-5556: “5556” iii. emulator-5558: “5558” iv. emulator-5560: “5560” v. emulator-5562: “5562”
5. Your app needs to assign a sequence number to each message it receives. The sequence number should start from 0 and increase by 1 for each message.
6. Each message and its sequence number should be stored as a <key, value pair in your content provider. The key should be the sequence number for the message (as a string); the value should be the actual message (again, as a string).
7. All app instances should store every message and its sequence number individually.
8. For your debugging purposes, you can display all the messages on the screen. However, there is no grading component for this.
9.