Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Requesting Android M permissions from Activity with noHistory="true" and/or showOnLockScreen="true"

I'm working on a video calling app and I have an 'incoming call' screen which alerts the user when someone is calling them. This screen is an Activity triggered by an incoming GCM and has noHistory="true" and showOnLockScreen="true" set in the manifest so that the user can engage in calls without having to unlock their device.

If the user chooses to accept the call, I launch another activity to engage in the actual call. However, before I launch the second activity I check that the necessary permissions (camera, mic etc) are present and request them if not.

This is where the problems arise.

Problem 1:

The permission request dialog that the system shows causes my activity to go into onPause. I believe because under the hood this dialog is actually an activity.

Since a new activity is launching here, using noHistory="true" means that our activity is instantly killed. Technically this is intentional behaviour and indeed the Android team have dismissed this issue as so:

https://code.google.com/p/android-developer-preview/issues/detail?id=2915

I can work around this problem by managing it manually in onPause and detecting if any outstanding permission requests are in flight etc.

Problem 2: After working around problem 1, I get to stage 2.

When requesting the permission now, my activity is no longer being killed BUT the device just goes back to the lock screen and I do not see the permission dialog.

If I then unlock the device, hurrah, I see my activity and the request permission dialog overlaid on top. This user experience is unpleasant.

Video here: https://youtu.be/cobINQ9e2GY

I am guessing that the activity for requesting permissions does not have the showOnLockScreen attribute set to true and therefore if it is launched with the screen locked, it does not show.

So, the big question, can we gracefully request permissions from Activities that are allowed to be displayed on the lock screen?

My gut feeling is NO we cannot show the permission dialogs without snapping back to the lock screen. However, an acceptable compromise for me would be to prompt the user to unlock the device / i.e show the pin entry screen.

So, question 2:

Can we programmatically show the pin unlock screen from an Activity that is shown while the screen is locked?

like image 223
Dean Wild Avatar asked Feb 02 '16 10:02

Dean Wild


1 Answers

From the documentation for requestPermission() (ActivityCompat):

This method may start an activity allowing the user to choose which permissions to grant and which to reject. Hence, you should be prepared that your activity may be paused and resumed. Further, granting some permissions may require a restart of you application. In such a case, the system will recreate the activity stack before delivering the result to your onRequestPermissionsResult( int, String[], int[]).

I ended up creating a state variable to deal with this, so that onPause() and onResume() can differentiate between being called as a result of a permission request and being called because of other system events.

So something like this:

private final int STATE_STARTING = 0;
private final int STATE_RUNNING = 1;
private final int STATE_REQUESTING_FINE_LOCATION_PERMISSION = 2;

private int state = STATE_STARTING;

@Override
public void onCreate() {
    super.onCreate();
    switch (state) {
        case STATE_STARTING:
            // do your initialization
            state = STATE_RUNNING;
            break;
    }
}

@Override
public void onResume() {
    super.onResume();
    switch (state) {
        case STATE_RUNNING:
            // handle other system events
            break;
        case STATE_REQUESTING_FINE_LOCATION_PERMISSION:
            // handle permission request event
            break;
    }
}

@Override
public void onPause() {
    super.onPause();
    switch (state) {
        case STATE_RUNNING:
            // handle other system events
            break;
        case STATE_REQUESTING_FINE_LOCATION_PERMISSION:
            // handle permission request event
            break;
    }
}

private void someFunction() {
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        state = STATE_REQUESTING_FINE_LOCATION_PERMISSION;
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_PERMISSION_FINE_LOCATION);
    } else {
        doProcessingRequiringFineLocationPermission();
    }

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case REQUEST_CODE_PERMISSION_FINE_LOCATION:
            if (grantResults != null && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                doProcessingRequiringFineLocationPermission();
            }
            state = STATE_RUNNING;
            break;
    }
}
like image 110
Chris B Avatar answered Oct 15 '22 15:10

Chris B