mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-30 21:23:04 +00:00
fix(app): allow Android tablets to rotate
Choose the orientation before the first activity frame, and update it when the available screen size changes. Co-authored-by: yz <43207690+yzim@users.noreply.github.com> Co-authored-by: magiclaw <930198090@qq.com>
This commit is contained in:
co-authored by
yz
magiclaw
parent
4351445467
commit
b678e122d5
@@ -1,3 +1,4 @@
|
||||
const withAndroidOrientation = require("./plugins/with-android-orientation");
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
const pkg = require("./package.json");
|
||||
@@ -142,6 +143,7 @@ export default {
|
||||
searchPaths: ["../../node_modules", "./node_modules"],
|
||||
},
|
||||
plugins: [
|
||||
withAndroidOrientation,
|
||||
"expo-router",
|
||||
withPasteInput,
|
||||
withAndroidScroll,
|
||||
|
||||
@@ -59,3 +59,52 @@ describe("Android app config", () => {
|
||||
30_000,
|
||||
);
|
||||
});
|
||||
|
||||
it("allows Android tablets to rotate without a portrait manifest lock", 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");
|
||||
}, 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" });
|
||||
const result = await config.mods.android.mainActivity({
|
||||
modRequest: {},
|
||||
modResults: {
|
||||
language: "kt",
|
||||
contents:
|
||||
"class MainActivity {\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(null)\n }\n}",
|
||||
},
|
||||
});
|
||||
expect(result.modResults.contents).toContain("smallestScreenWidthDp >= 600");
|
||||
expect(result.modResults.contents).toContain("SCREEN_ORIENTATION_UNSPECIFIED");
|
||||
expect(result.modResults.contents).toContain("SCREEN_ORIENTATION_PORTRAIT");
|
||||
expect(result.modResults.contents).toContain(
|
||||
"updateOrientation(resources.configuration)\n super.onCreate(null)",
|
||||
);
|
||||
expect(result.modResults.contents).toContain("updateOrientation(newConfig)");
|
||||
});
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
const { withAndroidManifest, withMainActivity, withDangerousMod } = require("expo/config-plugins");
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
|
||||
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) => {
|
||||
const activity = mod.modResults;
|
||||
if (activity.language !== "kt") throw new Error("Expected Kotlin MainActivity");
|
||||
const marker = " // Paseo orientation policy";
|
||||
if (!activity.contents.includes(marker)) {
|
||||
const anchor = " override fun onCreate(savedInstanceState: Bundle?)";
|
||||
if (!activity.contents.includes(anchor)) throw new Error("MainActivity anchor missing");
|
||||
activity.contents = activity.contents.replace(
|
||||
anchor,
|
||||
`${marker}
|
||||
private fun updateOrientation(configuration: android.content.res.Configuration) {
|
||||
val orientation = if (configuration.smallestScreenWidthDp >= 600)
|
||||
android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
||||
else
|
||||
android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
if (requestedOrientation != orientation) requestedOrientation = orientation
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: android.content.res.Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
updateOrientation(newConfig)
|
||||
}
|
||||
|
||||
${anchor}`,
|
||||
);
|
||||
if (!activity.contents.includes(" super.onCreate(null)"))
|
||||
throw new Error("MainActivity onCreate missing");
|
||||
activity.contents = activity.contents.replace(
|
||||
" super.onCreate(null)",
|
||||
" updateOrientation(resources.configuration)\n super.onCreate(null)",
|
||||
);
|
||||
}
|
||||
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;
|
||||
},
|
||||
]);
|
||||
};
|
||||
Reference in New Issue
Block a user