除了要求许可外,如何在不干扰当前前台进程的情况下获取媒体投影管理器?

时间:2015-10-28 17:53:52

标签: android android-5.0-lollipop

问题:我有一个截屏应用程序,它使用浮动覆盖服务进行控制,并使用屏幕转换API Media Project Manager来访问屏幕。有时,当设备内存不足时,Android会重新启动该服务,而我会丢失媒体投影。

我知道重新获取新媒体投影的唯一方法是重新打开请求权限的活动,这将是它的结束,除了一个问题。某些应用程序,特别是游戏,似乎在丢失前台进程,暂停或以其他方式重置时进行侦听。这很烦人。

这是我理想的场景。服务打开,如果用户在权限请求对话框中选择了“已检查不再询问我”,则会以不干扰当前前台活动的方式获取媒体投影。

如何在不干扰当前前台进程的情况下获取媒体投影管理器?

是否有办法从直接服务获取媒体投放,或者从服务中在后台打开活动?

目前我在Activity中使用此代码来获取媒体投影管理器

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
protected void getScreenShotPermission() {
    if(isLollipopOrNewer) {
        mediaProjectionManager = (MediaProjectionManager) getContext().getSystemService(MEDIA_PROJECTION_SERVICE);
        startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), 1);
    }
}




@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == 1) {
        if (resultCode == Activity.RESULT_OK) {
            mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
            this.finish();
        }
    }

}

2 个答案:

答案 0 :(得分:19)

所以我回到这里是因为它很愚蠢,它让我烦恼,我想出来了!

在另一个类中(在我的应用程序类中)放置此代码:

private static Intent screenshotPermission = null;

protected static void getScreenshotPermission() {
    try {
        if (hasScreenshotPermission()) {
            if(null != mediaProjection) {
                mediaProjection.stop();
                mediaProjection = null;
            }
            mediaProjection = mediaProjectionManager.getMediaProjection(Activity.RESULT_OK, (Intent) screenshotPermission.clone()); 
        } else {
            openScreenshotPermissionRequester();
        }
    } catch (final RuntimeException ignored) {
        openScreenshotPermissionRequester();
    }
}

protected static void openScreenshotPermissionRequester(){
    final Intent intent = new Intent(context, AcquireScreenshotPermissionIntent.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(intent);
}



protected static void setScreenshotPermission(final Intent permissionIntent) {
    screenshotPermission = permissionIntent;
}

在处理初始请求的活动类中(在我的情况下:AcquireScreenshotPermissionIntent)将此代码放入您的onactivityresult中:

@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (1 == requestCode) {
        if (Activity.RESULT_OK == resultCode) {
            setScreenshotPermission((Intent) data.clone());
        }
    } else if (Activity.RESULT_CANCELED == resultCode) {
        setScreenshotPermission(null);
        log("no access");

    }
    finish();

只要您需要权限,只需调用getScreenShotPermission(),然后使用生成的mediaProjection对象。

以下是它的工作原理:魔术标记是Intent中包含的一些数据。我最初尝试的是将结果意图放在一个全局变量中,并使用它来创建非活动类的媒体投影。问题是它会失败。我最终想到的是,当您使用它创建媒体投影时,令牌会消耗掉。将它作为参数传递或分配给一个新变量只是传递一个指向它的指针,它仍然被消耗。

您需要做的是使用object.clone();.这使得令牌的新副本,新副本被消耗,并且您可以根据需要创建其他令牌,只要您不使用原始令牌即可。作为奖励,您的应用程序每次启动时只需要请求一次屏幕截图。如果有其他东西接管了截屏视频,或者Android内存管理器得到了你,你就会被覆盖。您可以创建新的虚拟屏幕,而无需将onPause或onStop事件发送到其他应用程序。

答案 1 :(得分:1)

我有一个继续运行的服务,所以我在服务中声明了一个静态变量,并在用户点击我的浮动按钮(如聊天头)时使用它。

public static  Intent data = null;  //declaration 

然后当第一次用户打开应用程序时,我要求获得权限并按以下方式设置数据的值。

     @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {

 if(requestCode == 4){
               Log.d(TAG, "onActivityResult: for Screen Capture");
               if(resultCode == RESULT_OK)
               {
                   Log.d(TAG, "onActivityResult: Permission Granted");
                WindowChangeDetectingService.data = (Intent) data.clone();
                screenCapturePermission = true;
                   updateUI();
               }else
               {
                   Log.d(TAG, "onActivityResult: Permission Deined");
                   screenCapturePermission = false;
                   updateUI();
                   SnackBar screenCapturePermissionSnackbar = new SnackBar(this, "This Permission is needed.", "Grant", new View.OnClickListener() {
                       @Override
                       public void onClick(View v) {
                           takeScreenCapturePermission();
                       }
                   });
                   screenCapturePermissionSnackbar.setDismissTimer(2000);
                   screenCapturePermissionSnackbar.show();

               }
           }
    }

最后,当用户点击浮动叠加按钮时,首先检查数据的值。

 if(WindowChangeDetectingService.data == null)
        {
            Log.d(TAG, "basicSetup: Asking permission again");
            //open app again
        }else
        {
            Log.d(TAG, "basicSetup: Getting permission for the object");
            readPermissionObject();
        }

readPermissionObject的实现如下

 private void readPermissionObject()
    {
       Intent data =  WindowChangeDetectingService.getData();
        mMediaProjectionManager  = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
        startProjection(Activity.RESULT_OK,data);
    }

感谢@netsplit提供有关data.clone()的信息;