除非要求获得许可,否则如何在不影响当前前台stream程的情况下获得媒体投影pipe理器?

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

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

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

如何在不影响当前前台stream程的情况下获得媒体投影pipe理器?

有没有办法从直接的服务中获得媒体投射,还是通过服务在后台打开活动的方式?

目前我在Activity中使用这个代码来获得媒体投影pipe理器

@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(); } } } 

Solutions Collecting From Web of "除非要求获得许可,否则如何在不影响当前前台stream程的情况下获得媒体投影pipe理器?"

所以我回到了这里,因为它是愚蠢的,它正在扰乱我,我知道了!

在另一个类(在我的应用程序类)把这个代码:

 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)把这个代码放在你的onactivity结果:

 @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中包含的一些数据。 我最初的尝试是把结果意图变成一个全局variables,并用它来创build一个非活动类的媒体投影。 问题是会失败。 我最终想到的是当你用它创build一个媒体投影时所消耗的令牌。 传递它作为参数或分配给一个新的variables只是传递一个指针,它仍然被消耗。

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

我有一个继续运行的服务,所以我宣布一个静态variables内的服务,并使用它时,用户点击我的浮动button(如chatheads)。

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

最后,当用户点击浮动覆盖button时,首先检查数据的值。

  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()的信息; 。