从具有noHistory =" true"的Activity请求Android M权限和/或showOnLockScreen =" true"

时间:2016-02-02 10:43:59

标签: android permissions android-permissions android-6.0-marshmallow

我正在开发视频通话应用,而且我有一个来电'屏幕,当有人打电话给用户时提醒用户。此屏幕是由传入的GCM触发的活动,并且具有noHistory =" true"和showOnLockScreen =" true"在清单中设置,以便用户无需解锁设备即可进行通话。

如果用户选择接听电话,我会启动另一项活动以参与实际通话。但是,在我启动第二个活动之前,我会检查是否存在必要的权限(摄像头,麦克风等),如果没有则请求它们。

这就是出现问题的地方。

问题1:

系统显示的权限请求对话框导致我的活动进入onPause。我相信因为这个对话框实际上是一个活动。

由于此处启动了新活动,因此使用noHistory =" true"意味着我们的活动立即被杀死。从技术上讲,这是故意行为,事实上Android团队已经解决了这个问题:

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

我可以通过在onPause中手动管理并检测是否存在任何未完成的权限请求等来解决此问题。

问题2: 在解决问题1后,我进入第2阶段。

现在请求权限时,我的活动不再被杀死但是设备只是回到锁定屏幕而我没有看到权限对话框。

如果我然后解锁设备,欢迎,我看到我的活动和请求权限对话框覆盖在顶部。这种用户体验令人不快。

视频:https://youtu.be/cobINQ9e2GY

我猜测请求权限的活动没有将showOnLockScreen属性设置为true,因此如果在屏幕锁定的情况下启动它,则不显示。

所以,最重要的问题是,我们能否优雅地请求允许在锁定屏幕上显示的活动的权限?

我的直觉是不,我们无法在没有回到锁定屏幕的情况下显示权限对话框。但是,对我来说可接受的折衷方案是提示用户解锁设备/即显示引脚输入屏幕。

所以,问题2:

我们可以通过编程方式显示屏幕锁定时显示的活动的图钉解锁屏幕吗?

1 个答案:

答案 0 :(得分:2)

来自requestPermission()(ActivityCompat)的文档:

  

此方法可以启动一项活动,允许用户选择授予哪些权限以及拒绝哪些权限。因此,您应该准备好您的活动可以暂停和恢复。此外,授予某些权限可能需要重新启动您的应用程序。在这种情况下,系统将在将结果传递给onRequestPermissionsResult(int,String [],int [])之前重新创建活动堆栈。

我最终创建了一个状态变量来处理这个问题,因此onPause()和onResume()可以区分由于权限请求而被调用以及由于其他系统事件而被调用。

这样的事情:

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;
    }
}