ReviewOS

also looking at this

craft-native/craft

fix(mobile): preserve native editing, navigation, and durable media requests

#369
Merged chris wants to merge codex/native-vertical-scroll-tab-swipes into main
36 files +864 -185

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

packages/android/src/emulator.tsmodified+4-1
Changes to packages/android/src/emulator.ts
@@ -160,9 +160,12 @@ export async function createAndroidEmulator(options: AndroidEmulatorOptions): Pr
160160 // modifying device setup or relaxing native acceptance.
161161 const home = await run([adb, '-s', serial, 'shell', 'cmd', 'package', 'resolve-activity', '--brief', '-a', 'android.intent.action.MAIN', '-c', 'android.intent.category.HOME'], undefined, probeTimeout(), true)
162162 const homeActivity = home.stdout.trim().split(/\r?\n/).at(-1) ?? ''
163 const temporaryHome = homeActivity.startsWith('com.android.sdksetup/')
164 || /^com\.android\.settings\/(?:\.|com\.android\.settings\.)FallbackHome$/.test(homeActivity)
165 || /^android\/.*(?:Resolver|Chooser)Activity$/.test(homeActivity)
163166 booted = settings.code === 0 && packages.code === 0 && systemUi.code === 0 && events.code === 0
164167 && /^package:\/\S+/m.test(packages.stdout) && /^\d+(?:\s+\d+)*$/.test(systemUi.stdout.trim())
165 && home.code === 0 && /^[\w.]+\/[\w.$]+$/.test(homeActivity) && !homeActivity.startsWith('com.android.sdksetup/')
168 && home.code === 0 && /^[\w.]+\/[\w.$]+$/.test(homeActivity) && !temporaryHome
166169 }
167170 }
168171 const checkedAt = Date.now()
packages/typescript/src/__tests__/android-emulator.test.tsmodified+14-2
Changes to packages/typescript/src/__tests__/android-emulator.test.ts
@@ -5,7 +5,7 @@ import { join } from 'node:path'
55import { createAndroidEmulator } from '../../../android/src/emulator'
66import type { AndroidEmulatorOptions } from '../../../android/src/emulator'
77
8function fixture(hardware: boolean, delayedSettings = false, delayedEvents = false, delayedHome = false): { root: string, options: AndroidEmulatorOptions } {
8function fixture(hardware: boolean, delayedSettings = false, delayedEvents = false, delayedHome = false, bootstrapHome = 'com.android.sdksetup/.DefaultActivity'): { root: string, options: AndroidEmulatorOptions } {
99 const root = mkdtempSync(join(tmpdir(), 'craft emulator fixture '))
1010 const sdk = join(root, 'managed sdk')
1111 for (const directory of ['bin', 'platform-tools', 'emulator']) mkdirSync(join(sdk, directory), { recursive: true })
@@ -33,7 +33,7 @@ else
3333 *'cmd package resolve-activity --brief -a android.intent.action.MAIN -c android.intent.category.HOME')
3434 if [ '${delayedHome ? 'yes' : 'no'}' = yes ] && [ ! -f "$ANDROID_HOME/home-ready" ]; then
3535 touch "$ANDROID_HOME/home-ready"
36 printf 'com.android.sdksetup/.DefaultActivity\\n'
36 printf '${bootstrapHome}\\n'
3737 else
3838 printf 'com.android.launcher3/.Launcher\\n'
3939 fi ;;
@@ -135,6 +135,18 @@ test('boot completion waits for the automatic SDK setup activity to release HOME
135135 finally { await session?.dispose(); rmSync(root, { recursive: true, force: true }) }
136136}, 10_000)
137137
138test.each(['com.android.settings/.FallbackHome', 'android/com.android.internal.app.ResolverActivity'])('boot readiness rejects the temporary HOME destination %s', async (bootstrapHome) => {
139 const { root, options } = fixture(true, false, false, true, bootstrapHome)
140 let session: Awaited<ReturnType<typeof createAndroidEmulator>> | undefined
141 try {
142 session = await createAndroidEmulator(options)
143 const trace = readFileSync(join(options.artifactsDirectory, 'device-commands.jsonl'), 'utf8').trim().split('\n').map(line => JSON.parse(line))
144 const home = trace.filter(entry => entry.args.includes('resolve-activity'))
145 expect(home.map(entry => entry.stdout.trim())).toEqual([bootstrapHome, 'com.android.launcher3/.Launcher'])
146 }
147 finally { await session?.dispose(); rmSync(root, { recursive: true, force: true }) }
148}, 10_000)
149
138150test('the SDK process fixture records hardware mode and reaps only its owned process', async () => {
139151 const { root, options } = fixture(true)
140152 options.bootTimeoutMs = 42_000