Table of Contents

Assignment

General description

The purpose of this homework will be to create a messenger-like application with a client component (the Android application) and a server component (already written in Python). The latest version of the Python server can be found here. The server listens on the TCP port 4000.

Communication between the client and the server will be done through JSON messages. All messages must be followed by a NULL ('\0') character.

Setup

The Python server needs to be run using the following command python3 which should be available after downloading and installing the latest version of Python 3. The server has to run on a computer or laptop.

If the Android client application is developed using an Android mobile device, a WiFi connection is required in order for the client to be able to communicate with the server.

If the Android client application is developed on an emulator, there is no need for a WiFi connection since the communication will be done on the local host. For the Android application to be able to access the server on the host machine, you will have to use the following IP address 10.0.2.2 (magic). This IP address is the address of a virtual router that isolates the emulator network interfaces from the host's network interfaces. When accessing this IP from the emulator, it will be translated to the IP of the host.

Server revisions

This section will contain all the changes and bug fixes applied to the Python server code:

Diff

Diff

          265c265
          <     server.bind(("127.0.0.1", 4000))
          ---
          >     server.bind(("", 4000))
          

Diff

Diff

@@ -160,12 +160,26 @@
         buf = b''
         running = True
         while running:
-            aux_buf = self.socket.recv(4096)
+            try:
+                aux_buf = self.socket.recv(4096)
+            except Exception as e:
+                running = False
+                print("Client disconnected...")
+                try:
+                    clients.remove(self)
+                    self.socket.close()
+                except Exception as e:
+                    print("Server encountered following error: %s" % str(e))
 
             if len(aux_buf) == 0:
                 buf += b'\0'
                 running = False
                 print("Client exiting...")
+                try:
+                    clients.remove(self)
+                    self.socket.close()
+                except Exception as e:
+                    print("Server encountered following error: %s" % str(e))
             else:
                 buf += aux_buf
          

Tasks

The application will need to have the following features:

Task 1: Login and user creation activity (1p)

The entry activity for the application will be the login activity which will contain the following elements:

The user creation activity should contain the following elements:

When logging in, the message that the client will send to the server has the following structure:

 {
  "user": "username",
  "pass": "password"
} 

The account creation message has the following structure:

 {
  "user": "username",
  "pass": "password",
  "create": true
} 

If everything is ok, the server will reply with the following message:

 {
  "response": 0
  "message": "OK"
  "users": ["user1", "user2", ...]
} 

The list contains all users registered with the server plus 3 special (predefined) users: Echo, EchoX2 and EchoDelayed. These users are bots that send back the messages sent to them (Echo 1 message immediately, EchoX2 sends two messages immediately and EchoDelayed sends one message after 5 seconds).

If login (or account creation) does not succeed, you will get a message like this:

 {
  "response": !0
  "message": "error message"
} 

You should display the error message to the user using a Dialog.

Task 2: Display all users (1p)

After login, the user should be redirected to an activity that displays a list of all existing users from the server.

This activity should also have a menu with two options:

Task 3: Favorite users (1.5p)

This activity will contain a list with the favorite users who will be locally stored in a database.

For each list item from the activity that displays all users (Task 2) add two buttons:

Task 4: Chat activity (2.5p)

This activity will be used for sending messages and reading messages received from a user.

Conversations should be displayed per user and clicking on the name of the user in the list with all the users should show the conversation with that user. Conversations should be stored locally in a database. The TCP connection with the server should be kept alive after login.

Format of outgoing message:

 {
  "users": ["user1", "user2", "user3", ...],
  "message": "Message"
} 

The list of users from the outgoing message represents the users who should receive this message (it is similar to a broadcast message).

The outgoing message does not contain information about the author of the message. The Python server will “guess” the author of the message using the information provided by the login message. Therefore, only one user can be logged in at a time in the application.

Format of incoming message:

 {
  "type": 1
  "user": "user1"
  "message": "Message"
} 

Make sure to ignore messages of other types (the protocol might be expanded).

Task 5: Communication with the server (3p)

Communication with the server should be implemented through a service which stays alive after login and dies once the socket is closed or the user decides to logout.

The service should display new message notifications which open the correct Activity for reading the message.

Task 6: Service reconnect (1p)

Add a broadcast receiver component which reconnects the service when the internet comes back online (if previous state was logged in). If the user was previously logged in, the reconnect procedure should restart the login procedure (the JSON messages).

When implementing this receiver, it will most likely listen to events caused by the change of network connectivity state (WiFi interface goes down or up). However, when a WiFi interface goes up it transitions multiple times into the CONNECTED state which means that the receiver will receive that event multiple times. The reconnect procedure needs to be done only one time once the WiFi interface is up.