Android Well-Being Application Documentation

11
Android Well-Being Application Natalie Sanders I. Problem Presented Researchers were in need of a native Android application which would allow employers to gauge their employees’ emotional and physical state throughout the day. This would be accomplished by having the subjects complete multiple surveys during certain days at specific times. Thus, the application would be an interface for completing various surveys. This required the application to have the following capabilities: Store the surveys Receive updates from the administrator/s Notify the user when a survey becomes available Have a display listing all surveys and distinguish which surveys are open Send completed survey data to a web database (Parse) II. Implementation When the application is first installed, the class Wellbeing initializes the application to connect to the Wellbeing project in the Parse website. This will allow the application to communicate with Parse for updates and storing survey responses. Next, the class queries Parse to pull all of the active surveys from a table called SurveySummary. Each entry in the table corresponds to a survey and lists the name of a separate Parse table which specifies all of the survey’s questions and metadata. Thus, additional Parse queries are needed for each survey in order to retrieve all of the survey data. Each survey and its data are then stored in a SQLite database and alarms are set for each time that the survey is active. The home screen of the application is implemented in an Android activity called StartScreen. StartScreen first checks if the user’s email is saved in the application’s SharedPreferences. If no

Transcript of Android Well-Being Application Documentation

Page 1: Android Well-Being Application Documentation

Android Well-Being Application Natalie Sanders

I. Problem Presented

Researchers were in need of a native Android application which would allow employers to gauge

their employees’ emotional and physical state throughout the day. This would be accomplished by

having the subjects complete multiple surveys during certain days at specific times. Thus, the

application would be an interface for completing various surveys. This required the application to

have the following capabilities:

Store the surveys

Receive updates from the administrator/s

Notify the user when a survey becomes available

Have a display listing all surveys and distinguish which surveys are open

Send completed survey data to a web database (Parse)

II. Implementation

When the application is first installed, the class Wellbeing initializes the application to connect

to the Wellbeing project in the Parse website. This will allow the application to communicate with

Parse for updates and storing survey responses. Next, the class queries Parse to pull all of the active

surveys from a table called SurveySummary. Each entry in the table corresponds to a survey and lists

the name of a separate Parse table which specifies all of the survey’s questions and metadata. Thus,

additional Parse queries are needed for each survey in order to retrieve all of the survey data. Each

survey and its data are then stored in a SQLite database and alarms are set for each time that the

survey is active.

The home screen of the application is implemented in an Android activity called StartScreen.

StartScreen first checks if the user’s email is saved in the application’s SharedPreferences. If no

Page 2: Android Well-Being Application Documentation

email is found, StartScreen calls the activity EmailDialog which creates a pop-up alert dialog asking

the user for their email. The pop-up cannot be dismissed until the user enters a valid email address.

Figure 1: Email Dialog

The StartScreen activity also sets a daily alarm for the intent service UpdateService which updates

the application every night. The StartScreen activity and the UpdateService communicate via a

broadcast receiver so that the home screen’s ListView can be updated dynamically. Meanwhile, the

home screen displays a ListView that is populated with surveys from the database. Each entry has its

own icon, the name of the survey, the day abbreviations for which it is active, and the times for

which it is active. When a survey is active, its entry is displayed in black and when it’s inactive, its

entry is greyed out. Clicking on a survey entry while it is active will take the user to the survey itself,

implemented in SurveyScreen.

Page 3: Android Well-Being Application Documentation

Figure 2: Start Screen

The SurveyScreen activity is responsible for the survey itself. The previous activity sends the

survey ID along with the intent. This allows the SurveyScreen activity to retrieve all the data for the

corresponding survey from the SQLite database. Using this data, the activity can display four types

of questions: multiple-choice button questions, checkbox questions, slider rating questions, and

textbox input questions. One checkbox, textbox, or button question may be displayed per page but

up to three slider questions can be displayed on a page. A question is displayed by programmatically

adding the question and its answer method to a TableView in the RelativeLayout. To retrieve the

user’s responses, the activity implements a listener on the current question/s in the view. When a

user inputs their answer, the answer value and the timestamp at which it was chosen is stored in

the SQLite database. To move between questions the user uses the 'back' and 'next’ buttons at the

bottom of the screen. When switching between questions, the activity clears the TableView and

then programmatically builds the next question. Pressing ‘next’ on the last question brings the user

Page 4: Android Well-Being Application Documentation

to the end screen, implemented by the activity FinishScreen. Likewise, pressing ‘back’ on the first

question brings the user to the home screen.

Figure 3: Button, Slider, Textbox, & Checkbox Questions (Clockwise)

Page 5: Android Well-Being Application Documentation

The ending screen is implemented by the activity FinishScreen. In this view, the user is informed

of how many questions they have completed out of the survey’s total question count. They are able

to return to the survey by clicking the ‘back’ button or they can submit their survey to Parse by

clicking the ‘submit’ button. When the user chooses to submit, the activity checks that there is Wi-Fi

access. If there is not, the activity notifies the user with a Toast notification and returns to the home

page without submitting. Otherwise, all of the survey data is sent to Parse, question by question.

Each submission to Parse contains:

Question response

Unix timestamp for the question

Email of the user

Device IMEI

Application version, e.g. ND-WB-SAV-2015-05-05

Question number

Survey version

Application installation ID

After submission, the activity clears out the user responses and timestamps for the current survey in

the database and sets its completion flag as true (denoting that the survey has been completed). A

Toast notification informs the user that the survey has been submitted and the application returns

to the home screen.

Throughout the SurveyScreen and FinishScreen activities, I implemented a self-created method

called the last touch paradigm. As long as the user is actively filling out the survey, it will remain

open even if its active period ends. This prevents the user from filling out most of the survey only to

find that it can no longer be submitted. Every time the user interacts with the application, the

activity checks if the survey has since expired. If it has, the current time is compared to the last time

the user interacted with the survey. If this time is less than five minutes, the ‘lastTouch’ time is

Page 6: Android Well-Being Application Documentation

updated to the current time and the survey remains open. Otherwise, the user is notified that the

survey has expired with a Toast notification and the application returns to the main page.

Figure 4: Finish Screen

All survey notification reminders are handled by the NotificationService. This service is triggered

by the alarms set for the surveys earlier in the code. Each active period of a survey gives four

reminders to the user. These reminders are counted by an iteration number. Thus, an alarm will

pass the NotificationService the alarm iteration number, the survey ID and the starting time of the

active period, amongst other information. Before it does anything, the service checks that the

current time is indeed during an active period for the specified survey; an update the night before

could have changed the data. If the time is valid, the service proceeds; otherwise, the service is

ended. If it is the alarm’s first iteration, the active period has just begun and the following steps are

taken:

In preparation for the new active period, the service changes the specified survey’s

completion flag to false.

Page 7: Android Well-Being Application Documentation

Iteration one of a new alarm is set for the next time the active period occurs, one week from

the current time.

If the iteration is less than four, meaning it is not the last iteration, the following steps are taken:

The service sets the next iteration of the alarm for the current active period.

The service then creates an Android Notification reminding the user to take the specified

survey. If the user clicks on the notification and the survey is still open, the application will

go to the SurveyScreen activity where the user can complete the survey. Otherwise, the

application goes to the StartScreen activity where a Toast notification informs the user that

the survey is no longer active

If the iteration is four, meaning it is the last iteration, a more intrusive reminder is created. The

service calls ReminderDialog to create an alert dialog pop-up. The user has the choice to either

dismiss the pop-up or go to the specified survey is it is still open.

Figure 5: Survey Notification (left) & Survey Pop-Up Dialog (right)

Page 8: Android Well-Being Application Documentation

The intent service UpdateService is called once every day at a random time between 12:00 AM

and 4:00 AM to update the application. Since Parse can only handle 30 requests at one time, all

users of the application cannot update at once, hence the random call times. Before it begins the

update, the service checks that there is Wi-Fi connectivity; without it the update cannot occur. So, if

there is no Wi-Fi, the service exits. Otherwise the SQLite database is cleared in preparation for the

newly imported surveys. Next the service imports all active surveys from Parse, stores them in the

database, and sets alarms for all of them as specified in the discussion of the Wellbeing class. If the

alarm for the UpdateService was created by the StartScreen activity, then after each survey is

imported, the service sends a broadcast to the receiver in StartScreen. Once all anticipated imports

have finished, the start screen can repopulate its ListView with the new surveys.

The OnBoot broadcast receiver is called when the phone has restarted. All pending intents are

lost once a phone shuts down. Thus, the alarms for the survey notifications and the update service

are also lost. To work around this, the OnBoot broadcast receiver is called once the phone boots up.

In OnBoot the alarms for all of the surveys in the database are reset as described previously and an

alarm for the update service is also set. When OnBoot sets the update service alarm, it passes it a

flag ‘FROM_BOOT’ so that the update service does not try to communicate with the receiver in the

StartScreen activity. However, if the application is opened after a reboot but before the update

occurs, the alarm for the update service is reset such that the update service will communicate with

the receiver.

III. Difficulties: Solved & Unsolved

One of the major difficulties I faced while writing this application was integrating the update

service with the rest of the application. Once the update had finished I had to find a way to alert the

start screen so that the ListView could be invalidated and then repopulated with the new surveys.

What complicated the problem further was that all Parse queries are asynchronous. Although these

queries have a ‘done’ method which is called when the query is finished, my code must handle

Page 9: Android Well-Being Application Documentation

nested Parse queries. More specifically, inside the ‘done’ method of the query for the

SurveySummary table, I have a for-loop which queries each survey’s data table. As a result, there is

no easy way to definitively say that the Parse queries have finished. Eventually I came to a solution.

After the first Parse query, I know how many surveys I must import. So after each import of a

survey’s data table, I send a broadcast to a receiver in the StartScreen activity along with a Bundle

containing the total number of surveys to be imported. On the StartScreen side, once it receives a

broadcast, the activity increments a variable counting how many broadcasts it has received thus far,

which is equivalent to the number of surveys the update service has imported. The count variable is

then compared to the total number of imports to expect, the number sent with each broadcast. If

they’re equal, then all of the imports have finished and the StartScreen activity can repopulate its

ListView with the updated surveys.

Another difficulty I faced was implementing an alarm system for the survey notifications that

was compatible with the update service. Each time an update occurs, all of the surveys are cleared

from the database and the imported surveys are stored in their place. This means that a survey A

might have an ID of 5 in the database before the update. But once it is reimported during the

update, survey A might be given a new ID of 2. If an alarm for survey A was set before the update, it

thinks that survey A has an ID of 5. For obvious reasons, this complicates matters. So in order for the

alarm system to be compatible with the update service, all previously set alarms must be canceled

when an update occurs. However, this presented a difficult problem. To cancel an alarm in Android,

you must also cancel its pending intent. To do so, you must recreate the same exact pending intent

from the same context and then call ‘cancel’ on the created intent. Unfortunately, I had to cancel

my alarms in a different context from the one in which they were created. I initially planned on

somehow retrieving the same context and using it to both create and cancel the alarms but this fell

through. And there was no way to save a pending intent in a database. To solve my dilemma, I

decided not to cancel my alarms at all. Instead of setting repeating alarms, I set one-time alarms for

Page 10: Android Well-Being Application Documentation

the start of every active period. Once these alarms triggered the NotificationService, I set a new

alarm for the current active period for the next week (as well as the next iteration of the alarm). To

make sure that an alarm hadn’t triggered the NotificationService with the wrong ID after an update,

I check that the current time is valid for the survey corresponding to the given ID. This is all

explained above in the implementation section.

Fortunately, there does not seem to be unsolved problems at the moment although there are

definitely areas that could be improved upon. Currently, if there is no Wi-Fi available, the user is

unable to submit a survey. It would be preferable if the application could somehow queue these

surveys and submit them when Wi-Fi did become available. Also, it would be better if a more

straightforward solution could be found for my alarm-canceling dilemma described above.

IV. Continuation of Code: Portability & Readability

In order to make it easier for a future developer to expand on my code, I have logically separated my

code into well-named Java classes. For example, all code for the start screen of the application is

contained in the StartScreen class whereas all code for the survey itself is contained in the

SurveyScreen class. Within these various classes, I’ve also tried to separate the code into as many

functions as possible to make it more modularized. Every class and every function is preceded by a

block comment explaining its functionality and throughout the code I’ve added extensive comments

explaining the implementation. I’ve also tried to give all variables and functions descriptive names to

clarify their purpose. If a future developer has any concerns about my code, I’m happy to answer

their questions.

V. Compatibility

This Android application is compatible with Android 4.1 (Jelly Bean) and higher

Page 11: Android Well-Being Application Documentation

VI. Compilation

To compile the project in Android Studio, complete the following steps:

1. Open ‘Android_WellBeing’ as a project in Android Studio 2. A pop-up may tell you that the Gradle project files have changed and ask if you wish to sync

Gradle, choose ‘Sync Now’ 3. Build > Make Project

VII. Further Information

Contact information:

Natalie Sanders

(810) 355-8408

School email : [email protected]

Personal email : [email protected]

GitHub Repository:

https://github.com/nsanders1994/Android_WellBeing_v2