mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-06 02:00:19 +02:00
Add LAUNCHER to the real VR activity when only an activity-alias has it
Lepton's apk-info-extractor ignores <activity-alias>, and Godot 4 exports put LAUNCHER only on an alias (com.godot.game.GodotAppLauncher). Open Saber Plus 0.7.67 installed but Lepton exited with 'APP_ACTIVITY is empty'. Count only real activities as launchable and patch the activity's VR intent filter. Verified on the Frame: Open Saber Plus launches and renders. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
35ef3af54b
commit
077eab2b79
2 files changed
+24
-6
No files matched your search
@@ -18,11 +18,11 @@ import frame_android
|
|||||||
from test_frame_apk import pool
|
from test_frame_apk import pool
|
||||||
|
|
||||||
|
|
||||||
def manifest(utf8=False, launcher=False, category=None, samsung=False, split=False):
|
def manifest(utf8=False, launcher=False, category=None, samsung=False, split=False, alias=False):
|
||||||
strings = ['manifest', 'package', 'org.test.vr', 'application', 'activity', 'intent-filter',
|
strings = ['manifest', 'package', 'org.test.vr', 'application', 'activity', 'intent-filter',
|
||||||
'action', 'category', 'name', vr.MAIN, category or next(iter(sorted(vr.VR))),
|
'action', 'category', 'name', vr.MAIN, category or next(iter(sorted(vr.VR))),
|
||||||
vr.LAUNCHER, 'http://schemas.android.com/apk/res/android', 'meta-data', 'value',
|
vr.LAUNCHER, 'http://schemas.android.com/apk/res/android', 'meta-data', 'value',
|
||||||
'com.samsung.android.vr.application.mode', 'vr_only']
|
'com.samsung.android.vr.application.mode', 'vr_only', 'activity-alias']
|
||||||
def start(tag, attrs=()):
|
def start(tag, attrs=()):
|
||||||
body = struct.pack('<IIHHHHHH', 0xffffffff, strings.index(tag), 20, 20, len(attrs), 0, 0, 0)
|
body = struct.pack('<IIHHHHHH', 0xffffffff, strings.index(tag), 20, 20, len(attrs), 0, 0, 0)
|
||||||
for name, value in attrs:
|
for name, value in attrs:
|
||||||
@@ -42,7 +42,12 @@ def manifest(utf8=False, launcher=False, category=None, samsung=False, split=Fal
|
|||||||
b += end('intent-filter') + start('intent-filter')
|
b += end('intent-filter') + start('intent-filter')
|
||||||
if launcher:
|
if launcher:
|
||||||
b += leaf('category', [('name', vr.LAUNCHER)])
|
b += leaf('category', [('name', vr.LAUNCHER)])
|
||||||
b += end('intent-filter') + end('activity') + end('application') + end('manifest')
|
b += end('intent-filter') + end('activity')
|
||||||
|
if alias: # Godot 4: LAUNCHER only on an alias of the VR activity
|
||||||
|
b += start('activity-alias') + start('intent-filter') + leaf('action', [('name', vr.MAIN)])
|
||||||
|
b += leaf('category', [('name', strings[10])]) + leaf('category', [('name', vr.LAUNCHER)])
|
||||||
|
b += end('intent-filter') + end('activity-alias')
|
||||||
|
b += end('application') + end('manifest')
|
||||||
return struct.pack('<HHI', 3, 8, len(b) + 8) + b
|
return struct.pack('<HHI', 3, 8, len(b) + 8) + b
|
||||||
|
|
||||||
|
|
||||||
@@ -74,6 +79,17 @@ class VRTests(unittest.TestCase):
|
|||||||
self.assertFalse(vr.inspect(manifest(launcher=True, split=True))[0]['launchable'])
|
self.assertFalse(vr.inspect(manifest(launcher=True, split=True))[0]['launchable'])
|
||||||
self.assertTrue(vr.inspect(vr.add_launcher_category(manifest(launcher=True, split=True)))[0]['launchable'])
|
self.assertTrue(vr.inspect(vr.add_launcher_category(manifest(launcher=True, split=True)))[0]['launchable'])
|
||||||
|
|
||||||
|
def test_alias_launcher_is_not_enough(self):
|
||||||
|
original = manifest(alias=True)
|
||||||
|
info, filters = vr.inspect(original)
|
||||||
|
self.assertFalse(info['launchable'])
|
||||||
|
self.assertTrue(info['vr_activity'])
|
||||||
|
self.assertEqual(len(filters), 1)
|
||||||
|
result = vr.add_launcher_category(original)
|
||||||
|
info, filters = vr.inspect(result)
|
||||||
|
self.assertTrue(info['launchable'])
|
||||||
|
self.assertIn(vr.LAUNCHER, filters[0]['categories'])
|
||||||
|
|
||||||
def test_styled_pool(self):
|
def test_styled_pool(self):
|
||||||
for utf8 in (False, True):
|
for utf8 in (False, True):
|
||||||
p = bytearray(pool(['styled'], utf8))
|
p = bytearray(pool(['styled'], utf8))
|
||||||
|
|||||||
+5
-3
@@ -16,7 +16,7 @@ def inspect(data):
|
|||||||
tag, attrs = next(elements)
|
tag, attrs = next(elements)
|
||||||
value = attrs.get('name', (None, None, None))[2]
|
value = attrs.get('name', (None, None, None))[2]
|
||||||
if tag == 'intent-filter' and stack and stack[-1] in ('activity', 'activity-alias'):
|
if tag == 'intent-filter' and stack and stack[-1] in ('activity', 'activity-alias'):
|
||||||
current = {'actions': set(), 'categories': set(), 'templates': []}
|
current = {'actions': set(), 'categories': set(), 'templates': [], 'alias': stack[-1] == 'activity-alias'}
|
||||||
if current is not None and stack and stack[-1] == 'intent-filter':
|
if current is not None and stack and stack[-1] == 'intent-filter':
|
||||||
if tag == 'action':
|
if tag == 'action':
|
||||||
current['actions'].add(value)
|
current['actions'].add(value)
|
||||||
@@ -34,8 +34,10 @@ def inspect(data):
|
|||||||
current = None
|
current = None
|
||||||
mains = [f for f in filters if MAIN in f['actions']]
|
mains = [f for f in filters if MAIN in f['actions']]
|
||||||
vr_filters = [f for f in mains if VR & f['categories']]
|
vr_filters = [f for f in mains if VR & f['categories']]
|
||||||
return {'launchable': any(LAUNCHER in f['categories'] for f in mains),
|
# Lepton's apk-info-extractor ignores <activity-alias>; Godot 4 puts LAUNCHER only there.
|
||||||
'vr_activity': bool(vr_filters), 'vr': bool(vr_filters) or samsung}, vr_filters
|
return {'launchable': any(LAUNCHER in f['categories'] for f in mains if not f['alias']),
|
||||||
|
'vr_activity': bool(vr_filters), 'vr': bool(vr_filters) or samsung}, \
|
||||||
|
[f for f in vr_filters if not f['alias']]
|
||||||
|
|
||||||
|
|
||||||
def _append_string(chunk, text):
|
def _append_string(chunk, text):
|
||||||
|
|||||||
Reference in new issue
Block a user