Android Tip: Detect user inactivity - auto calling logout after a period of time

    When working with session, in some application which have high level security (like bank apps), your session will be expired after a period of time (5-15 minutes) if you inactivity. So, as a front-end developer, we should handle this problem to take the suitable interface for the user.
    In this tip, I will provide the way to call a method (logout) when user inactivity in 5 minutes.  Depending on the specific case, you can add more operations with your own requirements.

Detecting user inactivity

    When the Activity is not visible with user, onPause() and onStop() were called and when user reopen the Activity, onStart() and onResume() were invoked! We will rely on this life cycle to solve this problem. The solution is: if onPause() was called and after 5 minutes, onResume() is not being called, we will logout and redirect user to login screen.

java.util.Timer and the sample code

   Timer and TimerTask are 2 objects will be used to resolve problem. We initialize a Timer instance in onPause() and schedule a TimerTask (will be invoked after 5 minutes (300,000ms)) and in onResume(), we must cancel this Timer instance! Source code for our activity:
MainActivity.java
package vn.ecpay.autologout;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.util.Log;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {

    private Timer timer;
    private Toolbar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    }

    @Override
    protected void onPause() {
        super.onPause();

        timer = new Timer();
        Log.i("Main", "Invoking logout timer");
        LogOutTimerTask logoutTimeTask = new LogOutTimerTask();
        timer.schedule(logoutTimeTask, 300000); //auto logout in 5 minutes
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (timer != null) {
            timer.cancel();
            Log.i("Main", "cancel timer");
            timer = null;
        }
    }

    private class LogOutTimerTask extends TimerTask {

        @Override
        public void run() {
          
            //redirect user to login screen
            Intent i = new Intent(MainActivity.this, LoginActivity.class);
            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(i);
            finish();
        }
    }
}
    And it's layout:
activity_mian.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="vn.ecpay.autologout.MainActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:gravity="center"
        android:padding="@dimen/activity_horizontal_margin"
        android:text="Hi, friend! You logged in, after 5 minutes inactivity, you will be logout!" />
</LinearLayout>
    That is the main screen, we'll reach here after login, so this is a simple example of a login activity:
LoginActivity.java
package vn.ecpay.autologout;

import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

public class LoginActivity extends AppCompatActivity {

    private TextInputLayout userName;
    private TextInputLayout password;
    private View btnLogin;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        userName = (TextInputLayout) findViewById(R.id.username_field);
        password = (TextInputLayout) findViewById(R.id.pass_field);
        btnLogin = findViewById(R.id.btn_login);

        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (userName.getEditText().getText().toString().trim().equals("")) {
                    Toast.makeText(LoginActivity.this, "Please input your user name", Toast.LENGTH_SHORT).show();
                } else if (password.getEditText().getText().toString().trim().equals("")) {
                    Toast.makeText(LoginActivity.this, "Please input your password", Toast.LENGTH_SHORT).show();
                } else if (userName.getEditText().getText().toString().equals("devexchanges") &&
                        password.getEditText().getText().toString().equals("admin")) {
                    //Correct user name and password, go to main screen
                    Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                    startActivity(intent);
                    finish();
                } else {
                    Toast.makeText(LoginActivity.this, "Wrong input data", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}
    Login screen layout:
activity_login.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="@dimen/activity_horizontal_margin">

    <android.support.design.widget.TextInputLayout
        android:id="@+id/username_field"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/pass_field">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="User name"
            android:inputType="text" />

    </android.support.design.widget.TextInputLayout>

    <android.support.design.widget.TextInputLayout
        android:id="@+id/pass_field"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Password"
            android:inputType="textPassword" />

    </android.support.design.widget.TextInputLayout>

    <Button
        android:id="@+id/btn_login"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Login"
        android:layout_marginTop="@dimen/activity_horizontal_margin"
        android:layout_below="@+id/pass_field" />

</RelativeLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="vn.ecpay.autologout">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".LoginActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" />
    </application>

</manifest>
Important Note: I used TextInputLayout in login activity - a widget from Design Support Library, so you must add it's dependency to your app/build.gradle:
compile 'com.android.support:design:23.4.0'
    Running application, we have this output:
Click login, we will go to main screen:
 And if you click home button (to go home screen - close app) or the screen light turn off, after 5 minutes, unless reactivating your app, you will be auto redirect to the login screen!

Final thoughts

    By searching on Internet, you will find out more solutions to deal with this problem. For example: override onUserInteraction() method (reset "countdown time" when this method called). Some links in Stackoverflow you can take a glance:

Share


Previous post
« Prev Post
Next post
Next Post »