Support deploying Python apps for Android using bdist_apps

This commit is contained in:
rdb 2021-12-07 21:00:08 +01:00
parent 4c7e513dfd
commit 44e10d10a0
17 changed files with 7892 additions and 54 deletions

View File

@ -1835,7 +1835,7 @@ class Freezer:
# If it is a submodule of a frozen module, Python will have
# trouble importing it as a builtin module. Synthesize a frozen
# module that loads it dynamically.
if '.' in moduleName:
if '.' in moduleName and not self.platform.startswith('android'):
if self.platform.startswith("macosx") and not use_console:
# We write the Frameworks directory to sys.path[0].
code = 'import sys;del sys.modules["%s"];import sys,os,imp;imp.load_dynamic("%s",os.path.join(sys.path[0], "%s%s"))' % (moduleName, moduleName, moduleName, modext)

250
direct/src/dist/_android.py vendored Normal file
View File

@ -0,0 +1,250 @@
"""Internal support module for Android builds."""
import xml.etree.ElementTree as ET
from ._proto.targeting_pb2 import Abi
from ._proto.config_pb2 import BundleConfig
from ._proto.files_pb2 import NativeLibraries
from ._proto.Resources_pb2 import XmlNode, ResourceTable
AbiAlias = Abi.AbiAlias
def str_resource(id):
def compile(attrib):
attrib.resource_id = id
return compile
def int_resource(id):
def compile(attrib):
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):
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):
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):
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, type):
def compile(attrib):
assert attrib.value[0] == '@'
ref_type, ref_name = attrib.value[1:].split('/')
attrib.resource_id = id
if ref_type == 'android:style':
attrib.compiled_item.ref.id = ANDROID_STYLES[ref_name]
attrib.compiled_item.ref.name = 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),
'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),
'extractNativeLibs': bool_resource(0x10104ea),
'finishOnTaskLaunch': bool_resource(0x1010014),
'fullBackupContent': bool_resource(0x10104eb),
'glEsVersion': int_resource(0x1010281),
'hasCode': bool_resource(0x101000c),
'host': str_resource(0x1010028),
'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),
'pathPattern': str_resource(0x101002c),
'required': bool_resource(0x101028e),
'scheme': str_resource(0x1010027),
'stateNotNeeded': bool_resource(0x1010016),
'supportsUploading': bool_resource(0x101029b),
'targetSandboxVersion': int_resource(0x101054c),
'targetSdkVersion': int_resource(0x1010270),
'theme': ref_resource(0x01010000, 'android:style'),
'value': str_resource(0x1010024),
'versionCode': int_resource(0x101021b),
'versionName': str_resource(0x101021c),
}
class AndroidManifest:
def __init__(self):
super().__init__()
self._stack = []
self.root = XmlNode()
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)
def end(self, tag):
self._stack.pop()
def dumps(self):
return self.root.SerializeToString()

View File

@ -0,0 +1,766 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: frameworks/base/tools/aapt2/Configuration.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='frameworks/base/tools/aapt2/Configuration.proto',
package='aapt.pb',
syntax='proto3',
serialized_options=b'\n\020com.android.aapt',
create_key=_descriptor._internal_create_key,
serialized_pb=b'\n/frameworks/base/tools/aapt2/Configuration.proto\x12\x07\x61\x61pt.pb\"\xd9\x14\n\rConfiguration\x12\x0b\n\x03mcc\x18\x01 \x01(\r\x12\x0b\n\x03mnc\x18\x02 \x01(\r\x12\x0e\n\x06locale\x18\x03 \x01(\t\x12@\n\x10layout_direction\x18\x04 \x01(\x0e\x32&.aapt.pb.Configuration.LayoutDirection\x12\x14\n\x0cscreen_width\x18\x05 \x01(\r\x12\x15\n\rscreen_height\x18\x06 \x01(\r\x12\x17\n\x0fscreen_width_dp\x18\x07 \x01(\r\x12\x18\n\x10screen_height_dp\x18\x08 \x01(\r\x12 \n\x18smallest_screen_width_dp\x18\t \x01(\r\x12\x43\n\x12screen_layout_size\x18\n \x01(\x0e\x32\'.aapt.pb.Configuration.ScreenLayoutSize\x12\x43\n\x12screen_layout_long\x18\x0b \x01(\x0e\x32\'.aapt.pb.Configuration.ScreenLayoutLong\x12\x38\n\x0cscreen_round\x18\x0c \x01(\x0e\x32\".aapt.pb.Configuration.ScreenRound\x12?\n\x10wide_color_gamut\x18\r \x01(\x0e\x32%.aapt.pb.Configuration.WideColorGamut\x12\'\n\x03hdr\x18\x0e \x01(\x0e\x32\x1a.aapt.pb.Configuration.Hdr\x12\x37\n\x0borientation\x18\x0f \x01(\x0e\x32\".aapt.pb.Configuration.Orientation\x12\x37\n\x0cui_mode_type\x18\x10 \x01(\x0e\x32!.aapt.pb.Configuration.UiModeType\x12\x39\n\rui_mode_night\x18\x11 \x01(\x0e\x32\".aapt.pb.Configuration.UiModeNight\x12\x0f\n\x07\x64\x65nsity\x18\x12 \x01(\r\x12\x37\n\x0btouchscreen\x18\x13 \x01(\x0e\x32\".aapt.pb.Configuration.Touchscreen\x12\x36\n\x0bkeys_hidden\x18\x14 \x01(\x0e\x32!.aapt.pb.Configuration.KeysHidden\x12\x31\n\x08keyboard\x18\x15 \x01(\x0e\x32\x1f.aapt.pb.Configuration.Keyboard\x12\x34\n\nnav_hidden\x18\x16 \x01(\x0e\x32 .aapt.pb.Configuration.NavHidden\x12\x35\n\nnavigation\x18\x17 \x01(\x0e\x32!.aapt.pb.Configuration.Navigation\x12\x13\n\x0bsdk_version\x18\x18 \x01(\r\x12\x0f\n\x07product\x18\x19 \x01(\t\"a\n\x0fLayoutDirection\x12\x1a\n\x16LAYOUT_DIRECTION_UNSET\x10\x00\x12\x18\n\x14LAYOUT_DIRECTION_LTR\x10\x01\x12\x18\n\x14LAYOUT_DIRECTION_RTL\x10\x02\"\xaa\x01\n\x10ScreenLayoutSize\x12\x1c\n\x18SCREEN_LAYOUT_SIZE_UNSET\x10\x00\x12\x1c\n\x18SCREEN_LAYOUT_SIZE_SMALL\x10\x01\x12\x1d\n\x19SCREEN_LAYOUT_SIZE_NORMAL\x10\x02\x12\x1c\n\x18SCREEN_LAYOUT_SIZE_LARGE\x10\x03\x12\x1d\n\x19SCREEN_LAYOUT_SIZE_XLARGE\x10\x04\"m\n\x10ScreenLayoutLong\x12\x1c\n\x18SCREEN_LAYOUT_LONG_UNSET\x10\x00\x12\x1b\n\x17SCREEN_LAYOUT_LONG_LONG\x10\x01\x12\x1e\n\x1aSCREEN_LAYOUT_LONG_NOTLONG\x10\x02\"X\n\x0bScreenRound\x12\x16\n\x12SCREEN_ROUND_UNSET\x10\x00\x12\x16\n\x12SCREEN_ROUND_ROUND\x10\x01\x12\x19\n\x15SCREEN_ROUND_NOTROUND\x10\x02\"h\n\x0eWideColorGamut\x12\x1a\n\x16WIDE_COLOR_GAMUT_UNSET\x10\x00\x12\x1b\n\x17WIDE_COLOR_GAMUT_WIDECG\x10\x01\x12\x1d\n\x19WIDE_COLOR_GAMUT_NOWIDECG\x10\x02\"3\n\x03Hdr\x12\r\n\tHDR_UNSET\x10\x00\x12\x0e\n\nHDR_HIGHDR\x10\x01\x12\r\n\tHDR_LOWDR\x10\x02\"h\n\x0bOrientation\x12\x15\n\x11ORIENTATION_UNSET\x10\x00\x12\x14\n\x10ORIENTATION_PORT\x10\x01\x12\x14\n\x10ORIENTATION_LAND\x10\x02\x12\x16\n\x12ORIENTATION_SQUARE\x10\x03\"\xd7\x01\n\nUiModeType\x12\x16\n\x12UI_MODE_TYPE_UNSET\x10\x00\x12\x17\n\x13UI_MODE_TYPE_NORMAL\x10\x01\x12\x15\n\x11UI_MODE_TYPE_DESK\x10\x02\x12\x14\n\x10UI_MODE_TYPE_CAR\x10\x03\x12\x1b\n\x17UI_MODE_TYPE_TELEVISION\x10\x04\x12\x1a\n\x16UI_MODE_TYPE_APPLIANCE\x10\x05\x12\x16\n\x12UI_MODE_TYPE_WATCH\x10\x06\x12\x1a\n\x16UI_MODE_TYPE_VRHEADSET\x10\x07\"[\n\x0bUiModeNight\x12\x17\n\x13UI_MODE_NIGHT_UNSET\x10\x00\x12\x17\n\x13UI_MODE_NIGHT_NIGHT\x10\x01\x12\x1a\n\x16UI_MODE_NIGHT_NOTNIGHT\x10\x02\"m\n\x0bTouchscreen\x12\x15\n\x11TOUCHSCREEN_UNSET\x10\x00\x12\x17\n\x13TOUCHSCREEN_NOTOUCH\x10\x01\x12\x16\n\x12TOUCHSCREEN_STYLUS\x10\x02\x12\x16\n\x12TOUCHSCREEN_FINGER\x10\x03\"v\n\nKeysHidden\x12\x15\n\x11KEYS_HIDDEN_UNSET\x10\x00\x12\x1b\n\x17KEYS_HIDDEN_KEYSEXPOSED\x10\x01\x12\x1a\n\x16KEYS_HIDDEN_KEYSHIDDEN\x10\x02\x12\x18\n\x14KEYS_HIDDEN_KEYSSOFT\x10\x03\"`\n\x08Keyboard\x12\x12\n\x0eKEYBOARD_UNSET\x10\x00\x12\x13\n\x0fKEYBOARD_NOKEYS\x10\x01\x12\x13\n\x0fKEYBOARD_QWERTY\x10\x02\x12\x16\n\x12KEYBOARD_TWELVEKEY\x10\x03\"V\n\tNavHidden\x12\x14\n\x10NAV_HIDDEN_UNSET\x10\x00\x12\x19\n\x15NAV_HIDDEN_NAVEXPOSED\x10\x01\x12\x18\n\x14NAV_HIDDEN_NAVHIDDEN\x10\x02\"}\n\nNavigation\x12\x14\n\x10NAVIGATION_UNSET\x10\x00\x12\x14\n\x10NAVIGATION_NONAV\x10\x01\x12\x13\n\x0fNAVIGATION_DPAD\x10\x02\x12\x18\n\x14NAVIGATION_TRACKBALL\x10\x03\x12\x14\n\x10NAVIGATION_WHEEL\x10\x04\x42\x12\n\x10\x63om.android.aaptb\x06proto3'
)
_CONFIGURATION_LAYOUTDIRECTION = _descriptor.EnumDescriptor(
name='LayoutDirection',
full_name='aapt.pb.Configuration.LayoutDirection',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='LAYOUT_DIRECTION_UNSET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='LAYOUT_DIRECTION_LTR', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='LAYOUT_DIRECTION_RTL', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=1119,
serialized_end=1216,
)
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_LAYOUTDIRECTION)
_CONFIGURATION_SCREENLAYOUTSIZE = _descriptor.EnumDescriptor(
name='ScreenLayoutSize',
full_name='aapt.pb.Configuration.ScreenLayoutSize',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='SCREEN_LAYOUT_SIZE_UNSET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='SCREEN_LAYOUT_SIZE_SMALL', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='SCREEN_LAYOUT_SIZE_NORMAL', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='SCREEN_LAYOUT_SIZE_LARGE', index=3, number=3,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='SCREEN_LAYOUT_SIZE_XLARGE', index=4, number=4,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=1219,
serialized_end=1389,
)
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_SCREENLAYOUTSIZE)
_CONFIGURATION_SCREENLAYOUTLONG = _descriptor.EnumDescriptor(
name='ScreenLayoutLong',
full_name='aapt.pb.Configuration.ScreenLayoutLong',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='SCREEN_LAYOUT_LONG_UNSET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='SCREEN_LAYOUT_LONG_LONG', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='SCREEN_LAYOUT_LONG_NOTLONG', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=1391,
serialized_end=1500,
)
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_SCREENLAYOUTLONG)
_CONFIGURATION_SCREENROUND = _descriptor.EnumDescriptor(
name='ScreenRound',
full_name='aapt.pb.Configuration.ScreenRound',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='SCREEN_ROUND_UNSET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='SCREEN_ROUND_ROUND', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='SCREEN_ROUND_NOTROUND', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=1502,
serialized_end=1590,
)
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_SCREENROUND)
_CONFIGURATION_WIDECOLORGAMUT = _descriptor.EnumDescriptor(
name='WideColorGamut',
full_name='aapt.pb.Configuration.WideColorGamut',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='WIDE_COLOR_GAMUT_UNSET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='WIDE_COLOR_GAMUT_WIDECG', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='WIDE_COLOR_GAMUT_NOWIDECG', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=1592,
serialized_end=1696,
)
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_WIDECOLORGAMUT)
_CONFIGURATION_HDR = _descriptor.EnumDescriptor(
name='Hdr',
full_name='aapt.pb.Configuration.Hdr',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='HDR_UNSET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='HDR_HIGHDR', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='HDR_LOWDR', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=1698,
serialized_end=1749,
)
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_HDR)
_CONFIGURATION_ORIENTATION = _descriptor.EnumDescriptor(
name='Orientation',
full_name='aapt.pb.Configuration.Orientation',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='ORIENTATION_UNSET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='ORIENTATION_PORT', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='ORIENTATION_LAND', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='ORIENTATION_SQUARE', index=3, number=3,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=1751,
serialized_end=1855,
)
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_ORIENTATION)
_CONFIGURATION_UIMODETYPE = _descriptor.EnumDescriptor(
name='UiModeType',
full_name='aapt.pb.Configuration.UiModeType',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='UI_MODE_TYPE_UNSET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='UI_MODE_TYPE_NORMAL', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='UI_MODE_TYPE_DESK', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='UI_MODE_TYPE_CAR', index=3, number=3,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='UI_MODE_TYPE_TELEVISION', index=4, number=4,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='UI_MODE_TYPE_APPLIANCE', index=5, number=5,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='UI_MODE_TYPE_WATCH', index=6, number=6,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='UI_MODE_TYPE_VRHEADSET', index=7, number=7,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=1858,
serialized_end=2073,
)
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_UIMODETYPE)
_CONFIGURATION_UIMODENIGHT = _descriptor.EnumDescriptor(
name='UiModeNight',
full_name='aapt.pb.Configuration.UiModeNight',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='UI_MODE_NIGHT_UNSET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='UI_MODE_NIGHT_NIGHT', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='UI_MODE_NIGHT_NOTNIGHT', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=2075,
serialized_end=2166,
)
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_UIMODENIGHT)
_CONFIGURATION_TOUCHSCREEN = _descriptor.EnumDescriptor(
name='Touchscreen',
full_name='aapt.pb.Configuration.Touchscreen',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='TOUCHSCREEN_UNSET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='TOUCHSCREEN_NOTOUCH', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='TOUCHSCREEN_STYLUS', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='TOUCHSCREEN_FINGER', index=3, number=3,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=2168,
serialized_end=2277,
)
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_TOUCHSCREEN)
_CONFIGURATION_KEYSHIDDEN = _descriptor.EnumDescriptor(
name='KeysHidden',
full_name='aapt.pb.Configuration.KeysHidden',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='KEYS_HIDDEN_UNSET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='KEYS_HIDDEN_KEYSEXPOSED', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='KEYS_HIDDEN_KEYSHIDDEN', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='KEYS_HIDDEN_KEYSSOFT', index=3, number=3,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=2279,
serialized_end=2397,
)
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_KEYSHIDDEN)
_CONFIGURATION_KEYBOARD = _descriptor.EnumDescriptor(
name='Keyboard',
full_name='aapt.pb.Configuration.Keyboard',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='KEYBOARD_UNSET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='KEYBOARD_NOKEYS', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='KEYBOARD_QWERTY', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='KEYBOARD_TWELVEKEY', index=3, number=3,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=2399,
serialized_end=2495,
)
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_KEYBOARD)
_CONFIGURATION_NAVHIDDEN = _descriptor.EnumDescriptor(
name='NavHidden',
full_name='aapt.pb.Configuration.NavHidden',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='NAV_HIDDEN_UNSET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='NAV_HIDDEN_NAVEXPOSED', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='NAV_HIDDEN_NAVHIDDEN', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=2497,
serialized_end=2583,
)
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_NAVHIDDEN)
_CONFIGURATION_NAVIGATION = _descriptor.EnumDescriptor(
name='Navigation',
full_name='aapt.pb.Configuration.Navigation',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='NAVIGATION_UNSET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='NAVIGATION_NONAV', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='NAVIGATION_DPAD', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='NAVIGATION_TRACKBALL', index=3, number=3,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='NAVIGATION_WHEEL', index=4, number=4,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=2585,
serialized_end=2710,
)
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_NAVIGATION)
_CONFIGURATION = _descriptor.Descriptor(
name='Configuration',
full_name='aapt.pb.Configuration',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='mcc', full_name='aapt.pb.Configuration.mcc', index=0,
number=1, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='mnc', full_name='aapt.pb.Configuration.mnc', index=1,
number=2, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='locale', full_name='aapt.pb.Configuration.locale', index=2,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='layout_direction', full_name='aapt.pb.Configuration.layout_direction', index=3,
number=4, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='screen_width', full_name='aapt.pb.Configuration.screen_width', index=4,
number=5, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='screen_height', full_name='aapt.pb.Configuration.screen_height', index=5,
number=6, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='screen_width_dp', full_name='aapt.pb.Configuration.screen_width_dp', index=6,
number=7, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='screen_height_dp', full_name='aapt.pb.Configuration.screen_height_dp', index=7,
number=8, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='smallest_screen_width_dp', full_name='aapt.pb.Configuration.smallest_screen_width_dp', index=8,
number=9, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='screen_layout_size', full_name='aapt.pb.Configuration.screen_layout_size', index=9,
number=10, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='screen_layout_long', full_name='aapt.pb.Configuration.screen_layout_long', index=10,
number=11, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='screen_round', full_name='aapt.pb.Configuration.screen_round', index=11,
number=12, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='wide_color_gamut', full_name='aapt.pb.Configuration.wide_color_gamut', index=12,
number=13, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='hdr', full_name='aapt.pb.Configuration.hdr', index=13,
number=14, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='orientation', full_name='aapt.pb.Configuration.orientation', index=14,
number=15, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='ui_mode_type', full_name='aapt.pb.Configuration.ui_mode_type', index=15,
number=16, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='ui_mode_night', full_name='aapt.pb.Configuration.ui_mode_night', index=16,
number=17, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='density', full_name='aapt.pb.Configuration.density', index=17,
number=18, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='touchscreen', full_name='aapt.pb.Configuration.touchscreen', index=18,
number=19, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='keys_hidden', full_name='aapt.pb.Configuration.keys_hidden', index=19,
number=20, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='keyboard', full_name='aapt.pb.Configuration.keyboard', index=20,
number=21, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='nav_hidden', full_name='aapt.pb.Configuration.nav_hidden', index=21,
number=22, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='navigation', full_name='aapt.pb.Configuration.navigation', index=22,
number=23, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='sdk_version', full_name='aapt.pb.Configuration.sdk_version', index=23,
number=24, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='product', full_name='aapt.pb.Configuration.product', index=24,
number=25, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
_CONFIGURATION_LAYOUTDIRECTION,
_CONFIGURATION_SCREENLAYOUTSIZE,
_CONFIGURATION_SCREENLAYOUTLONG,
_CONFIGURATION_SCREENROUND,
_CONFIGURATION_WIDECOLORGAMUT,
_CONFIGURATION_HDR,
_CONFIGURATION_ORIENTATION,
_CONFIGURATION_UIMODETYPE,
_CONFIGURATION_UIMODENIGHT,
_CONFIGURATION_TOUCHSCREEN,
_CONFIGURATION_KEYSHIDDEN,
_CONFIGURATION_KEYBOARD,
_CONFIGURATION_NAVHIDDEN,
_CONFIGURATION_NAVIGATION,
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=61,
serialized_end=2710,
)
_CONFIGURATION.fields_by_name['layout_direction'].enum_type = _CONFIGURATION_LAYOUTDIRECTION
_CONFIGURATION.fields_by_name['screen_layout_size'].enum_type = _CONFIGURATION_SCREENLAYOUTSIZE
_CONFIGURATION.fields_by_name['screen_layout_long'].enum_type = _CONFIGURATION_SCREENLAYOUTLONG
_CONFIGURATION.fields_by_name['screen_round'].enum_type = _CONFIGURATION_SCREENROUND
_CONFIGURATION.fields_by_name['wide_color_gamut'].enum_type = _CONFIGURATION_WIDECOLORGAMUT
_CONFIGURATION.fields_by_name['hdr'].enum_type = _CONFIGURATION_HDR
_CONFIGURATION.fields_by_name['orientation'].enum_type = _CONFIGURATION_ORIENTATION
_CONFIGURATION.fields_by_name['ui_mode_type'].enum_type = _CONFIGURATION_UIMODETYPE
_CONFIGURATION.fields_by_name['ui_mode_night'].enum_type = _CONFIGURATION_UIMODENIGHT
_CONFIGURATION.fields_by_name['touchscreen'].enum_type = _CONFIGURATION_TOUCHSCREEN
_CONFIGURATION.fields_by_name['keys_hidden'].enum_type = _CONFIGURATION_KEYSHIDDEN
_CONFIGURATION.fields_by_name['keyboard'].enum_type = _CONFIGURATION_KEYBOARD
_CONFIGURATION.fields_by_name['nav_hidden'].enum_type = _CONFIGURATION_NAVHIDDEN
_CONFIGURATION.fields_by_name['navigation'].enum_type = _CONFIGURATION_NAVIGATION
_CONFIGURATION_LAYOUTDIRECTION.containing_type = _CONFIGURATION
_CONFIGURATION_SCREENLAYOUTSIZE.containing_type = _CONFIGURATION
_CONFIGURATION_SCREENLAYOUTLONG.containing_type = _CONFIGURATION
_CONFIGURATION_SCREENROUND.containing_type = _CONFIGURATION
_CONFIGURATION_WIDECOLORGAMUT.containing_type = _CONFIGURATION
_CONFIGURATION_HDR.containing_type = _CONFIGURATION
_CONFIGURATION_ORIENTATION.containing_type = _CONFIGURATION
_CONFIGURATION_UIMODETYPE.containing_type = _CONFIGURATION
_CONFIGURATION_UIMODENIGHT.containing_type = _CONFIGURATION
_CONFIGURATION_TOUCHSCREEN.containing_type = _CONFIGURATION
_CONFIGURATION_KEYSHIDDEN.containing_type = _CONFIGURATION
_CONFIGURATION_KEYBOARD.containing_type = _CONFIGURATION
_CONFIGURATION_NAVHIDDEN.containing_type = _CONFIGURATION
_CONFIGURATION_NAVIGATION.containing_type = _CONFIGURATION
DESCRIPTOR.message_types_by_name['Configuration'] = _CONFIGURATION
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
Configuration = _reflection.GeneratedProtocolMessageType('Configuration', (_message.Message,), {
'DESCRIPTOR' : _CONFIGURATION,
'__module__' : 'frameworks.base.tools.aapt2.Configuration_pb2'
# @@protoc_insertion_point(class_scope:aapt.pb.Configuration)
})
_sym_db.RegisterMessage(Configuration)
DESCRIPTOR._options = None
# @@protoc_insertion_point(module_scope)

4
direct/src/dist/_proto/README vendored Normal file
View File

@ -0,0 +1,4 @@
The files in this directory were generated from the .proto files in the
bundletool and aapt2 repositories.
They are used by installer.py when generating an Android App Bundle.

3246
direct/src/dist/_proto/Resources_pb2.py vendored Normal file

File diff suppressed because one or more lines are too long

0
direct/src/dist/_proto/__init__.py vendored Normal file
View File

1045
direct/src/dist/_proto/config_pb2.py vendored Normal file

File diff suppressed because it is too large Load Diff

307
direct/src/dist/_proto/files_pb2.py vendored Normal file
View File

@ -0,0 +1,307 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: files.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
from . import targeting_pb2 as targeting__pb2
DESCRIPTOR = _descriptor.FileDescriptor(
name='files.proto',
package='android.bundle',
syntax='proto3',
serialized_options=b'\n\022com.android.bundle',
create_key=_descriptor._internal_create_key,
serialized_pb=b'\n\x0b\x66iles.proto\x12\x0e\x61ndroid.bundle\x1a\x0ftargeting.proto\"D\n\x06\x41ssets\x12:\n\tdirectory\x18\x01 \x03(\x0b\x32\'.android.bundle.TargetedAssetsDirectory\"M\n\x0fNativeLibraries\x12:\n\tdirectory\x18\x01 \x03(\x0b\x32\'.android.bundle.TargetedNativeDirectory\"D\n\nApexImages\x12\x30\n\x05image\x18\x01 \x03(\x0b\x32!.android.bundle.TargetedApexImageJ\x04\x08\x02\x10\x03\"d\n\x17TargetedAssetsDirectory\x12\x0c\n\x04path\x18\x01 \x01(\t\x12;\n\ttargeting\x18\x02 \x01(\x0b\x32(.android.bundle.AssetsDirectoryTargeting\"d\n\x17TargetedNativeDirectory\x12\x0c\n\x04path\x18\x01 \x01(\t\x12;\n\ttargeting\x18\x02 \x01(\x0b\x32(.android.bundle.NativeDirectoryTargeting\"q\n\x11TargetedApexImage\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x17\n\x0f\x62uild_info_path\x18\x03 \x01(\t\x12\x35\n\ttargeting\x18\x02 \x01(\x0b\x32\".android.bundle.ApexImageTargetingB\x14\n\x12\x63om.android.bundleb\x06proto3'
,
dependencies=[targeting__pb2.DESCRIPTOR,])
_ASSETS = _descriptor.Descriptor(
name='Assets',
full_name='android.bundle.Assets',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='directory', full_name='android.bundle.Assets.directory', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=48,
serialized_end=116,
)
_NATIVELIBRARIES = _descriptor.Descriptor(
name='NativeLibraries',
full_name='android.bundle.NativeLibraries',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='directory', full_name='android.bundle.NativeLibraries.directory', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=118,
serialized_end=195,
)
_APEXIMAGES = _descriptor.Descriptor(
name='ApexImages',
full_name='android.bundle.ApexImages',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='image', full_name='android.bundle.ApexImages.image', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=197,
serialized_end=265,
)
_TARGETEDASSETSDIRECTORY = _descriptor.Descriptor(
name='TargetedAssetsDirectory',
full_name='android.bundle.TargetedAssetsDirectory',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='path', full_name='android.bundle.TargetedAssetsDirectory.path', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='targeting', full_name='android.bundle.TargetedAssetsDirectory.targeting', index=1,
number=2, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=267,
serialized_end=367,
)
_TARGETEDNATIVEDIRECTORY = _descriptor.Descriptor(
name='TargetedNativeDirectory',
full_name='android.bundle.TargetedNativeDirectory',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='path', full_name='android.bundle.TargetedNativeDirectory.path', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='targeting', full_name='android.bundle.TargetedNativeDirectory.targeting', index=1,
number=2, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=369,
serialized_end=469,
)
_TARGETEDAPEXIMAGE = _descriptor.Descriptor(
name='TargetedApexImage',
full_name='android.bundle.TargetedApexImage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='path', full_name='android.bundle.TargetedApexImage.path', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='build_info_path', full_name='android.bundle.TargetedApexImage.build_info_path', index=1,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='targeting', full_name='android.bundle.TargetedApexImage.targeting', index=2,
number=2, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=471,
serialized_end=584,
)
_ASSETS.fields_by_name['directory'].message_type = _TARGETEDASSETSDIRECTORY
_NATIVELIBRARIES.fields_by_name['directory'].message_type = _TARGETEDNATIVEDIRECTORY
_APEXIMAGES.fields_by_name['image'].message_type = _TARGETEDAPEXIMAGE
_TARGETEDASSETSDIRECTORY.fields_by_name['targeting'].message_type = targeting__pb2._ASSETSDIRECTORYTARGETING
_TARGETEDNATIVEDIRECTORY.fields_by_name['targeting'].message_type = targeting__pb2._NATIVEDIRECTORYTARGETING
_TARGETEDAPEXIMAGE.fields_by_name['targeting'].message_type = targeting__pb2._APEXIMAGETARGETING
DESCRIPTOR.message_types_by_name['Assets'] = _ASSETS
DESCRIPTOR.message_types_by_name['NativeLibraries'] = _NATIVELIBRARIES
DESCRIPTOR.message_types_by_name['ApexImages'] = _APEXIMAGES
DESCRIPTOR.message_types_by_name['TargetedAssetsDirectory'] = _TARGETEDASSETSDIRECTORY
DESCRIPTOR.message_types_by_name['TargetedNativeDirectory'] = _TARGETEDNATIVEDIRECTORY
DESCRIPTOR.message_types_by_name['TargetedApexImage'] = _TARGETEDAPEXIMAGE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
Assets = _reflection.GeneratedProtocolMessageType('Assets', (_message.Message,), {
'DESCRIPTOR' : _ASSETS,
'__module__' : 'files_pb2'
# @@protoc_insertion_point(class_scope:android.bundle.Assets)
})
_sym_db.RegisterMessage(Assets)
NativeLibraries = _reflection.GeneratedProtocolMessageType('NativeLibraries', (_message.Message,), {
'DESCRIPTOR' : _NATIVELIBRARIES,
'__module__' : 'files_pb2'
# @@protoc_insertion_point(class_scope:android.bundle.NativeLibraries)
})
_sym_db.RegisterMessage(NativeLibraries)
ApexImages = _reflection.GeneratedProtocolMessageType('ApexImages', (_message.Message,), {
'DESCRIPTOR' : _APEXIMAGES,
'__module__' : 'files_pb2'
# @@protoc_insertion_point(class_scope:android.bundle.ApexImages)
})
_sym_db.RegisterMessage(ApexImages)
TargetedAssetsDirectory = _reflection.GeneratedProtocolMessageType('TargetedAssetsDirectory', (_message.Message,), {
'DESCRIPTOR' : _TARGETEDASSETSDIRECTORY,
'__module__' : 'files_pb2'
# @@protoc_insertion_point(class_scope:android.bundle.TargetedAssetsDirectory)
})
_sym_db.RegisterMessage(TargetedAssetsDirectory)
TargetedNativeDirectory = _reflection.GeneratedProtocolMessageType('TargetedNativeDirectory', (_message.Message,), {
'DESCRIPTOR' : _TARGETEDNATIVEDIRECTORY,
'__module__' : 'files_pb2'
# @@protoc_insertion_point(class_scope:android.bundle.TargetedNativeDirectory)
})
_sym_db.RegisterMessage(TargetedNativeDirectory)
TargetedApexImage = _reflection.GeneratedProtocolMessageType('TargetedApexImage', (_message.Message,), {
'DESCRIPTOR' : _TARGETEDAPEXIMAGE,
'__module__' : 'files_pb2'
# @@protoc_insertion_point(class_scope:android.bundle.TargetedApexImage)
})
_sym_db.RegisterMessage(TargetedApexImage)
DESCRIPTOR._options = None
# @@protoc_insertion_point(module_scope)

1470
direct/src/dist/_proto/targeting_pb2.py vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -157,6 +157,50 @@ if os.path.isdir(tcl_dir):
del os
"""
SITE_PY_ANDROID = """
import sys, os
from _frozen_importlib import _imp, FrozenImporter
from importlib import _bootstrap_external
from importlib.abc import Loader, MetaPathFinder
from importlib.machinery import ModuleSpec
sys.frozen = True
sys.platform = "android"
# Alter FrozenImporter to give a __file__ property to frozen modules.
_find_spec = FrozenImporter.find_spec
def find_spec(fullname, path=None, target=None):
spec = _find_spec(fullname, path=path, target=target)
if spec:
spec.has_location = True
spec.origin = sys.executable
return spec
def get_data(path):
with open(path, 'rb') as fp:
return fp.read()
FrozenImporter.find_spec = find_spec
FrozenImporter.get_data = get_data
class AndroidExtensionFinder(MetaPathFinder):
@classmethod
def find_spec(cls, fullname, path=None, target=None):
soname = 'libpy.' + fullname + '.so'
path = os.path.join(sys._native_library_dir, soname)
if os.path.exists(path):
loader = _bootstrap_external.ExtensionFileLoader(fullname, path)
return ModuleSpec(fullname, loader, origin=path)
sys.meta_path.append(AndroidExtensionFinder)
"""
class build_apps(setuptools.Command):
description = 'build Panda3D applications'
@ -171,6 +215,12 @@ class build_apps(setuptools.Command):
def initialize_options(self):
self.build_base = os.path.join(os.getcwd(), 'build')
self.application_id = None
self.android_debuggable = False
self.android_version_code = 1
self.android_min_sdk_version = 21
self.android_max_sdk_version = None
self.android_target_sdk_version = 30
self.gui_apps = {}
self.console_apps = {}
self.macos_main_app = None
@ -266,6 +316,11 @@ class build_apps(setuptools.Command):
'/usr/lib/libxar.1.dylib',
'/usr/lib/libmenu.5.4.dylib',
'/System/Library/**',
# Android
'libc.so', 'libm.so', 'liblog.so', 'libdl.so', 'libandroid.so',
'libGLESv1_CM.so', 'libGLESv2.so', 'libjnigraphics.so', 'libEGL.so',
'libOpenSLES.so', 'libandroid.so', 'libOpenMAXAL.so',
]
self.package_data_dirs = {}
@ -508,6 +563,72 @@ class build_apps(setuptools.Command):
with open(os.path.join(contentsdir, 'Info.plist'), 'wb') as f:
plistlib.dump(plist, f)
def generate_android_manifest(self, path):
import xml.etree.ElementTree as ET
name = self.distribution.get_name()
version = self.distribution.get_version()
classifiers = self.distribution.get_classifiers()
is_game = False
for classifier in classifiers:
if classifier == 'Topic :: Games/Entertainment' or classifier.startswith('Topic :: Games/Entertainment ::'):
is_game = True
manifest = ET.Element('manifest')
manifest.set('xmlns:android', 'http://schemas.android.com/apk/res/android')
manifest.set('package', self.application_id)
manifest.set('android:versionCode', str(int(self.android_version_code)))
manifest.set('android:versionName', version)
manifest.set('android:installLocation', 'auto')
uses_sdk = ET.SubElement(manifest, 'uses-sdk')
uses_sdk.set('android:minSdkVersion', str(int(self.android_min_sdk_version)))
uses_sdk.set('android:targetSdkVersion', str(int(self.android_target_sdk_version)))
if self.android_max_sdk_version:
uses_sdk.set('android:maxSdkVersion', str(int(self.android_max_sdk_version)))
if 'pandagles2' in self.plugins:
uses_feature = ET.SubElement(manifest, 'uses-feature')
uses_feature.set('android:glEsVersion', '0x00020000')
uses_feature.set('android:required', 'false' if 'pandagles' in self.plugins else 'true')
if 'p3openal_audio' in self.plugins:
uses_feature = ET.SubElement(manifest, 'uses-feature')
uses_feature.set('android:name', 'android.hardware.audio.output')
uses_feature.set('android:required', 'false')
uses_feature = ET.SubElement(manifest, 'uses-feature')
uses_feature.set('android:name', 'android.hardware.gamepad')
uses_feature.set('android:required', 'false')
application = ET.SubElement(manifest, 'application')
application.set('android:label', name)
application.set('android:isGame', ('false', 'true')[is_game])
application.set('android:debuggable', ('false', 'true')[self.android_debuggable])
application.set('android:extractNativeLibs', 'true')
for appname in self.gui_apps:
activity = ET.SubElement(application, 'activity')
activity.set('android:name', 'org.panda3d.android.PandaActivity')
activity.set('android:label', appname)
activity.set('android:theme', '@android:style/Theme.NoTitleBar')
activity.set('android:configChanges', 'orientation|keyboardHidden')
activity.set('android:launchMode', 'singleInstance')
meta_data = ET.SubElement(activity, 'meta-data')
meta_data.set('android:name', 'android.app.lib_name')
meta_data.set('android:value', appname)
intent_filter = ET.SubElement(activity, 'intent-filter')
ET.SubElement(intent_filter, 'action').set('android:name', 'android.intent.action.MAIN')
ET.SubElement(intent_filter, 'category').set('android:name', 'android.intent.category.LAUNCHER')
ET.SubElement(intent_filter, 'category').set('android:name', 'android.intent.category.LEANBACK_LAUNCHER')
tree = ET.ElementTree(manifest)
with open(path, 'wb') as fh:
tree.write(fh, encoding='utf-8', xml_declaration=True)
def build_runtimes(self, platform, use_wheels):
""" Builds the distributions for the given platform. """
@ -607,6 +728,9 @@ class build_apps(setuptools.Command):
value = value[:c].rstrip()
if var == 'model-cache-dir' and value:
if platform.startswith('android'):
# Ignore on Android, where the cache dir is fixed.
continue
value = value.replace('/panda3d', '/{}'.format(self.distribution.get_name()))
if var == 'audio-library-name':
@ -683,33 +807,42 @@ class build_apps(setuptools.Command):
return search_path
def create_runtime(appname, mainscript, use_console):
def create_runtime(appname, mainscript, target_dir, use_console):
freezer = FreezeTool.Freezer(
platform=platform,
path=path,
hiddenImports=self.hidden_imports
)
freezer.addModule('__main__', filename=mainscript)
freezer.addModule('site', filename='site.py', text=SITE_PY)
if platform.startswith('android'):
freezer.addModule('site', filename='site.py', text=SITE_PY_ANDROID)
else:
freezer.addModule('site', filename='site.py', text=SITE_PY)
for incmod in self.include_modules.get(appname, []) + self.include_modules.get('*', []):
freezer.addModule(incmod)
for exmod in self.exclude_modules.get(appname, []) + self.exclude_modules.get('*', []):
freezer.excludeModule(exmod)
freezer.done(addStartupModules=True)
target_path = os.path.join(builddir, appname)
stub_name = 'deploy-stub'
target_name = appname
if platform.startswith('win') or 'macosx' in platform:
if not use_console:
stub_name = 'deploy-stubw'
elif platform.startswith('android'):
if not use_console:
stub_name = 'libdeploy-stubw.so'
target_name = 'lib' + target_name + '.so'
if platform.startswith('win'):
stub_name += '.exe'
target_path += '.exe'
target_name += '.exe'
if use_wheels:
stub_file = p3dwhl.open('panda3d_tools/{0}'.format(stub_name))
if stub_name.endswith('.so'):
stub_file = p3dwhl.open('deploy_libs/{0}'.format(stub_name))
else:
stub_file = p3dwhl.open('panda3d_tools/{0}'.format(stub_name))
else:
dtool_path = p3d.Filename(p3d.ExecutionEnvironment.get_dtool_name()).to_os_specific()
stub_path = os.path.join(os.path.dirname(dtool_path), '..', 'bin', stub_name)
@ -731,6 +864,7 @@ class build_apps(setuptools.Command):
if not self.log_filename or '%' not in self.log_filename:
use_strftime = False
target_path = os.path.join(target_dir, target_name)
freezer.generateRuntimeFromStub(target_path, stub_file, use_console, {
'prc_data': prcexport if self.embed_prc_data else None,
'default_prc_dir': self.default_prc_dir,
@ -750,10 +884,11 @@ class build_apps(setuptools.Command):
os.unlink(temp_file.name)
# Copy the dependencies.
search_path = [builddir]
search_path = [target_dir]
if use_wheels:
search_path.append(os.path.join(p3dwhlfn, 'panda3d'))
search_path.append(os.path.join(p3dwhlfn, 'deploy_libs'))
self.copy_dependencies(target_path, builddir, search_path, stub_name)
self.copy_dependencies(target_path, target_dir, search_path, stub_name)
freezer_extras.update(freezer.extras)
freezer_modules.update(freezer.getAllModuleNames())
@ -765,11 +900,37 @@ class build_apps(setuptools.Command):
if suffix[2] == imp.C_EXTENSION:
ext_suffixes.add(suffix[0])
# Where should we copy the various file types to?
lib_dir = builddir
data_dir = builddir
if platform.startswith('android'):
data_dir = os.path.join(data_dir, 'assets')
if platform == 'android_arm64':
lib_dir = os.path.join(lib_dir, 'lib', 'arm64-v8a')
elif platform == 'android_armv7a':
lib_dir = os.path.join(lib_dir, 'lib', 'armeabi-v7a')
elif platform == 'android_arm':
lib_dir = os.path.join(lib_dir, 'lib', 'armeabi')
elif platform == 'androidmips':
lib_dir = os.path.join(lib_dir, 'lib', 'mips')
elif platform == 'android_mips64':
lib_dir = os.path.join(lib_dir, 'lib', 'mips64')
elif platform == 'android_x86':
lib_dir = os.path.join(lib_dir, 'lib', 'x86')
elif platform == 'android_x86_64':
lib_dir = os.path.join(lib_dir, 'lib', 'x86_64')
else:
self.announce('Unrecognized Android architecture {}'.format(platform.split('_', 1)[-1]), distutils.log.ERROR)
os.makedirs(data_dir, exist_ok=True)
os.makedirs(lib_dir, exist_ok=True)
for appname, scriptname in self.gui_apps.items():
create_runtime(appname, scriptname, False)
create_runtime(appname, scriptname, lib_dir, False)
for appname, scriptname in self.console_apps.items():
create_runtime(appname, scriptname, True)
create_runtime(appname, scriptname, lib_dir, True)
# Copy extension modules
whl_modules = []
@ -805,7 +966,7 @@ class build_apps(setuptools.Command):
plugname = lib.split('.', 1)[0]
if plugname in plugin_list:
source_path = os.path.join(p3dwhlfn, lib)
target_path = os.path.join(builddir, os.path.basename(lib))
target_path = os.path.join(lib_dir, os.path.basename(lib))
search_path = [os.path.dirname(source_path)]
self.copy_with_dependencies(source_path, target_path, search_path)
@ -846,8 +1007,13 @@ class build_apps(setuptools.Command):
else:
continue
if platform.startswith('android'):
# Python modules on Android need a special prefix to be loadable
# as a library.
basename = 'libpy.' + basename
# If this is a dynamic library, search for dependencies.
target_path = os.path.join(builddir, basename)
target_path = os.path.join(lib_dir, basename)
search_path = get_search_path_for(source_path)
self.copy_with_dependencies(source_path, target_path, search_path)
@ -858,15 +1024,20 @@ class build_apps(setuptools.Command):
if os.path.isdir(tcl_dir) and 'tkinter' in freezer_modules:
self.announce('Copying Tcl files', distutils.log.INFO)
os.makedirs(os.path.join(builddir, 'tcl'))
os.makedirs(os.path.join(data_dir, 'tcl'))
for dir in os.listdir(tcl_dir):
sub_dir = os.path.join(tcl_dir, dir)
if os.path.isdir(sub_dir):
target_dir = os.path.join(builddir, 'tcl', dir)
target_dir = os.path.join(data_dir, 'tcl', dir)
self.announce('copying {0} -> {1}'.format(sub_dir, target_dir))
shutil.copytree(sub_dir, target_dir)
# Copy classes.dex on Android
if use_wheels and platform.startswith('android'):
self.copy(os.path.join(p3dwhlfn, 'deploy_libs', 'classes.dex'),
os.path.join(builddir, 'classes.dex'))
# Extract any other data files from dependency packages.
for module, datadesc in self.package_data_dirs.items():
if module not in freezer_modules:
@ -883,7 +1054,7 @@ class build_apps(setuptools.Command):
source_dir = os.path.dirname(source_pattern)
# Relocate the target dir to the build directory.
target_dir = target_dir.replace('/', os.sep)
target_dir = os.path.join(builddir, target_dir)
target_dir = os.path.join(data_dir, target_dir)
for wf in filenames:
if wf.lower().startswith(source_dir.lower() + '/'):
@ -1008,10 +1179,14 @@ class build_apps(setuptools.Command):
for fname in filelist:
src = os.path.join(dirpath, fname)
dst = os.path.join(builddir, update_path(src))
dst = os.path.join(data_dir, update_path(src))
copy_file(src, dst)
if 'android' in platform:
# Generate an AndroidManifest.xml
self.generate_android_manifest(os.path.join(builddir, 'AndroidManifest.xml'))
# Bundle into an .app on macOS
if self.macos_main_app and 'macosx' in platform:
self.bundle_macos_app(builddir)
@ -1333,6 +1508,13 @@ class bdist_apps(setuptools.Command):
'manylinux1_i686': ['gztar'],
'manylinux2010_x86_64': ['gztar'],
'manylinux2010_i686': ['gztar'],
'android_arm64': ['aab'],
'android_armv7a': ['aab'],
'android_arm': ['aab'],
'android_mips': ['aab'],
'android_mips64': ['aab'],
'android_x86': ['aab'],
'android_x86_64': ['aab'],
# Everything else defaults to ['zip']
}
@ -1342,6 +1524,7 @@ class bdist_apps(setuptools.Command):
'bztar': installers.create_bztar,
'xztar': installers.create_xztar,
'nsis': installers.create_nsis,
'aab': installers.create_aab,
}
description = 'bundle built Panda3D applications into distributable forms'

View File

@ -196,3 +196,71 @@ def create_nsis(command, basename, build_dir):
)
cmd.append(nsifile.to_os_specific())
subprocess.check_call(cmd)
def create_aab(command, basename, build_dir):
"""Create an Android App Bundle. This is a newer format that replaces
Android's .apk format for uploads to the Play Store. Unlike .apk files, it
does not rely on a proprietary signing scheme or an undocumented binary XML
format (protobuf is used instead), so it is easier to create without
requiring external tools. If desired, it is possible to install bundletool
and use it to convert an .aab into an .apk.
"""
from ._android import AndroidManifest, AbiAlias, BundleConfig, NativeLibraries, ResourceTable
bundle_fn = p3d.Filename.from_os_specific(command.dist_dir) / (basename + '.aab')
build_dir_fn = p3d.Filename.from_os_specific(build_dir)
# We use our own zip implementation, which can create the correct
# alignment needed by Android automatically.
bundle = p3d.ZipArchive()
if not bundle.open_write(bundle_fn):
command.announce.error(
f'\tUnable to open {bundle_fn} for writing', distutils.log.ERROR)
return
config = BundleConfig()
config.bundletool.version = '1.1.0'
config.optimizations.splits_config.Clear()
config.optimizations.uncompress_native_libraries.enabled = False
bundle.add_subfile('BundleConfig.pb', p3d.StringStream(config.SerializeToString()), 9)
resources = ResourceTable()
bundle.add_subfile('base/resources.pb', p3d.StringStream(resources.SerializeToString()), 9)
native = NativeLibraries()
for abi in os.listdir(os.path.join(build_dir, 'lib')):
native_dir = native.directory.add()
native_dir.path = 'lib/' + abi
native_dir.targeting.abi.alias = getattr(AbiAlias, abi.upper().replace('-', '_'))
bundle.add_subfile('base/native.pb', p3d.StringStream(native.SerializeToString()), 9)
# Convert the AndroidManifest.xml file to a protobuf-encoded version of it.
axml = AndroidManifest()
with open(os.path.join(build_dir, 'AndroidManifest.xml'), 'rb') as fh:
axml.parse_xml(fh.read())
bundle.add_subfile('base/manifest/AndroidManifest.xml', p3d.StringStream(axml.dumps()), 9)
# Add the classes.dex.
bundle.add_subfile(f'base/dex/classes.dex', build_dir_fn / 'classes.dex', 9)
# Add libraries, compressed.
for abi in os.listdir(os.path.join(build_dir, 'lib')):
abi_dir = os.path.join(build_dir, 'lib', abi)
for lib in os.listdir(abi_dir):
if lib.startswith('lib') and lib.endswith('.so'):
bundle.add_subfile(f'base/lib/{abi}/{lib}', build_dir_fn / 'lib' / abi / lib, 9)
# Add assets, compressed.
assets_dir = os.path.join(build_dir, 'assets')
for dirpath, dirnames, filenames in os.walk(assets_dir):
rel_dirpath = os.path.relpath(dirpath, build_dir).replace('\\', '/')
dirnames.sort()
filenames.sort()
for name in filenames:
fn = p3d.Filename.from_os_specific(dirpath) / name
if fn.is_regular_file():
bundle.add_subfile(f'base/{rel_dirpath}/{name}', fn, 9)

View File

@ -97,6 +97,7 @@ reload_implicit_pages() {
}
_implicit_pages.clear();
#ifndef ANDROID
// If we are running inside a deployed application, see if it exposes
// information about how the PRC data should be initialized.
struct BlobInfo {
@ -459,6 +460,7 @@ reload_implicit_pages() {
}
}
}
#endif // ANDROID
if (!_loaded_implicit) {
config_initialized();
@ -498,7 +500,6 @@ reload_implicit_pages() {
SetErrorMode(SEM_FAILCRITICALERRORS);
}
#endif
}
/**

View File

@ -6036,10 +6036,11 @@ if PkgSkip("PYTHON") == 0:
LibName('DEPLOYSTUB', "-Wl,-rpath,\\$ORIGIN")
LibName('DEPLOYSTUB', "-Wl,-z,origin")
LibName('DEPLOYSTUB', "-rdynamic")
PyTargetAdd('deploy-stub.exe', input='deploy-stub.obj')
if GetTarget() == 'windows':
PyTargetAdd('deploy-stub.exe', input='frozen_dllmain.obj')
PyTargetAdd('deploy-stub.exe', opts=['WINSHELL', 'DEPLOYSTUB', 'NOICON'])
PyTargetAdd('deploy-stub.exe', opts=['WINSHELL', 'DEPLOYSTUB', 'NOICON', 'ANDROID'])
if GetTarget() == 'windows':
PyTargetAdd('deploy-stubw.exe', input='deploy-stub.obj')
@ -6051,6 +6052,13 @@ if PkgSkip("PYTHON") == 0:
PyTargetAdd('deploy-stubw.obj', opts=OPTS, input='deploy-stub.c')
PyTargetAdd('deploy-stubw.exe', input='deploy-stubw.obj')
PyTargetAdd('deploy-stubw.exe', opts=['MACOS_APP_BUNDLE', 'DEPLOYSTUB', 'NOICON'])
elif GetTarget() == 'android':
PyTargetAdd('deploy-stubw_android_main.obj', opts=OPTS, input='android_main.cxx')
PyTargetAdd('libdeploy-stubw.dll', input='android_native_app_glue.obj')
PyTargetAdd('libdeploy-stubw.dll', input='deploy-stubw_android_main.obj')
PyTargetAdd('libdeploy-stubw.dll', input=COMMON_PANDA_LIBS)
PyTargetAdd('libdeploy-stubw.dll', input='libp3android.dll')
PyTargetAdd('libdeploy-stubw.dll', opts=['DEPLOYSTUB', 'ANDROID'])
#
# Generate the models directory and samples directory

View File

@ -10,11 +10,12 @@ import hashlib
import tempfile
import subprocess
import time
import struct
from distutils.util import get_platform
from distutils.sysconfig import get_config_var
from optparse import OptionParser
from base64 import urlsafe_b64encode
from makepandacore import LocateBinary, GetExtensionSuffix, SetVerbose, GetVerbose, GetMetadataValue
from makepandacore import LocateBinary, GetExtensionSuffix, SetVerbose, GetVerbose, GetMetadataValue, CrossCompiling, GetThirdpartyDir, SDK, GetStrip
def get_abi_tag():
@ -65,8 +66,11 @@ def is_fat_file(path):
def get_python_ext_module_dir():
import _ctypes
return os.path.dirname(_ctypes.__file__)
if CrossCompiling():
return os.path.join(GetThirdpartyDir(), "python", "lib", SDK["PYTHONVERSION"], "lib-dynload")
else:
import _ctypes
return os.path.dirname(_ctypes.__file__)
if sys.platform in ('win32', 'cygwin'):
@ -251,16 +255,72 @@ def parse_dependencies_unix(data):
return filenames
def _scan_dependencies_elf(elf):
deps = []
ident = elf.read(12)
# Make sure we read in the correct endianness and integer size
byte_order = "<>"[ord(ident[1:2]) - 1]
elf_class = ord(ident[0:1]) - 1 # 0 = 32-bits, 1 = 64-bits
header_struct = byte_order + ("HHIIIIIHHHHHH", "HHIQQQIHHHHHH")[elf_class]
section_struct = byte_order + ("4xI8xIII8xI", "4xI16xQQI12xQ")[elf_class]
dynamic_struct = byte_order + ("iI", "qQ")[elf_class]
type, machine, version, entry, phoff, shoff, flags, ehsize, phentsize, phnum, shentsize, shnum, shstrndx \
= struct.unpack(header_struct, elf.read(struct.calcsize(header_struct)))
dynamic_sections = []
string_tables = {}
# Seek to the section header table and find the .dynamic section.
elf.seek(shoff)
for i in range(shnum):
type, offset, size, link, entsize = struct.unpack_from(section_struct, elf.read(shentsize))
if type == 6 and link != 0: # DYNAMIC type, links to string table
dynamic_sections.append((offset, size, link, entsize))
string_tables[link] = None
# Read the relevant string tables.
for idx in string_tables.keys():
elf.seek(shoff + idx * shentsize)
type, offset, size, link, entsize = struct.unpack_from(section_struct, elf.read(shentsize))
if type != 3: continue
elf.seek(offset)
string_tables[idx] = elf.read(size)
# Loop through the dynamic sections to get the NEEDED entries.
needed = []
for offset, size, link, entsize in dynamic_sections:
elf.seek(offset)
data = elf.read(entsize)
tag, val = struct.unpack_from(dynamic_struct, data)
# Read tags until we find a NULL tag.
while tag != 0:
if tag == 1: # A NEEDED entry. Read it from the string table.
string = string_tables[link][val : string_tables[link].find(b'\0', val)]
needed.append(string.decode('utf-8'))
data = elf.read(entsize)
tag, val = struct.unpack_from(dynamic_struct, data)
elf.close()
return needed
def scan_dependencies(pathname):
""" Checks the named file for DLL dependencies, and adds any appropriate
dependencies found into pluginDependencies and dependentFiles. """
with open(pathname, 'rb') as fh:
if fh.read(4) == b'\x7FELF':
return _scan_dependencies_elf(fh)
if sys.platform == "darwin":
command = ['otool', '-XL', pathname]
elif sys.platform in ("win32", "cygwin"):
command = ['dumpbin', '/dependents', pathname]
else:
command = ['ldd', pathname]
sys.exit("Don't know how to determine dependencies from %s" % (pathname))
process = subprocess.Popen(command, stdout=subprocess.PIPE, universal_newlines=True)
output, unused_err = process.communicate()
@ -322,18 +382,24 @@ class WheelFile(object):
self.dep_paths[dep] = None
if dep in self.ignore_deps or dep.lower().startswith("python") or os.path.basename(dep).startswith("libpython"):
# Don't include the Python library, or any other explicit ignore.
if dep in self.ignore_deps:
if GetVerbose():
print("Ignoring {0} (explicitly ignored)".format(dep))
return
if sys.platform == "darwin" and dep.endswith(".so"):
# Temporary hack for 1.9, which had link deps on modules.
return
if not self.platform.startswith("android"):
if dep.lower().startswith("python") or os.path.basename(dep).startswith("libpython"):
if GetVerbose():
print("Ignoring {0} (explicitly ignored)".format(dep))
return
if sys.platform == "darwin" and dep.startswith("/System/"):
return
if self.platform.startswith("macosx"):
if dep.endswith(".so"):
# Temporary hack for 1.9, which had link deps on modules.
return
if dep.startswith("/System/"):
return
if dep.startswith('/'):
source_path = dep
@ -386,7 +452,7 @@ class WheelFile(object):
temp = tempfile.NamedTemporaryFile(suffix=suffix, prefix='whl', delete=False)
# On macOS, if no fat wheel was requested, extract the right architecture.
if sys.platform == "darwin" and is_fat_file(source_path) \
if self.platform.startswith("macosx") and is_fat_file(source_path) \
and not self.platform.endswith("_intel") \
and "_fat" not in self.platform \
and "_universal" not in self.platform:
@ -404,7 +470,7 @@ class WheelFile(object):
os.chmod(temp.name, os.stat(temp.name).st_mode | 0o711)
# Now add dependencies. On macOS, fix @loader_path references.
if sys.platform == "darwin":
if self.platform.startswith("macosx"):
if source_path.endswith('deploy-stubw'):
deps_path = '@executable_path/../Frameworks'
else:
@ -457,12 +523,32 @@ class WheelFile(object):
# On other unixes, we just add dependencies normally.
for dep in deps:
# Only include dependencies with relative path, for now.
if '/' not in dep:
target_dep = os.path.dirname(target_path) + '/' + dep
self.consider_add_dependency(target_dep, dep)
if '/' in dep:
continue
subprocess.call(["strip", "-s", temp.name])
subprocess.call(["patchelf", "--force-rpath", "--set-rpath", "$ORIGIN", temp.name])
if self.platform.startswith('android') and '.so.' in dep:
# Change .so.1.2 suffix to .so, to allow loading in .apk
new_dep = dep.rpartition('.so.')[0] + '.so'
subprocess.call(["patchelf", "--replace-needed", dep, new_dep, temp.name])
target_dep = os.path.dirname(target_path) + '/' + new_dep
else:
target_dep = os.path.dirname(target_path) + '/' + dep
self.consider_add_dependency(target_dep, dep)
subprocess.call([GetStrip(), "-s", temp.name])
if self.platform.startswith('android'):
# We must link explicitly with Python, because the usual
# -rdynamic trick doesn't work from a shared library loaded
# through ANativeActivity.
if suffix == '.so' and not os.path.basename(source_path).startswith('lib'):
pylib_name = "libpython" + get_config_var('LDVERSION') + ".so"
subprocess.call(["patchelf", "--add-needed", pylib_name, temp.name])
else:
# On other systems, we use the rpath to force it to locate
# dependencies in the same directory.
subprocess.call(["patchelf", "--force-rpath", "--set-rpath", "$ORIGIN", temp.name])
source_path = temp.name
@ -550,7 +636,7 @@ def makewheel(version, output_dir, platform=None):
raise Exception("patchelf is required when building a Linux wheel.")
if sys.version_info < (3, 6):
raise Exception("Python 3.6 is required to produce a wheel.")
raise Exception("Python 3.6 or higher is required to produce a wheel.")
if platform is None:
# Determine the platform from the build.
@ -571,6 +657,11 @@ def makewheel(version, output_dir, platform=None):
platform = platform.replace('-', '_').replace('.', '_')
is_windows = platform == 'win32' \
or platform.startswith('win_') \
or platform.startswith('cygwin_')
is_macosx = platform.startswith('macosx_')
# Global filepaths
panda3d_dir = join(output_dir, "panda3d")
pandac_dir = join(output_dir, "pandac")
@ -578,7 +669,7 @@ def makewheel(version, output_dir, platform=None):
models_dir = join(output_dir, "models")
etc_dir = join(output_dir, "etc")
bin_dir = join(output_dir, "bin")
if sys.platform == "win32":
if is_windows:
libs_dir = join(output_dir, "bin")
else:
libs_dir = join(output_dir, "lib")
@ -613,7 +704,7 @@ def makewheel(version, output_dir, platform=None):
whl = WheelFile('panda3d', version, platform)
whl.lib_path = [libs_dir]
if sys.platform == "win32":
if is_windows:
whl.lib_path.append(ext_mod_dir)
if platform.startswith("manylinux"):
@ -629,10 +720,10 @@ def makewheel(version, output_dir, platform=None):
whl.ignore_deps.update(MANYLINUX_LIBS)
# Add libpython for deployment.
if sys.platform in ('win32', 'cygwin'):
if is_windows:
pylib_name = 'python{0}{1}.dll'.format(*sys.version_info)
pylib_path = os.path.join(get_config_var('BINDIR'), pylib_name)
elif sys.platform == 'darwin':
elif is_macosx:
pylib_name = 'libpython{0}.{1}.dylib'.format(*sys.version_info)
pylib_path = os.path.join(get_config_var('LIBDIR'), pylib_name)
else:
@ -679,6 +770,9 @@ if __debug__:
if file.endswith('.pyd') and platform.startswith('cygwin'):
# Rename it to .dll for cygwin Python to be able to load it.
target_path = 'panda3d/' + os.path.splitext(file)[0] + '.dll'
elif file.endswith(ext_suffix) and platform.startswith('android'):
# Strip the extension suffix on Android.
target_path = 'panda3d/' + file[:-len(ext_suffix)] + '.so'
else:
target_path = 'panda3d/' + file
@ -686,7 +780,7 @@ if __debug__:
# And copy the extension modules from the Python installation into the
# deploy_libs directory, for use by deploy-ng.
ext_suffix = '.pyd' if sys.platform in ('win32', 'cygwin') else '.so'
ext_suffix = '.pyd' if is_windows else '.so'
for file in sorted(os.listdir(ext_mod_dir)):
if file.endswith(ext_suffix):
@ -703,9 +797,9 @@ if __debug__:
# Add plug-ins.
for lib in PLUGIN_LIBS:
plugin_name = 'lib' + lib
if sys.platform in ('win32', 'cygwin'):
if is_windows:
plugin_name += '.dll'
elif sys.platform == 'darwin':
elif is_macosx:
plugin_name += '.dylib'
else:
plugin_name += '.so'
@ -713,6 +807,15 @@ if __debug__:
if os.path.isfile(plugin_path):
whl.write_file('panda3d/' + plugin_name, plugin_path)
if platform.startswith('android'):
deploy_stub_path = os.path.join(libs_dir, 'libdeploy-stubw.so')
if os.path.isfile(deploy_stub_path):
whl.write_file('deploy_libs/libdeploy-stubw.so', deploy_stub_path)
classes_dex_path = os.path.join(output_dir, 'classes.dex')
if os.path.isfile(classes_dex_path):
whl.write_file('deploy_libs/classes.dex', classes_dex_path)
# Add the .data directory, containing additional files.
data_dir = 'panda3d-{0}.data'.format(version)
#whl.write_directory(data_dir + '/data/etc', etc_dir)

View File

@ -15,10 +15,13 @@ package org.panda3d.android;
import android.app.NativeActivity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.widget.Toast;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import dalvik.system.BaseDexClassLoader;
import org.panda3d.android.NativeIStream;
import org.panda3d.android.NativeOStream;
@ -74,6 +77,26 @@ public class PandaActivity extends NativeActivity {
return Thread.currentThread().getName();
}
/**
* Returns the path to the main native library.
*/
public String getNativeLibraryPath() {
String libname = "main";
try {
ActivityInfo ai = getPackageManager().getActivityInfo(
getIntent().getComponent(), PackageManager.GET_META_DATA);
if (ai.metaData != null) {
String ln = ai.metaData.getString(META_DATA_LIB_NAME);
if (ln != null) libname = ln;
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException("Error getting activity info", e);
}
BaseDexClassLoader classLoader = (BaseDexClassLoader) getClassLoader();
return classLoader.findLibrary(libname);
}
public String getIntentDataPath() {
Intent intent = getIntent();
Uri data = intent.getData();
@ -96,6 +119,9 @@ public class PandaActivity extends NativeActivity {
return getCacheDir().toString();
}
/**
* Shows a pop-up notification.
*/
public void showToast(final String text, final int duration) {
final PandaActivity activity = this;
runOnUiThread(new Runnable() {
@ -107,14 +133,10 @@ public class PandaActivity extends NativeActivity {
}
static {
//System.loadLibrary("gnustl_shared");
//System.loadLibrary("p3dtool");
//System.loadLibrary("p3dtoolconfig");
//System.loadLibrary("pandaexpress");
//System.loadLibrary("panda");
//System.loadLibrary("p3android");
//System.loadLibrary("p3framework");
System.loadLibrary("pandaegg");
System.loadLibrary("pandagles");
// Load this explicitly to initialize the JVM with the thread system.
System.loadLibrary("panda");
// Contains our JNI calls.
System.loadLibrary("p3android");
}
}

View File

@ -193,6 +193,8 @@ get_unique_id() const {
*/
bool ThreadPosixImpl::
attach_java_vm() {
assert(java_vm != nullptr);
JNIEnv *env;
std::string thread_name = _parent_obj->get_name();
JavaVMAttachArgs args;
@ -219,6 +221,8 @@ bind_java_thread() {
Thread *thread = Thread::get_current_thread();
nassertv(thread != nullptr);
assert(java_vm != nullptr);
// Get the JNIEnv for this Java thread, and store it on the corresponding
// Panda thread object.
JNIEnv *env;

View File

@ -0,0 +1,361 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file android_main.cxx
* @author rdb
* @date 2021-12-06
*/
#include "config_android.h"
#include "config_putil.h"
#include "virtualFileMountAndroidAsset.h"
#include "virtualFileSystem.h"
#include "filename.h"
#include "thread.h"
#include "urlSpec.h"
#include "android_native_app_glue.h"
#include "Python.h"
#include "structmember.h"
#include <sys/mman.h>
#include <android/log.h>
#include <thread>
// Leave room for future expansion.
#define MAX_NUM_POINTERS 24
// Define an exposed symbol where we store the offset to the module data.
extern "C" {
__attribute__((__visibility__("default"), used))
volatile struct {
uint64_t blob_offset;
uint64_t blob_size;
uint16_t version;
uint16_t num_pointers;
uint16_t codepage;
uint16_t flags;
uint64_t reserved;
void *pointers[MAX_NUM_POINTERS];
// The reason we initialize it to -1 is because otherwise, smart linkers may
// end up putting it in the .bss section for zero-initialized data.
} blobinfo = {(uint64_t)-1};
}
/**
* Maps the binary blob at the given memory address to memory, and returns the
* pointer to the beginning of it.
*/
static void *map_blob(const char *path, off_t offset, size_t size) {
FILE *runtime = fopen(path, "rb");
assert(runtime != NULL);
void *blob = (void *)mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fileno(runtime), offset);
assert(blob != MAP_FAILED);
fclose(runtime);
return blob;
}
/**
* The inverse of map_blob.
*/
static void unmap_blob(void *blob) {
if (blob) {
munmap(blob, blobinfo.blob_size);
}
}
/**
* This function is called by native_app_glue to initialize the program.
*
* Note that this does not run in the main thread, but in a thread created
* specifically for this activity by android_native_app_glue.
*
* Unlike the regular deploy-stub, we need to interface directly with the
* Panda3D libraries here, since we can't pass the pointers from Java to Panda
* through the Python interpreter easily.
*/
void android_main(struct android_app *app) {
panda_android_app = app;
// Attach the app thread to the Java VM.
JNIEnv *env;
ANativeActivity *activity = app->activity;
int attach_status = activity->vm->AttachCurrentThread(&env, nullptr);
if (attach_status < 0 || env == nullptr) {
android_cat.error() << "Failed to attach thread to JVM!\n";
return;
}
// Pipe stdout/stderr to the Android log stream, for convenience.
int pfd[2];
setvbuf(stdout, 0, _IOLBF, 0);
setvbuf(stderr, 0, _IOLBF, 0);
pipe(pfd);
dup2(pfd[1], 1);
dup2(pfd[1], 2);
std::thread t([=] {
ssize_t size;
char buf[4096] = {0};
char *bufstart = buf;
char *const bufend = buf + sizeof(buf) - 1;
while ((size = read(pfd[0], bufstart, bufend - bufstart)) > 0) {
bufstart[size] = 0;
bufstart += size;
while (char *nl = (char *)memchr(buf, '\n', strnlen(buf, bufend - buf))) {
*nl = 0;
__android_log_write(ANDROID_LOG_VERBOSE, "Python", buf);
// Move everything after the newline to the beginning of the buffer.
memmove(buf, nl + 1, bufend - (nl + 1));
bufstart -= (nl + 1) - buf;
}
}
});
jclass activity_class = env->GetObjectClass(activity->clazz);
// Get the current Java thread name. This just helps with debugging.
jmethodID methodID = env->GetStaticMethodID(activity_class, "getCurrentThreadName", "()Ljava/lang/String;");
jstring jthread_name = (jstring) env->CallStaticObjectMethod(activity_class, methodID);
std::string thread_name;
if (jthread_name != nullptr) {
const char *c_str = env->GetStringUTFChars(jthread_name, nullptr);
thread_name.assign(c_str);
env->ReleaseStringUTFChars(jthread_name, c_str);
}
// Before we make any Panda calls, we must make the thread known to Panda.
// This will also cause the JNIEnv pointer to be stored on the thread.
// Note that we must keep a reference to this thread around.
PT(Thread) current_thread = Thread::bind_thread(thread_name, "android_app");
android_cat.info()
<< "New native activity started on " << *current_thread << "\n";
// Fetch the data directory.
jmethodID get_appinfo = env->GetMethodID(activity_class, "getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;");
jobject appinfo = env->CallObjectMethod(activity->clazz, get_appinfo);
jclass appinfo_class = env->GetObjectClass(appinfo);
// Fetch the path to the data directory.
jfieldID datadir_field = env->GetFieldID(appinfo_class, "dataDir", "Ljava/lang/String;");
jstring datadir = (jstring) env->GetObjectField(appinfo, datadir_field);
const char *data_path = env->GetStringUTFChars(datadir, nullptr);
if (data_path != nullptr) {
Filename::_internal_data_dir = data_path;
android_cat.info() << "Path to data: " << data_path << "\n";
env->ReleaseStringUTFChars(datadir, data_path);
}
// Get the cache directory. Set the model-path to this location.
methodID = env->GetMethodID(activity_class, "getCacheDirString", "()Ljava/lang/String;");
jstring jcache_dir = (jstring) env->CallObjectMethod(activity->clazz, methodID);
if (jcache_dir != nullptr) {
const char *cache_dir;
cache_dir = env->GetStringUTFChars(jcache_dir, nullptr);
android_cat.info() << "Path to cache: " << cache_dir << "\n";
ConfigVariableFilename model_cache_dir("model-cache-dir", Filename());
model_cache_dir.set_value(cache_dir);
env->ReleaseStringUTFChars(jcache_dir, cache_dir);
}
// Get the path to the APK.
methodID = env->GetMethodID(activity_class, "getPackageCodePath", "()Ljava/lang/String;");
jstring code_path = (jstring) env->CallObjectMethod(activity->clazz, methodID);
const char *apk_path;
apk_path = env->GetStringUTFChars(code_path, nullptr);
android_cat.info() << "Path to APK: " << apk_path << "\n";
// Get the path to the native library.
methodID = env->GetMethodID(activity_class, "getNativeLibraryPath", "()Ljava/lang/String;");
jstring lib_path_jstr = (jstring) env->CallObjectMethod(activity->clazz, methodID);
const char *lib_path;
lib_path = env->GetStringUTFChars(lib_path_jstr, nullptr);
android_cat.info() << "Path to native library: " << lib_path << "\n";
ExecutionEnvironment::set_binary_name(lib_path);
// Map the blob to memory
void *blob = map_blob(lib_path, (off_t)blobinfo.blob_offset, (size_t)blobinfo.blob_size);
env->ReleaseStringUTFChars(lib_path_jstr, lib_path);
assert(blob != NULL);
assert(blobinfo.num_pointers <= MAX_NUM_POINTERS);
for (uint32_t i = 0; i < blobinfo.num_pointers; ++i) {
// Only offset if the pointer is non-NULL. Except for the first
// pointer, which may never be NULL and usually (but not always)
// points to the beginning of the blob.
if (i == 0 || blobinfo.pointers[i] != nullptr) {
blobinfo.pointers[i] = (void *)((uintptr_t)blobinfo.pointers[i] + (uintptr_t)blob);
}
}
// Now load the configuration files.
ConfigPage *page = nullptr;
ConfigPageManager *cp_mgr;
const char *prc_data = (char *)blobinfo.pointers[1];
if (prc_data != nullptr) {
cp_mgr = ConfigPageManager::get_global_ptr();
std::istringstream in(prc_data);
page = cp_mgr->make_explicit_page("builtin");
page->read_prc(in);
}
// Mount the assets directory.
Filename apk_fn(apk_path);
PT(VirtualFileMountAndroidAsset) asset_mount;
asset_mount = new VirtualFileMountAndroidAsset(app->activity->assetManager, apk_fn);
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
//Filename asset_dir(apk_fn.get_dirname(), "assets");
Filename asset_dir("/android_asset");
vfs->mount(asset_mount, asset_dir, 0);
// Release the apk_path.
env->ReleaseStringUTFChars(code_path, apk_path);
// Now add the asset directory to the model-path.
//TODO: prevent it from adding the directory multiple times.
get_model_path().append_directory(asset_dir);
// Offset the pointers in the module table using the base mmap address.
struct _frozen *moddef = (struct _frozen *)blobinfo.pointers[0];
while (moddef->name) {
moddef->name = (char *)((uintptr_t)moddef->name + (uintptr_t)blob);
if (moddef->code != nullptr) {
moddef->code = (unsigned char *)((uintptr_t)moddef->code + (uintptr_t)blob);
}
//__android_log_print(ANDROID_LOG_DEBUG, "Panda3D", "MOD: %s %p %d\n", moddef->name, (void*)moddef->code, moddef->size);
moddef++;
}
PyImport_FrozenModules = (struct _frozen *)blobinfo.pointers[0];
PyPreConfig preconfig;
PyPreConfig_InitIsolatedConfig(&preconfig);
preconfig.utf8_mode = 1;
PyStatus status = Py_PreInitialize(&preconfig);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
return;
}
PyConfig config;
PyConfig_InitIsolatedConfig(&config);
config.pathconfig_warnings = 0; /* Suppress errors from getpath.c */
config.buffered_stdio = 0;
config.configure_c_stdio = 0;
config.write_bytecode = 0;
status = Py_InitializeFromConfig(&config);
PyConfig_Clear(&config);
if (PyStatus_Exception(status)) {
Py_ExitStatusException(status);
return;
}
// Fetch the path to the library directory.
jfieldID libdir_field = env->GetFieldID(appinfo_class, "nativeLibraryDir", "Ljava/lang/String;");
jstring libdir_jstr = (jstring) env->GetObjectField(appinfo, libdir_field);
const char *libdir = env->GetStringUTFChars(libdir_jstr, nullptr);
if (libdir != nullptr) {
// This is used by the import hook to locate the module libraries.
PyObject *py_native_dir = PyUnicode_FromString(libdir);
PySys_SetObject("_native_library_dir", py_native_dir);
Py_DECREF(py_native_dir);
if (ExecutionEnvironment::get_dtool_name().empty()) {
std::string dtool_name = std::string(libdir) + "/libp3dtool.so";
ExecutionEnvironment::set_dtool_name(dtool_name);
android_cat.info() << "Path to dtool: " << dtool_name << "\n";
}
env->ReleaseStringUTFChars(libdir_jstr, libdir);
}
while (!app->destroyRequested) {
// Call the main module. This will not return until the app is done.
android_cat.info() << "Importing __main__\n";
int n = PyImport_ImportFrozenModule("__main__");
if (n == 0) {
Py_FatalError("__main__ not frozen");
break;
}
if (n < 0) {
PyErr_Print();
}
fsync(1);
fsync(2);
sched_yield();
if (app->destroyRequested) {
// The app closed responding to a destroy request.
break;
}
// Ask Android to clean up the activity.
android_cat.info() << "Exited from __main__, finishing activity\n";
ANativeActivity_finish(activity);
// We still need to keep an event loop going until Android gives us leave
// to end the process.
int looper_id;
int events;
struct android_poll_source *source;
while ((looper_id = ALooper_pollAll(-1, nullptr, &events, (void**)&source)) >= 0) {
// Process this event, but intercept application command events.
if (looper_id == LOOPER_ID_MAIN) {
int8_t cmd = android_app_read_cmd(app);
android_app_pre_exec_cmd(app, cmd);
android_app_post_exec_cmd(app, cmd);
// I don't think we can get a resume command after we call finish(),
// but let's handle it just in case.
if (cmd == APP_CMD_RESUME || cmd == APP_CMD_DESTROY) {
break;
}
} else if (source != nullptr) {
source->process(app, source);
}
}
}
Py_Finalize();
android_cat.info() << "Destroy requested, exiting from android_main\n";
vfs->unmount(asset_mount);
if (page != nullptr) {
cp_mgr->delete_explicit_page(page);
}
unmap_blob(blob);
// Detach the thread before exiting.
activity->vm->DetachCurrentThread();
}