mirror of
https://github.com/SteamFramelyHomebrew/framely.git
synced 2026-10-29 04:02:47 +01:00
Launch flat APK tasks in fullscreen without restarting games
This commit is contained in:
1 parent
45de17f617
commit
dec35d7529
8 files changed
+156
-21
No files matched your search
+57
-16
@@ -1109,6 +1109,23 @@ fn persistent_registration(c: &Container, expected: &Metadata, log: &Path) -> Re
|
||||
}
|
||||
// Adapt only the entry script in a private temporary file. Keep Lepton's original
|
||||
// libraries and dev-context data handling; app mode can clear existing baked data.
|
||||
fn window_runtime(home: &Path) -> Result<(PathBuf, PathBuf)> {
|
||||
let dir = root(home).join("steam/window-runtime");
|
||||
fs::create_dir_all(&dir)?;
|
||||
let dex = dir.join("framely-window.dex");
|
||||
let script = dir.join("window.sh");
|
||||
steam_shortcuts::write_owned(
|
||||
&dex,
|
||||
include_bytes!("../native/android/framely-window.dex"),
|
||||
0o600,
|
||||
)?;
|
||||
steam_shortcuts::write_owned(
|
||||
&script,
|
||||
include_bytes!("../native/android/window.sh"),
|
||||
0o600,
|
||||
)?;
|
||||
Ok((dex, script))
|
||||
}
|
||||
fn direct_launch_script(source: &str) -> Result<String> {
|
||||
let directory =
|
||||
"SCRIPT_DIR=$( cd -- \"$( dirname -- \"${BASH_SOURCE[0]}\" )\" &> /dev/null && pwd )";
|
||||
@@ -1189,6 +1206,16 @@ if [[ -n "${FRAMELY_SHADER_CACHE_DIR:-}${FRAMELY_EXTERNAL_MEDIA_DIR:-}" ]]; then
|
||||
fi
|
||||
}
|
||||
fi
|
||||
# Per-user readonly helper uses Android's task API, without patching its image.
|
||||
if [[ -n "${FRAMELY_WINDOW_DEX:-}" ]]; then
|
||||
declare -F setup_podman_mounts >/dev/null || { echo "Unsupported Lepton window mounts" >&2; exit 64; }
|
||||
eval "$(declare -f setup_podman_mounts | sed '1s/setup_podman_mounts/framely_original_window_mounts/')"
|
||||
function setup_podman_mounts() {
|
||||
framely_original_window_mounts "$@" || return
|
||||
podman_mount_entry "$FRAMELY_WINDOW_DEX" /vendor/share/framely-window.dex ro
|
||||
podman_mount_entry "${FRAMELY_WINDOW_SCRIPT:?}" /vendor/share/framely-window.sh ro
|
||||
}
|
||||
fi
|
||||
# Optional virtual gamepad: mount only its event node, not host input devices.
|
||||
if [[ -n "${FRAMELY_GAMEPAD_EVENT:-}" ]]; then
|
||||
for hook in setup_podman_mounts generate_zygote_launch_rc; do
|
||||
@@ -1357,6 +1384,9 @@ fn start_oriented_container(
|
||||
"false"
|
||||
},
|
||||
);
|
||||
let (window_dex, window_script) = window_runtime(home)?;
|
||||
cmd.env("FRAMELY_WINDOW_DEX", window_dex)
|
||||
.env("FRAMELY_WINDOW_SCRIPT", window_script);
|
||||
cmd.env_remove("SteamAppId");
|
||||
storage::configure(
|
||||
&mut cmd,
|
||||
@@ -1844,26 +1874,32 @@ fn launch_with_started(c: &Container, a: &App, log: &Path, started: impl FnOnce(
|
||||
if a.show_window.unwrap_or(!a.metadata.vr) {
|
||||
apply_orientation(c, a.orientation.as_deref(), log)?;
|
||||
}
|
||||
let s = podman(
|
||||
&[
|
||||
"exec",
|
||||
&format!("lepton-{}", c.name),
|
||||
"am",
|
||||
"start",
|
||||
"-W",
|
||||
"--user",
|
||||
"0",
|
||||
"-n",
|
||||
&component,
|
||||
],
|
||||
Some(log),
|
||||
)?;
|
||||
let runtime = format!("lepton-{}", c.name);
|
||||
let mut launch_args = vec!["exec"];
|
||||
launch_args.extend([runtime.as_str(), "am", "start", "-W", "--user", "0"]);
|
||||
if a.show_window.unwrap_or(!a.metadata.vr) {
|
||||
launch_args.extend(["--windowingMode", "1"]);
|
||||
}
|
||||
launch_args.extend(["-n", &component]);
|
||||
let s = podman(&launch_args, Some(log))?;
|
||||
ensure!(
|
||||
!s.contains("Error:")
|
||||
&& !s.contains("Exception")
|
||||
&& s.lines().any(|line| line.trim() == "Status: ok"),
|
||||
"Application launch failed: {s}"
|
||||
);
|
||||
if a.show_window.unwrap_or(!a.metadata.vr) {
|
||||
podman(
|
||||
&[
|
||||
"exec",
|
||||
&runtime,
|
||||
"sh",
|
||||
"/vendor/share/framely-window.sh",
|
||||
&a.metadata.package,
|
||||
],
|
||||
Some(log),
|
||||
)?;
|
||||
}
|
||||
// Select the display mode after the requested activity is foreground.
|
||||
// Lepton's per-app HWC mode can create a zero-sized xdg_surface on Gamescope
|
||||
// and abort its display service. Full-display mode avoids that transition;
|
||||
@@ -4388,7 +4424,7 @@ setup_props
|
||||
launch(&c, &a, &log).unwrap();
|
||||
let trace = fs::read_to_string(&commands).unwrap();
|
||||
let start = trace
|
||||
.find("am start -W --user 0 -n com.example.app/")
|
||||
.find("am start -W --user 0 --windowingMode 1 -n com.example.app/")
|
||||
.unwrap();
|
||||
let reveal = trace.find("setprop waydroid.active_apps Waydroid").unwrap();
|
||||
assert!(start < reveal);
|
||||
@@ -4398,6 +4434,9 @@ setup_props
|
||||
assert!(fs::read_to_string(&commands)
|
||||
.unwrap()
|
||||
.contains("setprop waydroid.active_apps none"));
|
||||
assert!(!fs::read_to_string(&commands)
|
||||
.unwrap()
|
||||
.contains("--windowingMode"));
|
||||
fs::write(&commands, "").unwrap();
|
||||
a.show_window = Some(true);
|
||||
fs::write(f.dir.path().join("launch-fail"), "").unwrap();
|
||||
@@ -4998,7 +5037,9 @@ esac
|
||||
assert_eq!(fs::read(&mounted).unwrap(), original);
|
||||
assert!(fs::read_to_string(f.dir.path().join("commands"))
|
||||
.unwrap()
|
||||
.contains("am start -W --user 0 -n com.example.extra/com.example.extra.Main"));
|
||||
.contains(
|
||||
"am start -W --user 0 --windowingMode 1 -n com.example.extra/com.example.extra.Main"
|
||||
));
|
||||
}
|
||||
#[test]
|
||||
fn review_tampering_expiry_and_cancel_are_rejected() {
|
||||
|
||||
+23
-1
@@ -9,6 +9,17 @@ const NATIVE_HOOKS: &str = r#"
|
||||
function is_app_baked() { return 0; }
|
||||
function get_app_mount_dir() { print "${FRAMELY_NATIVE_MOUNT:?}"; }
|
||||
function get_app_activity() { print "${FRAMELY_NATIVE_ACTIVITY:?}"; }
|
||||
# Android may otherwise reuse its desktop/freeform launch preference. Select
|
||||
# fullscreen before creating the activity, rather than resizing it afterwards.
|
||||
function run_app_commands() {
|
||||
local APP_ID="${1:-$(get_app_id)}"
|
||||
local APP_ACTIVITY="${2:-$(get_app_activity)}"
|
||||
if app_wants_flatscreen; then
|
||||
print "am start -S --windowingMode 1 ${APP_ID}/${APP_ACTIVITY} && /system/bin/sh /vendor/share/framely-window.sh ${APP_ID}"
|
||||
else
|
||||
print "am start -S ${APP_ID}/${APP_ACTIVITY}"
|
||||
fi
|
||||
}
|
||||
function get_app_hash() { extract_app_hash; }
|
||||
function get_app_last_depot_version() { extract_app_last_depot_version; }
|
||||
function clear_baked_app_data() { println 'Framely: keeping installed application data'; }
|
||||
@@ -149,7 +160,10 @@ pub(super) fn prepare(
|
||||
c.baked.join("external")
|
||||
};
|
||||
let flat = a.show_window.unwrap_or(!a.metadata.vr);
|
||||
let (window_dex, window_script) = window_runtime(home)?;
|
||||
let mut env = json!({
|
||||
"FRAMELY_WINDOW_DEX": window_dex,
|
||||
"FRAMELY_WINDOW_SCRIPT": window_script,
|
||||
"FRAMELY_LEPTON_DIR":runner.parent().context("Missing Lepton directory")?,
|
||||
"STEAM_COMPAT_DATA_PATH":c.baked.parent().context("Missing application data")?,
|
||||
"FRAMELY_NATIVE_MOUNT":mount,
|
||||
@@ -373,6 +387,7 @@ waitforexitandrun)
|
||||
setup_podman_mounts
|
||||
get_app_mount_dir
|
||||
get_app_activity
|
||||
run_app_commands test.Package test.Selected
|
||||
teardown
|
||||
;;
|
||||
esac
|
||||
@@ -387,7 +402,7 @@ esac
|
||||
let save = data.join("data/test/save");
|
||||
fs::create_dir_all(save.parent().unwrap()).unwrap();
|
||||
fs::write(&save, b"saved game").unwrap();
|
||||
for _ in 0..2 {
|
||||
for flat in [true, false] {
|
||||
let out = Command::new("bash")
|
||||
.arg(&entry)
|
||||
.env("FRAMELY_LEPTON_DIR", lib.parent().unwrap())
|
||||
@@ -397,6 +412,7 @@ esac
|
||||
.env("FRAMELY_NATIVE_LAUNCH", "true")
|
||||
.env("FRAMELY_NATIVE_MOUNT", "/data/app/test")
|
||||
.env("FRAMELY_NATIVE_ACTIVITY", "test.Selected")
|
||||
.env("APP_WANTS_FLATSCREEN", if flat { "true" } else { "false" })
|
||||
.env("TEST_DATA", &data)
|
||||
.env("TEST_PROPS", t.path().join("props"))
|
||||
.output()
|
||||
@@ -407,6 +423,12 @@ esac
|
||||
String::from_utf8_lossy(&out.stderr)
|
||||
);
|
||||
assert!(String::from_utf8_lossy(&out.stdout).contains("test.Selected"));
|
||||
let expected = if flat {
|
||||
"am start -S --windowingMode 1 test.Package/test.Selected"
|
||||
} else {
|
||||
"am start -S test.Package/test.Selected"
|
||||
};
|
||||
assert!(String::from_utf8_lossy(&out.stdout).contains(expected));
|
||||
assert_eq!(fs::read(&save).unwrap(), b"saved game");
|
||||
assert_eq!(fs::read(&download).unwrap(), b"resume-me");
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user