1

I set a timer on AccountActivity.class to ensure that user does not press home button if not will start the countdown to logout the user or if the user locks his screen.

But now I am facing an issue because of the onPause method. When my user clicks on a button which invokes the getaccounttask() method and it will redirect my user to AccountInformationActivity.class, the onPause method is activated as well and the timer starts to countdown.

Is there any solution to prevent the onPause method from counting down or the timer to be cancelled on my AccountInformationActivity.class?

I tried to do the cancelling of timer before my intent starts but still does not work.

I have tried using handler as well but encountered the same problem, I am still trying to grasp how Android fully works, so your help or solution is deeply appreciated.

public class AccountActivity extends AppCompatActivity {

    private Timer timer;

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

    private class getaccounttask extends AsyncTask<String, Void, String>
    {
      @Override
      protected String doInBackground(String... urlaccount)
      {
        StringBuilder result = new StringBuilder();
        try
        {
            //My Codes
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return result.toString();
      }

      @Override
      protected void onPostExecute(String result)
      {
        Intent intent = new Intent();
        intent.setClass(getApplicationContext(), AccountInformationActivity.class);
        startActivity(intent);
      }
     }

    @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(AccountActivity.this, MainActivity.class);
            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(i);
            finish();
        }
    }
}
Reaz Murshed
  • 23,691
  • 13
  • 78
  • 98
iOSAndroid
  • 17
  • 1
  • 11

2 Answers2

0

Well, the implementation architecture you choose could be improved. I shall come to that later. First apply this quick fix to fix your architecture.

Clearly you want to start a Timer when you go out of Activity using home screen. But user can also go out of Activity by using Intent to switch to AccountActivity. This you can track. So keep a boolean flag like shouldNavigate, initially it should be false. when onResume, it should be set to false, but when getcounttask goes to onPostExecute it should be set to true. So in onPause, if you are going out via getcounttask,shouldNavigate is going to be true and if is true, cancel your Timer else, start your Timer.

Code:

public class AccountActivity extends AppCompatActivity {

    private Timer timer;
    private volatile boolean shouldNavigate = false;

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

    private class getaccounttask extends AsyncTask<String, Void, String>
    {
      @Override
      protected String doInBackground(String... urlaccount)
      {
        StringBuilder result = new StringBuilder();
        try
        {
            //My Codes
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return result.toString();
      }

      @Override
      protected void onPostExecute(String result)
      {
        shouldNavigate = true;
        Intent intent = new Intent();
        intent.setClass(getApplicationContext(), AccountInformationActivity.class);
        startActivity(intent);
      }
     }

    @Override
    protected void onPause() {
        super.onPause();
        if (!shouldNavigate){
            timer = new Timer();
            Log.i("Main", "Invoking logout timer");
            LogOutTimerTask logoutTimeTask = new LogOutTimerTask();
            timer.schedule(logoutTimeTask, 300000); 
        }else{
            if (timer != null){
                  timer.cancel();
                  timer = null;
            }
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        shouldNavigate = false;
        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
            shouldNavigate = false;
            Intent i = new Intent(AccountActivity.this, MainActivity.class);
            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(i);
            finish();
        }
    }
}

Now a better approach could be keep a Service and a Singleton class. The Singleton class would be

public Singleton{
    private static Singleton instance = null;
    private Singleton(){
        activityMap = new HashMap<String, Activity>();
    }

    public static Singleton getInstance(){
         if (instance == null) instance = new Singeton();
         return instance;
    }

    public HashMap<String, Activity> activityMap;

}

Now each activity will have a Tag (like its name), so each activity when resumes will do

Singleton.getInstance().activityMap.put(tag, this);

and when goes to onPause will do

Singleton.getInstance().activityMap.remove(tag, this);

So when the service finds that size of Singleton.getInstance().activityMap is zero then clearly no activity is on foreground, so it starts a timer. when the timer expires check again if the count is still zero, if zero then perform your logout.

Reaz Murshed
  • 23,691
  • 13
  • 78
  • 98
dumb_terminal
  • 1,815
  • 1
  • 16
  • 27
  • Hi, I did try handler as well but I am stuck at the same problem. For the tracking part of shouldNavigate I am still not really sure as I am still new to Android and Java, if you could provide some codes it will be awesome and a great help for me to understand – iOSAndroid Aug 24 '16 at 04:47
  • please check edit, and ofcourse fix according to your need. – dumb_terminal Aug 24 '16 at 04:52
  • 1
    OMG..Finally it worked! Thanks alot! I have been stuck on this issue for like weeks! Once again thanks for everything! – iOSAndroid Aug 24 '16 at 05:38
0

Make some modifications in onPause() and add this permission

<uses-permission android:name="android.permission.GET_TASKS" />

    @Override
    protected void onPause() {
        if (isApplicationSentToBackground(this)) {
            // Do what you want to do on detecting Home Key being Pressed
            timer = new Timer();
            Log.i("Main", "Invoking logout timer");
            LogOutTimerTask logoutTimeTask = new LogOutTimerTask();
            timer.schedule(logoutTimeTask, 300000); //auto logout in 5 minutes
            Log.i("Main", "Invoking Home Key pressed");
        }
        super.onPause();

    }

    public boolean isApplicationSentToBackground(final Context context) {
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
        if (!tasks.isEmpty()) {
            ComponentName topActivity = tasks.get(0).topActivity;
            if (!topActivity.getPackageName().equals(context.getPackageName())) {
                return true;
            }
        }
        return false;
    }
Sohail Zahid
  • 8,099
  • 2
  • 25
  • 41