2525import android .app .Instrumentation .ActivityResult ;
2626import android .content .ComponentName ;
2727import android .content .Intent ;
28+ import android .content .pm .PackageManager ;
29+ import android .content .pm .PackageManager .Property ;
2830import android .os .Build .VERSION ;
2931import android .os .Bundle ;
3032import android .os .Looper ;
@@ -200,7 +202,7 @@ private ActivityScenario(Class<A> activityClass) {
200202 */
201203 public static <A extends Activity > ActivityScenario <A > launch (Class <A > activityClass ) {
202204 ActivityScenario <A > scenario = new ActivityScenario <>(checkNotNull (activityClass ));
203- scenario .launchInternal (/*activityOptions=*/ null , /*launchActivityForResult=*/ false );
205+ scenario .checkXrAndLaunchInternal (/* activityOptions= */ null );
204206 return scenario ;
205207 }
206208
@@ -213,7 +215,7 @@ public static <A extends Activity> ActivityScenario<A> launch(Class<A> activityC
213215 public static <A extends Activity > ActivityScenario <A > launch (
214216 Class <A > activityClass , @ Nullable Bundle activityOptions ) {
215217 ActivityScenario <A > scenario = new ActivityScenario <>(checkNotNull (activityClass ));
216- scenario .launchInternal (activityOptions , /*launchActivityForResult=*/ false );
218+ scenario .checkXrAndLaunchInternal (activityOptions );
217219 return scenario ;
218220 }
219221
@@ -234,7 +236,7 @@ public static <A extends Activity> ActivityScenario<A> launch(
234236 */
235237 public static <A extends Activity > ActivityScenario <A > launch (Intent startActivityIntent ) {
236238 ActivityScenario <A > scenario = new ActivityScenario <>(checkNotNull (startActivityIntent ));
237- scenario .launchInternal (/*activityOptions=*/ null , /*launchActivityForResult=*/ false );
239+ scenario .checkXrAndLaunchInternal (/* activityOptions= */ null );
238240 return scenario ;
239241 }
240242
@@ -249,7 +251,7 @@ public static <A extends Activity> ActivityScenario<A> launch(Intent startActivi
249251 public static <A extends Activity > ActivityScenario <A > launch (
250252 Intent startActivityIntent , @ Nullable Bundle activityOptions ) {
251253 ActivityScenario <A > scenario = new ActivityScenario <>(checkNotNull (startActivityIntent ));
252- scenario .launchInternal (activityOptions , /*launchActivityForResult=*/ false );
254+ scenario .checkXrAndLaunchInternal (activityOptions );
253255 return scenario ;
254256 }
255257
@@ -383,6 +385,39 @@ private void launchInternal(@Nullable Bundle activityOptions, boolean launchActi
383385 }
384386 }
385387
388+ /**
389+ * An internal helper method for handling launching the activity for the given scenario instance
390+ * on XR devices.
391+ *
392+ * @param activityOptions activity options bundle to be passed when launching this activity
393+ */
394+ private void checkXrAndLaunchInternal (@ Nullable Bundle activityOptions ) {
395+ // Activities cannot be launched in full screen mode from the application context on XR devices.
396+ // Check if the current device is an XR device and fall back to launching activity for result
397+ // if the android.window.PROPERTY_XR_ACTIVITY_START_MODE property is set to full screen mode
398+ // so that the bootstrap activity can act as a temporary focused activity which the requested
399+ // activity is launched from.
400+ PackageManager packageManager = getInstrumentation ().getTargetContext ().getPackageManager ();
401+ if (packageManager .hasSystemFeature ("android.software.xr.immersive" )) {
402+ String packageName = getInstrumentation ().getTargetContext ().getPackageName ();
403+ try {
404+ Property startMode =
405+ packageManager .getProperty (
406+ "android.window.PROPERTY_XR_ACTIVITY_START_MODE" , packageName );
407+ if (startMode .getString ().equals ("XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED" )
408+ || startMode .getString ().equals ("XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED" )) {
409+ launchInternal (activityOptions , true );
410+ } else {
411+ launchInternal (activityOptions , false );
412+ }
413+ } catch (PackageManager .NameNotFoundException e ) {
414+ launchInternal (activityOptions , false );
415+ }
416+ } else {
417+ launchInternal (activityOptions , false );
418+ }
419+ }
420+
386421 /**
387422 * Finishes the managed activity and cleans up device's state. This method blocks execution until
388423 * the activity becomes {@link State#DESTROYED}.
0 commit comments