fix(app): keep tablet orientation policy in activity

Android resolves manifest resources without screen size qualifiers, so preserve the portrait declaration and unlock tablets when the activity starts.
This commit is contained in:
Mohamed Boudra
2026-10-30 03:50:14 +01:00
parent b678e122d5
commit 15635531c6
2 changed files with 4 additions and 54 deletions
+2 -23
View File
@@ -60,35 +60,14 @@ describe("Android app config", () => {
);
});
it("allows Android tablets to rotate without a portrait manifest lock", async () => {
it("keeps the Android manifest portrait for phone startup", async () => {
const manifest = await resolveAndroidManifest();
const activity = manifest.application[0].activity.find(
(entry: ManifestEntry) => entry.$["android:name"] === ".MainActivity",
);
expect(activity.$["android:screenOrientation"]).toBe("@integer/paseo_orientation");
expect(activity.$["android:screenOrientation"]).toBe("portrait");
}, 30_000);
it("generates portrait phone and unrestricted tablet orientation resources", async () => {
const { mkdtemp, readFile, rm } = await import("node:fs/promises");
const { tmpdir } = await import("node:os");
const { join } = await import("node:path");
const root = await mkdtemp(join(tmpdir(), "paseo-orientation-"));
try {
const plugin = createRequire(import.meta.url)("./plugins/with-android-orientation.js");
const config = plugin({ name: "test", slug: "test" });
await config.mods.android.dangerous({
modRequest: { platformProjectRoot: root },
modResults: {},
});
const resource = (directory: string) =>
readFile(join(root, "app/src/main/res", directory, "paseo_orientation.xml"), "utf8");
expect(await resource("values")).toContain('name="paseo_orientation">1</integer>');
expect(await resource("values-sw600dp")).toContain('name="paseo_orientation">-1</integer>');
} finally {
await rm(root, { recursive: true, force: true });
}
});
it("updates the native orientation before launch and when screen size changes", async () => {
const plugin = createRequire(import.meta.url)("./plugins/with-android-orientation.js");
const config = plugin({ name: "test", slug: "test" });
@@ -1,17 +1,7 @@
const { withAndroidManifest, withMainActivity, withDangerousMod } = require("expo/config-plugins");
const fs = require("node:fs");
const path = require("node:path");
const { withMainActivity } = require("expo/config-plugins");
module.exports = function withAndroidOrientation(config) {
// The manifest locks phones before the first activity frame. Tablets start unlocked.
config = withAndroidManifest(config, (mod) => {
const activity = mod.modResults.manifest.application[0].activity.find(
(item) => item.$["android:name"] === ".MainActivity",
);
activity.$["android:screenOrientation"] = "@integer/paseo_orientation";
return mod;
});
config = withMainActivity(config, (mod) => {
return withMainActivity(config, (mod) => {
const activity = mod.modResults;
if (activity.language !== "kt") throw new Error("Expected Kotlin MainActivity");
const marker = " // Paseo orientation policy";
@@ -45,23 +35,4 @@ ${anchor}`,
}
return mod;
});
return withDangerousMod(config, [
"android",
async (mod) => {
const res = path.join(mod.modRequest.platformProjectRoot, "app/src/main/res");
// ActivityInfo uses 1 for portrait and -1 for unspecified.
for (const [dir, value] of [
["values", "1"],
["values-sw600dp", "-1"],
]) {
const target = path.join(res, dir);
fs.mkdirSync(target, { recursive: true });
fs.writeFileSync(
path.join(target, "paseo_orientation.xml"),
`<resources><integer name="paseo_orientation">${value}</integer></resources>\n`,
);
}
return mod;
},
]);
};