How do I get a media projection manager without disturbing the current foreground process, except to ask for permission?

前端 未结 2 1200
没有蜡笔的小新
没有蜡笔的小新 2020-12-02 11:06

Problem: I have a screenshot app that uses a floating overlay service for controls, and screen cast API Media Project Manager to get access to the screen. Sometimes when a d

相关标签:
2条回答
  • 2020-12-02 11:18

    So I came back to this because it was dumb and it was bugging me, and I figured it out!

    In another class (in mine it's the application class) put this code:

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

    In your activity class handling the initial request (in my case: AcquireScreenshotPermissionIntent) put this code in your 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();
    

    Simply call getScreenShotPermission() whenever you need permission, then use the resulting mediaProjection object.

    Here's how it works: The magic token is some data included in the Intent. What I tried initially was putting the result intent a global variable and using it to create the media projection from a nonactivity class. Problem is it would fail. What I eventually figured out is the token gets consumed when you create a media projection with it. Passing it as an argument or assigning to a new variable just passes a pointer to it, and it still gets consumed.

    What you need to do instead is use object.clone();. This makes a new copy of the token, the new copy gets consumed, and you can create additional tokens as needed, as long as you don't consume the original. As a bonus your app only has to ask for screenshot permission once per launch. If something else takes over the screencast, or the Android memory manager gets you, you're covered. You can create a new virtual screen without sending onPause or onStop events to other apps.

    0 讨论(0)
  • 2020-12-02 11:29

    I have a continues running service so i declared a one static variable inside the service and use it when user click my floating button (like chatheads).

    public static  Intent data = null;  //declaration 
    

    then when first time user open the app I am asking for the permission and setting the value of the data in following way.

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

    Finally when user clicks on the floating Overlay Button, first check value of the data.

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

    Implementation of readPermissionObject is as follows

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

    Thanks to @netsplit for giving info about data.clone(); .

    0 讨论(0)
提交回复
热议问题