cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with MediaProjection and permission dialog

vit.hlavacek
Protege

Hi

Im new to oculus development (Oculus Quest 2) and im trying simple app for making screenshots and screen recording. But im having a problem with permission to retrieve MediaProjectionApi

I start activity for result, and the standard android dialog for permission shows but, but without allow/deny buttons, so im stuck.

MediaProjectionPermissionDialogMediaProjectionPermissionDialog

This is the dialog, sorry for the phone pic, but build in screenshot does not show this dialog.
Found simmilar issue here https://github.com/rom1v/sndcpy/issues/75 but no solution either.

My code for showing this dialog. This is in my MainActivity and the testMediaProjectionPermission method is call as onClickListener from a button.

 

ActivityResultLauncher<Intent> resultLauncher =  registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult> () {

@Override
public void onActivityResult(ActivityResult result) {
if(RESULT_OK == result.getResultCode()) {
Log.d(TAG, "Media projection permission granted");
MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
MediaProjection mediaProjection = mediaProjectionManager.getMediaProjection(result.getResultCode(), result.getData());
Log.d(TAG, "Successfully retrieved mediPerojeciton="+mediaProjection);

}
}
});

private void testMediaProjectionPermission(View view) {
MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
resultLauncher.launch(mediaProjectionManager.createScreenCaptureIntent());
}

 

Any advice would be appriciated. Any kind of workaround or another option to record screen other then the build in caster.

1 ACCEPTED SOLUTION

Accepted Solutions

vit.hlavacek
Protege

Figured it out and i have when i hate a question and find bunch of same questions without an answer, so here it is. Hope it helps. 

Propably a bug in oculus android flavor. This dialog does not work from regular activity, but works fine prom VR activity.

So here is my part of android manifest. Notice the ScreenCaptureActivity, with the params, and meta-data inside of it (only for that one activity so it does not affect rest of my app), to launch it as VR / fullscreen.

 

 

 

<meta-data android:name="com.oculus.supportedDevices" android:value="quest2"/>
<activity android:name=".activity.MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity 
    android:name=".activity.ScreenCaptureActivity" 
    android:configChanges="density|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|uiMode" 
    android:launchMode="singleTask" 
    android:resizeableActivity="false" 
    android:screenOrientation="landscape" 
    android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" 
    android:noHistory="false" >
    <intent-filter>
        <action android:name="cz.test.app.SCREEN_CAPTURE" />
        <category android:name="com.oculus.intent.category.VR" />
    </intent-filter>
    <meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
</activity>

 

 

 

And code for my screencapture activity, its fairly simple as well. The main thing is the manifest and launching it as VR

 

 

 

public class ScreenCaptureActivity extends ComponentActivity {
    public static final String TAG = "ScreenCaptureActivity";
    
    
     private final ActivityResultLauncher<Intent> resultLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {

                @Override
                public void onActivityResult(ActivityResult result) {
                    Log.d(TAG, "resultLauncher onActivityResult");
                    if (RESULT_OK == result.getResultCode()) {
                        Log.d(TAG, "Media projection permission granted");
                        MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
                        MediaProjection mediaProjection = mediaProjectionManager.getMediaProjection(result.getResultCode(), result.getData());
                        Log.d(TAG, "Successfully retrieved mediPerojeciton=" + mediaProjection);
                        //TODO pass mediaprojection to service
                        finish();
                    }
                }
            });


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
        resultLauncher.launch(mediaProjectionManager.createScreenCaptureIntent());
    }


}

 

 

 

 

View solution in original post

10 REPLIES 10

vit.hlavacek
Protege

Figured it out and i have when i hate a question and find bunch of same questions without an answer, so here it is. Hope it helps. 

Propably a bug in oculus android flavor. This dialog does not work from regular activity, but works fine prom VR activity.

So here is my part of android manifest. Notice the ScreenCaptureActivity, with the params, and meta-data inside of it (only for that one activity so it does not affect rest of my app), to launch it as VR / fullscreen.

 

 

 

<meta-data android:name="com.oculus.supportedDevices" android:value="quest2"/>
<activity android:name=".activity.MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity 
    android:name=".activity.ScreenCaptureActivity" 
    android:configChanges="density|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|uiMode" 
    android:launchMode="singleTask" 
    android:resizeableActivity="false" 
    android:screenOrientation="landscape" 
    android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" 
    android:noHistory="false" >
    <intent-filter>
        <action android:name="cz.test.app.SCREEN_CAPTURE" />
        <category android:name="com.oculus.intent.category.VR" />
    </intent-filter>
    <meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
</activity>

 

 

 

And code for my screencapture activity, its fairly simple as well. The main thing is the manifest and launching it as VR

 

 

 

public class ScreenCaptureActivity extends ComponentActivity {
    public static final String TAG = "ScreenCaptureActivity";
    
    
     private final ActivityResultLauncher<Intent> resultLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {

                @Override
                public void onActivityResult(ActivityResult result) {
                    Log.d(TAG, "resultLauncher onActivityResult");
                    if (RESULT_OK == result.getResultCode()) {
                        Log.d(TAG, "Media projection permission granted");
                        MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
                        MediaProjection mediaProjection = mediaProjectionManager.getMediaProjection(result.getResultCode(), result.getData());
                        Log.d(TAG, "Successfully retrieved mediPerojeciton=" + mediaProjection);
                        //TODO pass mediaprojection to service
                        finish();
                    }
                }
            });


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
        resultLauncher.launch(mediaProjectionManager.createScreenCaptureIntent());
    }


}

 

 

 

 

Thank you for sharing this information!!!

 

I was very excited to learn these things because I have been trying to get a non-null MediaProjection and I wasn't having any success.  I was about to give up when I found your post.  This fills me with hope.

 

I am lacking in my Android and Java knowledge with primarily a Windows (C++/C#) background; that combined with a multi-minute inner dev loop for just testing out any of these Android specific changes to my project means my process has been a very slow iterative one.  I am determined to get this to work, and expect to be working on it for at least a few more days if not a week as I figure out all of the additional pieces.

 

There are a few visible hurdles that I need to get past next, which I believe you have already solved.  

 

First, I'm dumbfounded about how to even import ComponentActivity.  "import androidx.activity.ComponentActivity;" gives me the package not found error.  And a little searching seems to indicate that this is because of the "androidx" part, and that I need enable this for my project using UPL.  For which I found this article:

How to force the Unreal Engine Android project to use AndroidX? | by Taras Leskiv | nineva | Medium

https://medium.com/nineva/how-to-force-the-unreal-engine-android-project-to-use-androidx-f7060abd56a...

 

But turns out I have already done everything in that article, because I'm using a solution for calling java that already does that:

Sovahero/PluginMobileNativeCode (github.com)

https://github.com/Sovahero/PluginMobileNativeCode

I'm putting my java files in with the plugin's java to simplify my tests.  Still can't figure out I'm still getting this error.

 

But once I figure that out, the next problem is how to get my android manifest to have the activity changes you showed above.  Since the manifest is generated each time, simply changing the one in the intermediate folder does not look like a path forward.  I believe I need to figure out how to use my own UPL for adding that.  

 

 

To get around the error "package androidx.activity does not exist" when I tried to "import androidx.activity.ComponentActivity;" I had to find this file in the plugin code:

\MobileNativeCode\Source\MobileNativeCode\MobileNativeCode_UPL_Android.xml

 

Then add 

implementation "androidx.activity:activity:1.2.0"

under buildGradleAdditions -> insert -> dependencies.  Mine looks like this now:
dependencies {
implementation 'com.google.guava:guava:28.2-android'
implementation "androidx.activity:activity:1.2.0"
}

To get the activity defined in the manifest, if you are using the MobileNativeCode plugin, then in:

\MobileNativeCode\Source\MobileNativeCode\MobileNativeCode_UPL_Android.xml

 

Locate "<!-- Your lines that you want to add to the "application" section -->" and it is as easy as copy and pasting there.  Doesn't look like you need to further convert that to UPL.

vit.hlavacek
Protege

check out https://forums.oculusvr.com/t5/Oculus-Quest-Development/Bug-in-latest-Quest-2-Os-Version-createScree...
They broke screenCapture intent with the latest release for oculus 2, so you dont get stuck on something you cant do anything about

Thanks for pointing that out. 🙂

 

I'm still working to get to the point where an exception is the only problem I have.  The problem I am having now is the app process crashes, or hangs and is then closed automatically?  UE4 Launcher logs don't have a callstack; and my logging indicates that the call to startActivity didn't cause an exception.  I don't know this space well and so I have just been researching and trying various things to try and make progress on it; maybe while the update did break it, there is still a way to get it to work given the right setup.  

From other attempts to capture audio, I tried MediaRecorder (only works for capturing Mic I now believe) and I can get a permissions dialog prompt to appear using Activity's requestPermissions.  I would have thought that they would be using similar mechanisms and so if that one still works perhaps there is still a way.

 

I came across an interesting sample (note: my goal is to capture audio that is being played by UE4's Android Media Player): https://github.com/lincollincol/QRecorder

 

But I'm still can't get my activity to start.  

 

If I keep <category android:name="com.oculus.intent.category.VR" /> in the manifest under the <intent-filter> tag, then my activity isn't found (intent.addCategory("com.oculus.intent.category.VR") doesn't appear to help?), but changing the manifest to use <category android:name="android.intent.category.DEFAULT"/> instead, I avoid the "activity not found" error; no exception is thrown, but my app immediately crashes.  

So I think I am still just stuck on beginner problems related to android and activities and intents and all that jazz.  

Anonymous
Not applicable

I get 

AndroidJavaException: java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/activity/ComponentActivity;
java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/activity/ComponentActivity;
at java.lang.Class.newInstance(Native Method)
at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95)

when starting the ScreenCaptureActivity: 

startActivityForResult(new Intent(this, ScreenCaptureActivity.class), SCREEN_CAPTURE_REQUEST_CODE);

The exception message I get when I do this call:

resultLauncher.launch(mediaProjectionManager.createScreenCaptureIntent());

is:

"unable to find explicit activity class com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity"

Is that the same exception you are getting vit?

 

eusebium, the way I found that got the ScreenCaptureActivity to be created was like this:

 

public static String start(Activity activity)
{
	try
	{
		Intent intent = new Intent(activity, ScreenCaptureActivity.class);
		intent.setAction("SCREEN_CAPTURE");
		activity.startActivity(intent);

		return "start: no exception";
	}
	catch (Exception e)
	{
		return "EXCEPTION: " + e.getMessage();
	}
}

 Please ignore my String return that I'm leveraging for logging.  The activity passed to this function is FJavaWrapper::GameActivityThis that the MobileNativeCode passes in with this call:

FString TestResult = AndroidUtils::CallJavaCode<FString>(
		"com/Plugins/MobileNativeCode/ScreenCaptureActivity",
		"start",
		"",
		true);

 

My activity in my manifest looks like this:

 

      <activity
          android:name="com.Plugins.MobileNativeCode.ScreenCaptureActivity"
          android:configChanges="density|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|uiMode"
          android:launchMode="singleTask"
          android:resizeableActivity="false"
          android:screenOrientation="landscape"
          android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
          android:noHistory="false" >
        <intent-filter>
          <action android:name="SCREEN_CAPTURE" />
          <category android:name="com.oculus.intent.category.VR" />
        </intent-filter>
        <meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
      </activity>

 

I've been taking a few days of vacation this week; so my replies may be delayed.  The exception I mentioned is related to the more recent other thread that vit created.  Sounds like a bug may have been introduced.