open_toontown_panda3d/direct/src/dist/_android.py

282 lines
10 KiB
Python

"""Internal support module for Android builds."""
import xml.etree.ElementTree as ET
from ._proto.targeting_pb2 import Abi
from ._proto.config_pb2 import BundleConfig # pylint: disable=unused-import
from ._proto.files_pb2 import NativeLibraries # pylint: disable=unused-import
from ._proto.Resources_pb2 import ResourceTable # pylint: disable=unused-import
from ._proto.Resources_pb2 import XmlNode
AbiAlias = Abi.AbiAlias
def str_resource(id):
def compile(attrib, manifest):
attrib.resource_id = id
return compile
def int_resource(id):
def compile(attrib, manifest):
attrib.resource_id = id
if attrib.value.startswith('0x') or attrib.value.startswith('0X'):
attrib.compiled_item.prim.int_hexadecimal_value = int(attrib.value, 16)
else:
attrib.compiled_item.prim.int_decimal_value = int(attrib.value)
return compile
def bool_resource(id):
def compile(attrib, manifest):
attrib.resource_id = id
attrib.compiled_item.prim.boolean_value = {
'true': True, '1': True, 'false': False, '0': False
}[attrib.value]
return compile
def enum_resource(id, *values):
def compile(attrib, manifest):
attrib.resource_id = id
attrib.compiled_item.prim.int_decimal_value = values.index(attrib.value)
return compile
def flag_resource(id, **values):
def compile(attrib, manifest):
attrib.resource_id = id
bitmask = 0
flags = attrib.value.split('|')
for flag in flags:
bitmask = values[flag]
attrib.compiled_item.prim.int_hexadecimal_value = bitmask
return compile
def ref_resource(id):
def compile(attrib, manifest):
assert attrib.value[0] == '@'
ref_type, ref_name = attrib.value[1:].split('/')
attrib.resource_id = id
attrib.compiled_item.ref.name = ref_type + '/' + ref_name
if ref_type == 'android:style':
attrib.compiled_item.ref.id = ANDROID_STYLES[ref_name]
elif ':' not in ref_type:
attrib.compiled_item.ref.id = manifest.register_resource(ref_type, ref_name)
else:
print(f'Warning: unhandled AndroidManifest.xml reference "{attrib.value}"')
return compile
# See data/res/values/public.xml
ANDROID_STYLES = {
'Animation': 0x01030000,
'Animation.Activity': 0x01030001,
'Animation.Dialog': 0x01030002,
'Animation.Translucent': 0x01030003,
'Animation.Toast': 0x01030004,
'Theme': 0x01030005,
'Theme.NoTitleBar': 0x01030006,
'Theme.NoTitleBar.Fullscreen': 0x01030007,
'Theme.Black': 0x01030008,
'Theme.Black.NoTitleBar': 0x01030009,
'Theme.Black.NoTitleBar.Fullscreen': 0x0103000a,
'Theme.Dialog': 0x0103000b,
'Theme.Light': 0x0103000c,
'Theme.Light.NoTitleBar': 0x0103000d,
'Theme.Light.NoTitleBar.Fullscreen': 0x0103000e,
'Theme.Translucent': 0x0103000f,
'Theme.Translucent.NoTitleBar': 0x01030010,
'Theme.Translucent.NoTitleBar.Fullscreen': 0x01030011,
'Widget': 0x01030012,
'Widget.AbsListView': 0x01030013,
'Widget.Button': 0x01030014,
'Widget.Button.Inset': 0x01030015,
'Widget.Button.Small': 0x01030016,
'Widget.Button.Toggle': 0x01030017,
'Widget.CompoundButton': 0x01030018,
'Widget.CompoundButton.CheckBox': 0x01030019,
'Widget.CompoundButton.RadioButton': 0x0103001a,
'Widget.CompoundButton.Star': 0x0103001b,
'Widget.ProgressBar': 0x0103001c,
'Widget.ProgressBar.Large': 0x0103001d,
'Widget.ProgressBar.Small': 0x0103001e,
'Widget.ProgressBar.Horizontal': 0x0103001f,
'Widget.SeekBar': 0x01030020,
'Widget.RatingBar': 0x01030021,
'Widget.TextView': 0x01030022,
'Widget.EditText': 0x01030023,
'Widget.ExpandableListView': 0x01030024,
'Widget.ImageWell': 0x01030025,
'Widget.ImageButton': 0x01030026,
'Widget.AutoCompleteTextView': 0x01030027,
'Widget.Spinner': 0x01030028,
'Widget.TextView.PopupMenu': 0x01030029,
'Widget.TextView.SpinnerItem': 0x0103002a,
'Widget.DropDownItem': 0x0103002b,
'Widget.DropDownItem.Spinner': 0x0103002c,
'Widget.ScrollView': 0x0103002d,
'Widget.ListView': 0x0103002e,
'Widget.ListView.White': 0x0103002f,
'Widget.ListView.DropDown': 0x01030030,
'Widget.ListView.Menu': 0x01030031,
'Widget.GridView': 0x01030032,
'Widget.WebView': 0x01030033,
'Widget.TabWidget': 0x01030034,
'Widget.Gallery': 0x01030035,
'Widget.PopupWindow': 0x01030036,
'MediaButton': 0x01030037,
'MediaButton.Previous': 0x01030038,
'MediaButton.Next': 0x01030039,
'MediaButton.Play': 0x0103003a,
'MediaButton.Ffwd': 0x0103003b,
'MediaButton.Rew': 0x0103003c,
'MediaButton.Pause': 0x0103003d,
'TextAppearance': 0x0103003e,
'TextAppearance.Inverse': 0x0103003f,
'TextAppearance.Theme': 0x01030040,
'TextAppearance.DialogWindowTitle': 0x01030041,
'TextAppearance.Large': 0x01030042,
'TextAppearance.Large.Inverse': 0x01030043,
'TextAppearance.Medium': 0x01030044,
'TextAppearance.Medium.Inverse': 0x01030045,
'TextAppearance.Small': 0x01030046,
'TextAppearance.Small.Inverse': 0x01030047,
'TextAppearance.Theme.Dialog': 0x01030048,
'TextAppearance.Widget': 0x01030049,
'TextAppearance.Widget.Button': 0x0103004a,
'TextAppearance.Widget.IconMenu.Item': 0x0103004b,
'TextAppearance.Widget.EditText': 0x0103004c,
'TextAppearance.Widget.TabWidget': 0x0103004d,
'TextAppearance.Widget.TextView': 0x0103004e,
'TextAppearance.Widget.TextView.PopupMenu': 0x0103004f,
'TextAppearance.Widget.DropDownHint': 0x01030050,
'TextAppearance.Widget.DropDownItem': 0x01030051,
'TextAppearance.Widget.TextView.SpinnerItem': 0x01030052,
'TextAppearance.WindowTitle': 0x01030053,
}
# See data/res/values/public.xml, attrs.xml and especially attrs_manifest.xml
ANDROID_ATTRIBUTES = {
'allowBackup': bool_resource(0x1010280),
'allowClearUserData': bool_resource(0x1010005),
'allowParallelSyncs': bool_resource(0x1010332),
'allowSingleTap': bool_resource(0x1010259),
'allowTaskReparenting': bool_resource(0x1010204),
'alwaysRetainTaskState': bool_resource(0x1010203),
'clearTaskOnLaunch': bool_resource(0x1010015),
'debuggable': bool_resource(0x0101000f),
'documentLaunchMode': enum_resource(0x1010445, "none", "intoExisting", "always", "never"),
'configChanges': flag_resource(0x0101001f, mcc=0x0001, mnc=0x0002, locale=0x0004, touchscreen=0x0008, keyboard=0x0010, keyboardHidden=0x0020, navigation=0x0040, orientation=0x0080, screenLayout=0x0100, uiMode=0x0200, screenSize=0x0400, smallestScreenSize=0x0800, layoutDirection=0x2000, fontScale=0x40000000),
'enabled': bool_resource(0x101000e),
'excludeFromRecents': bool_resource(0x1010017),
'exported': bool_resource(0x1010010),
'extractNativeLibs': bool_resource(0x10104ea),
'finishOnTaskLaunch': bool_resource(0x1010014),
'fullBackupContent': bool_resource(0x10104eb),
'glEsVersion': int_resource(0x1010281),
'hasCode': bool_resource(0x101000c),
'host': str_resource(0x1010028),
'icon': ref_resource(0x1010002),
'immersive': bool_resource(0x10102c0),
'installLocation': enum_resource(0x10102b7, "auto", "internalOnly", "preferExternal"),
'isGame': bool_resource(0x010103f4),
'label': str_resource(0x01010001),
'launchMode': enum_resource(0x101001d, "standard", "singleTop", "singleTask", "singleInstance"),
'maxSdkVersion': int_resource(0x1010271),
'mimeType': str_resource(0x1010026),
'minSdkVersion': int_resource(0x101020c),
'multiprocess': bool_resource(0x1010013),
'name': str_resource(0x1010003),
'noHistory': bool_resource(0x101022d),
'pathPattern': str_resource(0x101002c),
'resizeableActivity': bool_resource(0x10104f6),
'required': bool_resource(0x101028e),
'scheme': str_resource(0x1010027),
'screenOrientation': enum_resource(0x101001e, 'landscape', 'portrait', 'user', 'behind', 'sensor', 'nosensor', 'sensorLandscape', 'sensorPortrait', 'reverseLandscape', 'reversePortrait', 'fullSensor', 'userLandscape', 'userPortrait', 'fullUser', 'locked'),
'stateNotNeeded': bool_resource(0x1010016),
'supportsRtl': bool_resource(0x010103af),
'supportsUploading': bool_resource(0x101029b),
'targetSandboxVersion': int_resource(0x101054c),
'targetSdkVersion': int_resource(0x1010270),
'theme': ref_resource(0x01010000),
'value': str_resource(0x1010024),
'versionCode': int_resource(0x101021b),
'versionName': str_resource(0x101021c),
}
class AndroidManifest:
def __init__(self):
super().__init__()
self._stack = []
self.root = XmlNode()
self.resource_types = []
self.resources = {}
def parse_xml(self, data):
parser = ET.XMLParser(target=self)
parser.feed(data)
parser.close()
def start_ns(self, prefix, uri):
decl = self.root.element.namespace_declaration.add()
decl.prefix = prefix
decl.uri = uri
def start(self, tag, attribs):
if not self._stack:
node = self.root
else:
node = self._stack[-1].child.add()
element = node.element
element.name = tag
self._stack.append(element)
for key, value in attribs.items():
attrib = element.attribute.add()
attrib.value = value
if key.startswith('{'):
attrib.namespace_uri, key = key[1:].split('}', 1)
res_compile = ANDROID_ATTRIBUTES.get(key, None)
if not res_compile:
print(f'Warning: unhandled AndroidManifest.xml attribute "{key}"')
else:
res_compile = None
attrib.name = key
if res_compile:
res_compile(attrib, self)
def end(self, tag):
self._stack.pop()
def register_resource(self, type, name):
if type not in self.resource_types:
self.resource_types.append(type)
type_id = len(self.resource_types)
self.resources[type] = []
else:
type_id = self.resource_types.index(type) + 1
resources = self.resources[type]
if name in resources:
entry_id = resources.index(name)
else:
entry_id = len(resources)
resources.append(name)
id = (0x7f << 24) | (type_id << 16) | (entry_id)
return id
def dumps(self):
return self.root.SerializeToString()