Developing iForm ES for Android

Dan Calabrese
Zerion Engineering
Published in
5 min readAug 7, 2018

iForm Enhanced Security (ES) is a version of the iForm mobile client that is compliant with the federal government’s FISMA and HIPAA requirements. However, since it was first released eight years ago, it has only been available on iOS mobile devices. iOS’s reign of the iForm ES app has come to an end. The long awaited Android app is now available for download from the Google Play Store.

As the Android developer at Zerion Software, the task became mine to undertake. Because iForm ES already exists for iOS (and has for some time), this became my biggest blessing as well a my biggest curse. On one hand, the task had well defined parameters. Basically, make the Android client mimic the iOS client. On the other hand, the iOS client has gone through many cycles and iterations in the development process to bring it to where it is today and now we had to play catch up in a month’s time.

One of the most notable differences between iForm and iForm ES is the ability to set an idle timeout. A user-customizable time can be set for how long this timeout is. When this specified time has elapsed and if no user activity has taken place, the current signed in user is required to re-enter their password in order to continue using the app via a challenge password screen. This is where I began developing the ES client. The idle timeout timer is a simple Android Count Down Timer customized to fit the needs of the app. Each activity in the application needs to be able to track user interaction and start or stop the timer as needed. For simplicity’s sake, I created a base activity from which all of my other activities could then inherit. This base activity will do all the heavy lifting for the idle timeout (i.e. creating the timer objects, starting and stopping the timer when necessary, handling what happens when the timer runs out, and detecting user interaction).

public interface IdleTimeoutCallback {
void onTimerFinished();
}
public class IdleTimeoutActivity extends AppCompatActivity implements IdleTimeoutCallback {@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//create timer
}
@Override
protected void onResume() {
super.onResume();
//start timer
}
@Override
protected void onPause() {
super.onPause();
//stop timer
}
@Override
public void onUserInteraction() {
super.onUserInteraction();
//restart timer
}
@Override
public void onTimerFinished() {
//show challenge password
}
Idle timeout in action

One behavior of the Android system that I became aware of while testing is that using the keyboard did not trigger the callback to on User Interaction. This became a problem as even if a user was inputting data into a field via the keyboard, the timeout timer would continue to countdown and present to the user the challenge password dialog if they didn’t finish entering the text in the specified time. Fortunately, for text fields Android has a convenient way of dealing with text as the user inputs keystrokes.

addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {

}

@Override
public void afterTextChanged(Editable s) {
//restart the timer after text is entered
}
});

The iForm app is well known for its offline capabilities. We have users that spend months offline collecting data. One of the nice aspects of iForm ES is that it inherently makes implementing offline login to the app much simpler. This is because of a user specific password encrypted database. When online and attempting to login, the entered credentials are authenticated with our server. If the credentials authenticate correctly, the server responds back to the client that the user is allowed to login. In the absence of this server call when no network is available, the database is used to verify the user’s identity. The database will only open if it’s supplied the correct password. If an incorrect password is used to try to open the database, a SQLiteException is thrown.

public interface CheckUserCredentialsCallback {    void onCredentialsChecked(String response);}public class LoginAsyncTask extends AsyncTask<Void, Void, String> {
CheckUserCredentialsCallback callback;
String username;
String password;

public LoginAsyncTask(CheckUserCredentialsCallback callback){
this.callback = callback;
username = UsernameEditText.getText().toString();
password = PasswordEditText.getText().toString();

@Override
protected String doInBackground(Void... voids) {
//check for network connectivity
//if no network check if the user database file exists
//if the db exists return a positive result

@Override
protected void onPostExecute(String s) {
callback.onCredentialsChecked(s);
}
}
@Override
public void onCredentialsChecked(String response) {
//if the response is a positive offline result
try {
//try to open the users database with the password
//if the db opens successfully, the credentials were
//correct so allow the user access to the app to collect
//data.
}catch (SQLiteException e) {
//if opening the database with the password causes a
//SQLiteException to be thrown, handle the exception and alert
//the user that the entered credentials are incorrect.
}
}

With the user now signed in, the the user’s password needs to be accessed routinely when database reads or writes occur. However, the password can’t be written to the device. Android apps have an Application class. From the documentation, the Application class is a

base class for maintaining global application state…The Application class, or your subclass of the Application class, is instantiated before any other class when the process for your application/package is created.

The iForm app already makes use of a custom Application class, so this seemed like a logical place for dealing with the password problem since the password needs to be tracked in all areas of the application.

public class MyApplication extends Application {

private String mLastGoodPassword;

public void setLastGoodPassword(String lastGoodPassword) {
mLastGoodPassword = lastGoodPassword;
}

public String getLastGoodPassword() {
return mLastGoodPassword;
}
}

Whenever the user is presented with the challenge password screen or logs into the app, this password is updated if the entered password successfully opened the database.

My goal of this article was to give the users some developer insights/behind the scene functionality to the app that they use daily and these were just some examples from the iForm ES for Android development process. If you have any new and useful features that you would like to see incorporated into our app, you can make feature requests here. Then, be sure to follow the Zerion Engineering team on Medium for future insights into the iForm client evolution and see how we bring the features to life!

--

--