How to Get Mediaprojectionmanager Without Disturbing the Current Foreground Process, Except to Ask for Permission

How do I get MediaProjectionManager without disturbing the current foreground process, except to ask for permission?

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.

how to take MediaProjectionManager screen caputuring permission for only once instead of each time use?

public void onToggleScreenShare(View view) {
if (((ToggleButton) view).isChecked()) {
if (mMediaProjection == null) {
startActivityForResult(mProjectionManager.createScreenCaptureIntent(), REQUEST_CODE);
} else {
startRecording();
}
} else {
releaseEncoders();
}
}

On this Method startActivityForResult() method prompt screen capturing permission. If grant permission or deny it the code transfer call to onActivityResultMethod()

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

Log.d(TAG, " requestCode " + requestCode + " resultCode " + requestCode);

if (REQUEST_CODE == requestCode) {
if (resultCode == RESULT_OK) {
mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
startRecording(); // defined below
} else {
Log.d(TAG, "Persmission denied");
}
}
}

On this method we get Intent data and resultCode. To further use MediaProjectionManager without requesting continuous permission, we have to save reference of the Intent and value of resultCode and use mediaProjectionManager via this line of code

mMediaProjection = mProjectionManager.getMediaProjection(saveResult, savedIntent);

So it won't request permission again as permission is already granted

Android MediaProjectionManager in Service

I really want to do this from a service, which is how I found this question. This is the closest I've came up, so just throwing this out there, till a better answer comes along. Here's a way to do it from an activity that's almost like doing it from a service:

import static your.package.YourClass.mediaProjectionManager;

public class MainActivity extends Activity {

@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(null);
mediaProjectionManager = (MediaProjectionManager)getContext().getSystemService(MEDIA_PROJECTION_SERVICE);
startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), 1);
}

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

Then in your service when ever you need permission call

private void openMainActivity() {
Intent mainIntent = new Intent(getContext(), MainActivity.class);
mainIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(mainIntent);
}

To make the activity invisible in your AndroidManifest.xml

    <activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoDisplay"
android:excludeFromRecents="true"
android:screenOrientation="portrait">
</activity>

Caveats:

For a brief second the application you're screenshooting will lose focus.

For a brief second your app will be the foreground app, so don't trip over your own shoelaces



Related Topics



Leave a reply



Submit