mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-10-14 19:27:09 -04:00
81 lines
3.9 KiB
Python
81 lines
3.9 KiB
Python
import argparse
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import time
|
|
from pathlib import Path
|
|
|
|
from adb_device import resolve_serial
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description='Validate immersive DroidDeck XR on a connected Quest')
|
|
parser.add_argument('--adb', default=os.environ.get('ADB', 'adb'))
|
|
parser.add_argument('--serial')
|
|
parser.add_argument('--seconds', type=int, default=20)
|
|
parser.add_argument('--output', type=Path, default=Path('questxr-validation'))
|
|
parser.add_argument('--require-controllers', action='store_true')
|
|
parser.add_argument('--surface', action='store_true')
|
|
parser.add_argument('--guest', action='store_true')
|
|
args = parser.parse_args()
|
|
if args.seconds < 5 or args.seconds > 600:
|
|
parser.error('--seconds must be between 5 and 600')
|
|
serial = resolve_serial(args.adb, args.serial)
|
|
args.output.mkdir(parents=True, exist_ok=True)
|
|
|
|
def adb(*command):
|
|
return subprocess.run([args.adb, '-s', serial, *command], check=True,
|
|
capture_output=True, text=True).stdout
|
|
|
|
package = 'com.droiddeck.launcher' if args.guest else 'com.droiddeck.questxr'
|
|
health_path = f'/sdcard/Android/data/{package}/files/xr-health.json'
|
|
if not args.guest:
|
|
adb('shell', 'am', 'force-stop', package)
|
|
adb('shell', 'rm', '-f', health_path)
|
|
adb('shell', 'input', 'keyevent', 'KEYCODE_WAKEUP')
|
|
adb('shell', 'am', 'broadcast', '-a', 'com.oculus.vrpowermanager.prox_close')
|
|
component = f'{package}/.QuestXrActivity' if args.guest else f'{package}/android.app.NativeActivity'
|
|
launch = ['shell', 'am', 'start', '-n', component]
|
|
if args.surface:
|
|
launch += ['--ez', 'surface_test', 'true']
|
|
if args.guest:
|
|
launch += ['--ez', 'guest_surface', 'true']
|
|
adb(*launch)
|
|
samples = []
|
|
failure = None
|
|
deadline = time.monotonic() + args.seconds
|
|
while time.monotonic() < deadline:
|
|
time.sleep(1)
|
|
adb('shell', 'am', 'broadcast', '-a', 'com.oculus.vrpowermanager.prox_close')
|
|
try:
|
|
sample = json.loads(adb('shell', 'cat', health_path))
|
|
samples.append(sample)
|
|
if sample.get('error'):
|
|
failure = sample['error']
|
|
break
|
|
except (subprocess.CalledProcessError, json.JSONDecodeError):
|
|
pass
|
|
log = adb('logcat', '-d', '-s', 'DroidDeckXR:I', 'OpenXR-Loader:W', 'AndroidRuntime:E')
|
|
(args.output / 'logcat.txt').write_text(log, encoding='utf-8')
|
|
if len(samples) < 2:
|
|
failure = failure or 'No advancing telemetry; check runtime initialization and headset wake/proximity'
|
|
elif samples[-1]['rendered'] - samples[0]['rendered'] < 72:
|
|
failure = failure or 'Fewer than 72 additional stereo frames were submitted'
|
|
elif not any(sample['sessionState'] == 5 and sample['headFlags'] & 3 == 3 for sample in samples):
|
|
failure = failure or 'No focused session with valid position and orientation'
|
|
elif args.require_controllers and not any(all(sample['controllersActive']) for sample in samples):
|
|
failure = failure or 'Both controllers did not become active'
|
|
elif args.guest and samples[-1].get('guestFrames', 0) - samples[0].get('guestFrames', 0) < 72:
|
|
failure = failure or 'No advancing guest GPU presentation; submitting an XR layer alone is insufficient'
|
|
elif samples[-1].get('source') != ('guest' if args.guest else 'surface' if args.surface else 'native'):
|
|
failure = failure or 'Wrong projection source'
|
|
report = {'ok': failure is None, 'error': failure, 'samples': samples}
|
|
(args.output / 'report.json').write_text(json.dumps(report, indent=2), encoding='utf-8')
|
|
print(json.dumps({'ok': report['ok'], 'error': failure, 'samples': len(samples),
|
|
'last': samples[-1] if samples else None}, indent=2))
|
|
return 0 if report['ok'] else 1
|
|
|
|
|
|
if __name__ == '__main__':
|
|
raise SystemExit(main())
|