Skip to content

Support launching activities in full screen mode with ActivityScenario on XR devices #2383

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
**Bug Fixes**

* Downgrade to kotlin 1.9
* Support launching activities in fullscreen mode with ActivityScenario on XR devices

**New Features**

Expand Down
43 changes: 39 additions & 4 deletions core/java/androidx/test/core/app/ActivityScenario.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import android.app.Instrumentation.ActivityResult;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.Property;
import android.os.Build.VERSION;
import android.os.Bundle;
import android.os.Looper;
Expand Down Expand Up @@ -200,7 +202,7 @@ private ActivityScenario(Class<A> activityClass) {
*/
public static <A extends Activity> ActivityScenario<A> launch(Class<A> activityClass) {
ActivityScenario<A> scenario = new ActivityScenario<>(checkNotNull(activityClass));
scenario.launchInternal(/*activityOptions=*/ null, /*launchActivityForResult=*/ false);
scenario.checkXrAndLaunchInternal(/* activityOptions= */ null);
return scenario;
}

Expand All @@ -213,7 +215,7 @@ public static <A extends Activity> ActivityScenario<A> launch(Class<A> activityC
public static <A extends Activity> ActivityScenario<A> launch(
Class<A> activityClass, @Nullable Bundle activityOptions) {
ActivityScenario<A> scenario = new ActivityScenario<>(checkNotNull(activityClass));
scenario.launchInternal(activityOptions, /*launchActivityForResult=*/ false);
scenario.checkXrAndLaunchInternal(activityOptions);
return scenario;
}

Expand All @@ -234,7 +236,7 @@ public static <A extends Activity> ActivityScenario<A> launch(
*/
public static <A extends Activity> ActivityScenario<A> launch(Intent startActivityIntent) {
ActivityScenario<A> scenario = new ActivityScenario<>(checkNotNull(startActivityIntent));
scenario.launchInternal(/*activityOptions=*/ null, /*launchActivityForResult=*/ false);
scenario.checkXrAndLaunchInternal(/* activityOptions= */ null);
return scenario;
}

Expand All @@ -249,7 +251,7 @@ public static <A extends Activity> ActivityScenario<A> launch(Intent startActivi
public static <A extends Activity> ActivityScenario<A> launch(
Intent startActivityIntent, @Nullable Bundle activityOptions) {
ActivityScenario<A> scenario = new ActivityScenario<>(checkNotNull(startActivityIntent));
scenario.launchInternal(activityOptions, /*launchActivityForResult=*/ false);
scenario.checkXrAndLaunchInternal(activityOptions);
return scenario;
}

Expand Down Expand Up @@ -383,6 +385,39 @@ private void launchInternal(@Nullable Bundle activityOptions, boolean launchActi
}
}

/**
* An internal helper method for handling launching the activity for the given scenario instance
* on XR devices.
*
* @param activityOptions activity options bundle to be passed when launching this activity
*/
private void checkXrAndLaunchInternal(@Nullable Bundle activityOptions) {
// Activities cannot be launched in full screen mode from the application context on XR devices.
// Check if the current device is an XR device and fall back to launching activity for result
// if the android.window.PROPERTY_XR_ACTIVITY_START_MODE property is set to full screen mode
// so that the bootstrap activity can act as a temporary focused activity which the requested
// activity is launched from.
PackageManager packageManager = getInstrumentation().getTargetContext().getPackageManager();
if (packageManager.hasSystemFeature("android.software.xr.immersive")) {
String packageName = getInstrumentation().getTargetContext().getPackageName();
try {
Property startMode =
packageManager.getProperty(
"android.window.PROPERTY_XR_ACTIVITY_START_MODE", packageName);
if (startMode.getString().equals("XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED")
|| startMode.getString().equals("XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED")) {
launchInternal(activityOptions, true);
} else {
launchInternal(activityOptions, false);
}
} catch (PackageManager.NameNotFoundException e) {
launchInternal(activityOptions, false);
}
} else {
launchInternal(activityOptions, false);
}
}

/**
* Finishes the managed activity and cleans up device's state. This method blocks execution until
* the activity becomes {@link State#DESTROYED}.
Expand Down
Loading