0

I need to show a Pincode screen when the user is inactive for more than 1 minute.

I found this answer that gave me a good solution for my needs and I implemented it on my BaseActivity.

But now I am having a problem with the onUserInteraction() method, which is being called twice (and triggering my Runnable twice) everytime I press a button and start a new activity, because when I come back after 1 minute to the previous screen, the pincode screen is showing.

I've changed my Runnable to be static, but I lose the context to start the pincode activity.

What could I do to start the activity from the runnable or to make sure the onUserInteraction() is being triggered only when something is tapped on the screen?

My current code:

  public class BaseActivity {
        private static final String TAG = BaseActivity.class.getSimpleName();

    static private Handler disconnectHandler = new Handler() {
        public void handleMessage(Message msg) {
        }
    };

    private Runnable disconnectCallback = new Runnable() {
        @Override
        public void run() {
            Intent intent = new Intent(BaseActivity.this, CustomPinActivity.class);
            startActivity(intent);
        }
    };

    public void resetDisconnectTimer() {
        disconnectHandler.removeCallbacks(disconnectCallback);
        disconnectHandler.postDelayed(disconnectCallback, getResources().getInteger(R.integer.disconnect_timeout));
    }

    public void stopDisconnectTimer() {
        disconnectHandler.removeCallbacks(disconnectCallback);
    }

    @Override
    public void onUserInteraction() {
        resetDisconnectTimer();
    }

    @Override
    protected void onResume() {
        super.onResume();
        resetDisconnectTimer();
    }

    @Override
    public void onStop() {
        super.onStop();
        stopDisconnectTimer();
    }
}

Manifest:

<activity
        android:name=".CustomPinActivity"
        android:launchMode="singleTop"
        android:label="@string/title_activity_pincode" />

<activity android:name=".base.BaseActivity"
        android:launchMode="singleTop" />
Ana Varani
  • 105
  • 1
  • 8
  • You should use the flag FLAG_ACTIVITY_SINGLE_TOP when you launch the Activity. – No More Hello World May 29 '18 at 11:13
  • I am. But when I start the activity by a button click, I should stop my timer due to an user interaction. It does work, but only for the first onUserInteraction(). The second starts it again. logs: `D/BaseActivity: onUserInteraction: reset timer resetDisconnectTimer D/BaseActivity: onUserInteraction: reset timer resetDisconnectTimer D/BaseActivity: onStop: .MainActivity stopDisconnectTimer` – Ana Varani May 29 '18 at 11:17
  • I suggest you to post the intent to start your BaseActivity, or the manifest of its, to checkt if you use the single_top option. Anyway, as a general rule, I use onPause() method as opposite of onResume() method. – No More Hello World May 29 '18 at 11:33
  • Thank you, @NoMoreHelloWorld. I edited my post with the Manifest snippet. Using onPause ou onStop didn't stop it to run twice. The problem is before this. The user interaction is called twice before the onPause, and I think it's there where the thread is being duplicated. – Ana Varani May 29 '18 at 11:44
  • It seems like CustomPinActivity extends BaseActivity, and both instances receive a call to onUserInteraction, so both of them call postDelayed. Both classes use its own instance of Runnable class, so different objects, so the removeCallback of one class doesn't remove the callback of the other class, just the callback of its instance of Runnable if it was used. – No More Hello World May 29 '18 at 12:12
  • The CustomPinActivity is extending Activity, not my BaseActivity. I was debugging my code and I found when onUserInteraction is called. The first is called on dispatchTouchEvent and the second on performUserLeavingActivity > callActivityOnUserLeaving > performUserLeaving. Does it ring a bell? – Ana Varani May 29 '18 at 12:27

1 Answers1

0

Well, I think the problem is the method onUserInteraction(). The documentation says:

All calls to your activity's onUserLeaveHint() callback will be accompanied by calls to onUserInteraction().

The link here. The documentation for onUserLeaveHint() says:

This callback and onUserInteraction() are intended to help activities manage status bar notifications intelligently; specifically, for helping activities determine the proper time to cancel a notification.

Second link here.

I understand, that onUserInteraction() method will be called each time an activity is paused, and before the pause. So I would use a flag like:

    private boolean mStartingActivity;
    private Runnable disconnectCallback = new Runnable() {
            @Override
            public void run() {
                        mStartingActivity = true;
                        Intent intent = new Intent(BaseActivity.this, CustomPinActivity.class);
                        startActivity(intent);
                    }
                };

@Override 
public void onUserInteraction() {
                    if(!mStartingActivity)
                          resetDisconnectTimer();
                }

@Override
protected void onResume() {
                    super.onResume();
                    resetDisconnectTimer();
                    mStartingActivity = false;
                }

I gess, there are more elegant solutions. I hope it helps.