mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
fix(aaptcompiler): merge aaptcompiler from AOSP upstream
This commit is contained in:
Generated
+1
-33
@@ -121,6 +121,7 @@
|
||||
<module name="AndroidIDE.subprojects.fuzzysearch.test" target="11" />
|
||||
<module name="AndroidIDE.subprojects.google-java-format" target="17" />
|
||||
<module name="AndroidIDE.subprojects.google-java-format.test" target="11" />
|
||||
<module name="AndroidIDE.subprojects.indexing.test" target="17" />
|
||||
<module name="AndroidIDE.subprojects.java-compiler-utils.main" target="8" />
|
||||
<module name="AndroidIDE.subprojects.java-compiler-utils.test" target="8" />
|
||||
<module name="AndroidIDE.subprojects.javac" target="11" />
|
||||
@@ -166,50 +167,17 @@
|
||||
<module name="ATS.tree-sitter-log" target="17" />
|
||||
<module name="ATS.tree-sitter-python" target="17" />
|
||||
<module name="ATS.tree-sitter-xml" target="17" />
|
||||
<module name="build-deps.appintro" target="17" />
|
||||
<module name="build-deps.desugaring-core" target="11" />
|
||||
<module name="build-deps.desugaring-core.main" target="11" />
|
||||
<module name="build-deps.desugaring-core.test" target="11" />
|
||||
<module name="build-deps.fuzzysearch" target="17" />
|
||||
<module name="build-deps.fuzzysearch.main" target="17" />
|
||||
<module name="build-deps.fuzzysearch.test" target="17" />
|
||||
<module name="build-deps.google-java-format" target="17" />
|
||||
<module name="build-deps.javac" target="17" />
|
||||
<module name="build-deps.javac.main" target="17" />
|
||||
<module name="build-deps.javac.test" target="17" />
|
||||
<module name="build-deps.javapoet" target="17" />
|
||||
<module name="build-deps.javapoet.main" target="17" />
|
||||
<module name="build-deps.javapoet.test" target="17" />
|
||||
<module name="build-deps.jdk-jdeps" target="17" />
|
||||
<module name="build-deps.jdk-jdeps.main" target="17" />
|
||||
<module name="build-deps.jdk-jdeps.test" target="17" />
|
||||
<module name="build-deps.jdt" target="17" />
|
||||
<module name="build-deps.jdt.main" target="17" />
|
||||
<module name="build-deps.jdt.test" target="17" />
|
||||
<module name="build-deps.layoutlib-api" target="17" />
|
||||
<module name="build-deps.layoutlib-api.main" target="17" />
|
||||
<module name="build-deps.layoutlib-api.test" target="17" />
|
||||
<module name="build-logic.ats" target="17" />
|
||||
<module name="build-logic.ats.main" target="17" />
|
||||
<module name="build-logic.ats.test" target="17" />
|
||||
<module name="build-logic.common" target="17" />
|
||||
<module name="build-logic.common.main" target="17" />
|
||||
<module name="build-logic.common.test" target="17" />
|
||||
<module name="build-logic.desugaring" target="17" />
|
||||
<module name="build-logic.desugaring-core" target="11" />
|
||||
<module name="build-logic.desugaring-core.main" target="11" />
|
||||
<module name="build-logic.desugaring-core.test" target="11" />
|
||||
<module name="build-logic.desugaring.main" target="17" />
|
||||
<module name="build-logic.desugaring.test" target="17" />
|
||||
<module name="build-logic.ide" target="17" />
|
||||
<module name="build-logic.ide.main" target="17" />
|
||||
<module name="build-logic.ide.test" target="17" />
|
||||
<module name="build-logic.plugins" target="17" />
|
||||
<module name="build-logic.plugins.main" target="17" />
|
||||
<module name="build-logic.plugins.test" target="17" />
|
||||
<module name="build-logic.properties-parser" target="17" />
|
||||
<module name="build-logic.properties-parser.main" target="17" />
|
||||
<module name="build-logic.properties-parser.test" target="17" />
|
||||
<module name="composite-builds.build-logic.desugaring-core.main" target="11" />
|
||||
<module name="composite-builds.build-logic.desugaring-core.test" target="11" />
|
||||
<module name="composite-builds.plugins" target="17" />
|
||||
|
||||
@@ -34,6 +34,7 @@ plugins {
|
||||
alias(libs.plugins.kotlin.jvm) apply false
|
||||
alias(libs.plugins.maven.publish) apply false
|
||||
alias(libs.plugins.gradle.publish) apply false
|
||||
alias(libs.plugins.protobuf) apply false
|
||||
}
|
||||
|
||||
buildscript {
|
||||
|
||||
@@ -110,7 +110,7 @@ google-auto-value-annotations = { module = "com.google.auto.value:auto-value-ann
|
||||
google-auto-value-ap = { module = "com.google.auto.value:auto-value", version = "1.10.4" }
|
||||
google-auto-service-annotations = { module = "com.google.auto.service:auto-service-annotations", version = "1.1.1" }
|
||||
google-auto-service = { module = "com.google.auto.service:auto-service", version = "1.1.1" }
|
||||
google-protobuf = { module = "com.google.protobuf:protobuf-java", version = "3.25.3" }
|
||||
google-protobuf = { module = "com.google.protobuf:protobuf-javalite", version = "3.25.3" }
|
||||
google-java-format = { module = "com.google.googlejavaformat:google-java-format", version = "1.20.0" }
|
||||
google-flexbox = { module = "com.google.android.flexbox:flexbox", version = "3.0.0" }
|
||||
|
||||
@@ -169,3 +169,4 @@ kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
maven-publish = { id = "com.vanniktech.maven.publish.base", version.ref = "maven-publish-plugin" }
|
||||
gradle-publish = { id = "com.gradle.plugin-publish", version = "1.2.1" }
|
||||
protobuf = { id = "com.google.protobuf", version = "0.9.4" }
|
||||
|
||||
@@ -23,6 +23,7 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
implementation(libs.androidx.annotation)
|
||||
implementation(libs.androidx.collection)
|
||||
implementation(libs.google.guava)
|
||||
implementation(libs.google.gson)
|
||||
implementation(projects.logger)
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import com.google.protobuf.gradle.id
|
||||
import com.itsaky.androidide.build.config.BuildConfig
|
||||
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("kotlin-android")
|
||||
id("com.google.protobuf")
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -32,15 +34,32 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
protobuf {
|
||||
protoc {
|
||||
artifact = "com.google.protobuf:protoc:4.27.0"
|
||||
}
|
||||
|
||||
generateProtoTasks {
|
||||
all().forEach {
|
||||
it.builtins {
|
||||
id("java") {
|
||||
option("lite")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.common.kotlin)
|
||||
implementation(libs.androidx.collection)
|
||||
implementation(projects.logger)
|
||||
implementation(libs.composite.jaxp)
|
||||
|
||||
implementation(projects.logger)
|
||||
implementation(projects.shared)
|
||||
|
||||
api(libs.aapt2.annotations)
|
||||
api(libs.aapt2.common)
|
||||
api(libs.aapt2.proto)
|
||||
api(libs.google.protobuf)
|
||||
api(libs.composite.layoutlibApi)
|
||||
|
||||
|
||||
Executable → Regular
+3
-1
@@ -1,5 +1,7 @@
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aaptcompiler.android.ResTableConfig
|
||||
|
||||
private const val ANIM_TAG = "anim"
|
||||
private const val ANIMATOR_TAG = "animator"
|
||||
private const val ARRAY_TAG = "array"
|
||||
@@ -29,7 +31,7 @@ private const val TRANSITION_TAG = "transition"
|
||||
private const val XML_TAG = "xml"
|
||||
|
||||
fun resourceTypeFromTag(tag: String) =
|
||||
when (tag) {
|
||||
when(tag) {
|
||||
ANIM_TAG -> AaptResourceType.ANIM
|
||||
ANIMATOR_TAG -> AaptResourceType.ANIMATOR
|
||||
ARRAY_TAG -> AaptResourceType.ARRAY
|
||||
|
||||
Executable → Regular
+45
-21
@@ -19,32 +19,36 @@ package com.android.aaptcompiler
|
||||
import com.android.ide.common.blame.SourceFilePosition
|
||||
import com.android.ide.common.blame.SourcePosition
|
||||
import com.android.utils.ILogger
|
||||
import java.io.File
|
||||
import jaxp.xml.stream.Location
|
||||
import java.io.File
|
||||
|
||||
internal fun blameSource(
|
||||
source: Source,
|
||||
line: Int? = source.line,
|
||||
column: Int? = null
|
||||
): BlameLogger.Source = BlameLogger.Source(source.path, line ?: -1, column ?: -1)
|
||||
): BlameLogger.Source =
|
||||
BlameLogger.Source(source.path, line ?: -1, column ?: -1)
|
||||
|
||||
internal fun blameSource(source: Source, location: Location): BlameLogger.Source =
|
||||
internal fun blameSource(
|
||||
source: Source,
|
||||
location: Location
|
||||
): BlameLogger.Source =
|
||||
BlameLogger.Source(source.path, location.lineNumber, location.columnNumber)
|
||||
|
||||
class BlameLogger
|
||||
constructor(
|
||||
class BlameLogger(
|
||||
val logger: ILogger,
|
||||
private val userVisibleSourceTransform: (String) -> String,
|
||||
val blameMap: (Source) -> Source = { it }
|
||||
) {
|
||||
|
||||
@JvmOverloads
|
||||
constructor(
|
||||
logger: ILogger,
|
||||
blameMap: (Source) -> Source = { it }
|
||||
) : this(logger, { it }, blameMap)
|
||||
constructor(logger: ILogger, blameMap: (Source) -> Source = { it })
|
||||
: this(logger, { it }, blameMap)
|
||||
|
||||
data class Source(val sourcePath: String, val line: Int = -1, val column: Int = -1) {
|
||||
data class Source(
|
||||
val sourcePath: String,
|
||||
val line: Int = -1,
|
||||
val column: Int = -1
|
||||
) {
|
||||
|
||||
override fun toString(): String {
|
||||
var result = sourcePath
|
||||
@@ -58,7 +62,16 @@ constructor(
|
||||
}
|
||||
|
||||
fun toSourceFilePosition() =
|
||||
SourceFilePosition(File(sourcePath), SourcePosition(line, column, -1, line, column, -1))
|
||||
SourceFilePosition(
|
||||
File(sourcePath), SourcePosition(
|
||||
line,
|
||||
column,
|
||||
-1,
|
||||
line,
|
||||
column,
|
||||
-1
|
||||
)
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun fromSourceFilePosition(filePosition: SourceFilePosition) =
|
||||
@@ -79,27 +92,38 @@ constructor(
|
||||
}
|
||||
|
||||
fun warning(message: String, source: Source? = null) {
|
||||
if (source != null) logger.warning("${getOutputSource(source)}$message")
|
||||
else logger.warning(message)
|
||||
if (source != null)
|
||||
logger.warning("${getOutputSource(source)}$message")
|
||||
else
|
||||
logger.warning(message)
|
||||
}
|
||||
|
||||
fun info(message: String, source: Source? = null) {
|
||||
if (source != null) logger.info("${getOutputSource(source)}$message") else logger.info(message)
|
||||
if (source != null)
|
||||
logger.info("${getOutputSource(source)}$message")
|
||||
else
|
||||
logger.info(message)
|
||||
}
|
||||
|
||||
fun lifecycle(message: String, source: Source? = null) {
|
||||
if (source != null) logger.lifecycle("${getOutputSource(source)}$message")
|
||||
else logger.lifecycle(message)
|
||||
if (source != null)
|
||||
logger.lifecycle("${getOutputSource(source)}$message")
|
||||
else
|
||||
logger.lifecycle(message)
|
||||
}
|
||||
|
||||
fun quiet(message: String, source: Source? = null) {
|
||||
if (source != null) logger.quiet("${getOutputSource(source)}$message")
|
||||
else logger.quiet(message)
|
||||
if (source != null)
|
||||
logger.quiet("${getOutputSource(source)}$message")
|
||||
else
|
||||
logger.quiet(message)
|
||||
}
|
||||
|
||||
fun verbose(message: String, source: Source? = null) {
|
||||
if (source != null) logger.verbose("${getOutputSource(source)}$message")
|
||||
else logger.verbose(message)
|
||||
if (source != null)
|
||||
logger.verbose("${getOutputSource(source)}$message")
|
||||
else
|
||||
logger.verbose(message)
|
||||
}
|
||||
|
||||
internal fun getOutputSource(source: Source): Source {
|
||||
|
||||
Executable → Regular
+8
@@ -63,6 +63,13 @@ fun parse(config: String): ConfigDescription {
|
||||
return configDescription
|
||||
}
|
||||
|
||||
if (parseGrammaticalInflection(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if(parseLayoutDirection(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
@@ -221,6 +228,7 @@ private fun applyVersionForCompatibility(config: ConfigDescription): ConfigDescr
|
||||
config.layoutSize() != ResTableConfig.SCREEN_LAYOUT.SIZE_ANY ||
|
||||
config.layoutLong() != ResTableConfig.SCREEN_LAYOUT.SCREENLONG_ANY ||
|
||||
config.density != ResTableConfig.DENSITY.DEFAULT -> SDKConstants.SDK_DONUT
|
||||
config.grammaticalInflection != ResTableConfig.GRAMMATICAL_GENDER.ANY -> SDKConstants.SDK_U
|
||||
else -> 0
|
||||
}
|
||||
|
||||
|
||||
Executable → Regular
+38
-41
@@ -27,9 +27,8 @@ fun parseMcc(part: String, config: ConfigDescription): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
// mnc may have a dynamic sized value ranging from 2 to 3 digits. It is possible to have unique
|
||||
// mcn such as 01 and 001 that are represented by the number digits.
|
||||
if (!part.startsWith("mnc") || part.length !in 4..6) {
|
||||
// The only acceptable format is "mccDDD" (where D is a digit).
|
||||
if (!part.startsWith("mcc") || part.length != 6) {
|
||||
return false
|
||||
}
|
||||
val value = part.substring(3).toIntOrNull()?.toShort() ?: return false
|
||||
@@ -44,8 +43,9 @@ fun parseMnc(part: String, config: ConfigDescription): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
// The only acceptable format is "mncDDD" (where D is a digit).
|
||||
if (!part.startsWith("mnc") || part.length != 6) {
|
||||
// mnc may have a dynamic sized value ranging from 2 to 3 digits. It is possible to have unique
|
||||
// mcn such as 01 and 001 that are represented by the number digits.
|
||||
if (!part.startsWith("mnc") || part.length !in 4..6) {
|
||||
return false
|
||||
}
|
||||
val value = part.substring(3).toIntOrNull()?.toShort() ?: return false
|
||||
@@ -56,9 +56,8 @@ fun parseMnc(part: String, config: ConfigDescription): Boolean {
|
||||
}
|
||||
|
||||
// TODO(@daniellabar): Make more like the aapt2 parser.
|
||||
fun parseLayoutDirection(part: String, config: ConfigDescription): Boolean {
|
||||
val value =
|
||||
when (part) {
|
||||
fun parseLayoutDirection(part: String, config: ConfigDescription) : Boolean {
|
||||
val value = when(part) {
|
||||
WILDCARD_NAME -> ResTableConfig.SCREEN_LAYOUT.DIR_ANY
|
||||
"ldltr" -> ResTableConfig.SCREEN_LAYOUT.DIR_LTR
|
||||
"ldrtl" -> ResTableConfig.SCREEN_LAYOUT.DIR_RTL
|
||||
@@ -78,7 +77,7 @@ fun parseSmallestScreenWidthDp(part: String, config: ConfigDescription): Boolean
|
||||
if (!part.startsWith("sw") || !part.endsWith("dp")) {
|
||||
return false
|
||||
}
|
||||
val value = part.substring(2, part.length - 2).toIntOrNull() ?: return false
|
||||
val value = part.substring(2, part.length-2).toIntOrNull() ?: return false
|
||||
config.smallestScreenWidthDp = value
|
||||
return true
|
||||
}
|
||||
@@ -91,7 +90,7 @@ fun parseScreenWidthDp(part: String, config: ConfigDescription): Boolean {
|
||||
if (!part.startsWith('w') || !part.endsWith("dp")) {
|
||||
return false
|
||||
}
|
||||
val value = part.substring(1, part.length - 2).toIntOrNull() ?: return false
|
||||
val value = part.substring(1, part.length-2).toIntOrNull() ?: return false
|
||||
config.screenWidthDp = value
|
||||
return true
|
||||
}
|
||||
@@ -104,14 +103,13 @@ fun parseScreenHeightDp(part: String, config: ConfigDescription): Boolean {
|
||||
if (!part.startsWith('h') || !part.endsWith("dp")) {
|
||||
return false
|
||||
}
|
||||
val value = part.substring(1, part.length - 2).toIntOrNull() ?: return false
|
||||
val value = part.substring(1, part.length-2).toIntOrNull() ?: return false
|
||||
config.screenHeightDp = value
|
||||
return true
|
||||
}
|
||||
|
||||
fun parseScreenLayoutSize(part: String, config: ConfigDescription): Boolean {
|
||||
val value =
|
||||
when (part) {
|
||||
val value = when (part) {
|
||||
WILDCARD_NAME -> 0
|
||||
"small" -> ResTableConfig.SCREEN_LAYOUT.SIZE_SMALL
|
||||
"normal" -> ResTableConfig.SCREEN_LAYOUT.SIZE_NORMAL
|
||||
@@ -126,8 +124,7 @@ fun parseScreenLayoutSize(part: String, config: ConfigDescription): Boolean {
|
||||
}
|
||||
|
||||
fun parseScreenLayoutLong(part: String, config: ConfigDescription): Boolean {
|
||||
val value =
|
||||
when (part) {
|
||||
val value = when (part) {
|
||||
WILDCARD_NAME -> ResTableConfig.SCREEN_LAYOUT.SCREENLONG_ANY
|
||||
"long" -> ResTableConfig.SCREEN_LAYOUT.SCREENLONG_YES
|
||||
"notlong" -> ResTableConfig.SCREEN_LAYOUT.SCREENLONG_NO
|
||||
@@ -140,8 +137,7 @@ fun parseScreenLayoutLong(part: String, config: ConfigDescription): Boolean {
|
||||
}
|
||||
|
||||
fun parseScreenRound(part: String, config: ConfigDescription): Boolean {
|
||||
val value =
|
||||
when (part) {
|
||||
val value = when (part) {
|
||||
WILDCARD_NAME -> ResTableConfig.SCREEN_LAYOUT2.SCREENROUND_ANY
|
||||
"round" -> ResTableConfig.SCREEN_LAYOUT2.SCREENROUND_YES
|
||||
"notround" -> ResTableConfig.SCREEN_LAYOUT2.SCREENROUND_NO
|
||||
@@ -153,8 +149,7 @@ fun parseScreenRound(part: String, config: ConfigDescription): Boolean {
|
||||
}
|
||||
|
||||
fun parseWideColorGamut(part: String, config: ConfigDescription): Boolean {
|
||||
val value =
|
||||
when (part) {
|
||||
val value = when (part) {
|
||||
WILDCARD_NAME -> ResTableConfig.COLOR_MODE.WIDE_GAMUT_ANY
|
||||
"widecg" -> ResTableConfig.COLOR_MODE.WIDE_GAMUT_YES
|
||||
"nowidecg" -> ResTableConfig.COLOR_MODE.WIDE_GAMUT_NO
|
||||
@@ -166,8 +161,7 @@ fun parseWideColorGamut(part: String, config: ConfigDescription): Boolean {
|
||||
}
|
||||
|
||||
fun parseHdr(part: String, config: ConfigDescription): Boolean {
|
||||
val value =
|
||||
when (part) {
|
||||
val value = when (part) {
|
||||
WILDCARD_NAME -> ResTableConfig.COLOR_MODE.HDR_ANY
|
||||
"highdr" -> ResTableConfig.COLOR_MODE.HDR_YES
|
||||
"lowdr" -> ResTableConfig.COLOR_MODE.HDR_NO
|
||||
@@ -178,8 +172,7 @@ fun parseHdr(part: String, config: ConfigDescription): Boolean {
|
||||
}
|
||||
|
||||
fun parseOrientation(part: String, config: ConfigDescription): Boolean {
|
||||
config.orientation =
|
||||
when (part) {
|
||||
config.orientation = when (part) {
|
||||
WILDCARD_NAME -> ResTableConfig.ORIENTATION.ANY
|
||||
"port" -> ResTableConfig.ORIENTATION.PORT
|
||||
"land" -> ResTableConfig.ORIENTATION.LAND
|
||||
@@ -190,8 +183,7 @@ fun parseOrientation(part: String, config: ConfigDescription): Boolean {
|
||||
}
|
||||
|
||||
fun parseUiModeType(part: String, config: ConfigDescription): Boolean {
|
||||
val value =
|
||||
when (part) {
|
||||
val value = when (part) {
|
||||
WILDCARD_NAME -> ResTableConfig.UI_MODE.TYPE_ANY
|
||||
"desk" -> ResTableConfig.UI_MODE.TYPE_DESK
|
||||
"car" -> ResTableConfig.UI_MODE.TYPE_CAR
|
||||
@@ -206,8 +198,7 @@ fun parseUiModeType(part: String, config: ConfigDescription): Boolean {
|
||||
}
|
||||
|
||||
fun parseUiModeNight(part: String, config: ConfigDescription): Boolean {
|
||||
val value =
|
||||
when (part) {
|
||||
val value = when (part) {
|
||||
WILDCARD_NAME -> ResTableConfig.UI_MODE.NIGHT_ANY
|
||||
"night" -> ResTableConfig.UI_MODE.NIGHT_YES
|
||||
"notnight" -> ResTableConfig.UI_MODE.NIGHT_NO
|
||||
@@ -219,8 +210,7 @@ fun parseUiModeNight(part: String, config: ConfigDescription): Boolean {
|
||||
|
||||
fun parseDensity(part: String, config: ConfigDescription): Boolean {
|
||||
if (part.isNotEmpty() && part[0].isLetter()) {
|
||||
config.density =
|
||||
when (part) {
|
||||
config.density = when (part) {
|
||||
WILDCARD_NAME -> ResTableConfig.DENSITY.DEFAULT
|
||||
"anydpi" -> ResTableConfig.DENSITY.ANY
|
||||
"nodpi" -> ResTableConfig.DENSITY.NONE
|
||||
@@ -239,15 +229,14 @@ fun parseDensity(part: String, config: ConfigDescription): Boolean {
|
||||
if (!part.endsWith("dpi")) {
|
||||
return false
|
||||
}
|
||||
val value = part.substring(0, part.length - 3).toIntOrNull() ?: return false
|
||||
val value = part.substring(0, part.length-3).toIntOrNull() ?: return false
|
||||
config.density = value
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
fun parseTouchscreen(part: String, config: ConfigDescription): Boolean {
|
||||
config.touchscreen =
|
||||
when (part) {
|
||||
config.touchscreen = when (part) {
|
||||
WILDCARD_NAME -> ResTableConfig.TOUCHSCREEN.ANY
|
||||
"notouch" -> ResTableConfig.TOUCHSCREEN.NOTOUCH
|
||||
"stylus" -> ResTableConfig.TOUCHSCREEN.STYLUS
|
||||
@@ -258,8 +247,7 @@ fun parseTouchscreen(part: String, config: ConfigDescription): Boolean {
|
||||
}
|
||||
|
||||
fun parseKeysHidden(part: String, config: ConfigDescription): Boolean {
|
||||
val value =
|
||||
when (part) {
|
||||
val value = when (part) {
|
||||
WILDCARD_NAME -> ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_ANY
|
||||
"keysexposed" -> ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_NO
|
||||
"keyshidden" -> ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_YES
|
||||
@@ -272,8 +260,7 @@ fun parseKeysHidden(part: String, config: ConfigDescription): Boolean {
|
||||
}
|
||||
|
||||
fun parseKeyboard(part: String, config: ConfigDescription): Boolean {
|
||||
config.keyboard =
|
||||
when (part) {
|
||||
config.keyboard = when (part) {
|
||||
WILDCARD_NAME -> ResTableConfig.KEYBOARD.ANY
|
||||
"nokeys" -> ResTableConfig.KEYBOARD.NOKEYS
|
||||
"qwerty" -> ResTableConfig.KEYBOARD.QWERTY
|
||||
@@ -284,8 +271,7 @@ fun parseKeyboard(part: String, config: ConfigDescription): Boolean {
|
||||
}
|
||||
|
||||
fun parseNavHidden(part: String, config: ConfigDescription): Boolean {
|
||||
val value =
|
||||
when (part) {
|
||||
val value = when (part) {
|
||||
WILDCARD_NAME -> ResTableConfig.INPUT_FLAGS.NAVHIDDEN_ANY
|
||||
"navexposed" -> ResTableConfig.INPUT_FLAGS.NAVHIDDEN_NO
|
||||
"navhidden" -> ResTableConfig.INPUT_FLAGS.NAVHIDDEN_YES
|
||||
@@ -297,8 +283,7 @@ fun parseNavHidden(part: String, config: ConfigDescription): Boolean {
|
||||
}
|
||||
|
||||
fun parseNavigation(part: String, config: ConfigDescription): Boolean {
|
||||
config.navigation =
|
||||
when (part) {
|
||||
config.navigation = when (part) {
|
||||
WILDCARD_NAME -> ResTableConfig.NAVIGATION.ANY
|
||||
"nonav" -> ResTableConfig.NAVIGATION.NONAV
|
||||
"dpad" -> ResTableConfig.NAVIGATION.DPAD
|
||||
@@ -309,6 +294,17 @@ fun parseNavigation(part: String, config: ConfigDescription): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
fun parseGrammaticalInflection(part: String, config: ConfigDescription): Boolean {
|
||||
config.grammaticalInflection = when (part) {
|
||||
WILDCARD_NAME -> ResTableConfig.GRAMMATICAL_GENDER.ANY
|
||||
"neuter" -> ResTableConfig.GRAMMATICAL_GENDER.NEUTER
|
||||
"feminine" -> ResTableConfig.GRAMMATICAL_GENDER.FEMININE
|
||||
"masculine" -> ResTableConfig.GRAMMATICAL_GENDER.MASCULINE
|
||||
else -> return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun parseScreenSize(part: String, config: ConfigDescription): Boolean {
|
||||
if (part == WILDCARD_NAME) {
|
||||
config.screenWidth = 0
|
||||
@@ -346,5 +342,6 @@ fun parseVersion(part: String, config: ConfigDescription): Boolean {
|
||||
|
||||
fun maskAndApply(current: Byte, mask: Int, value: Byte) =
|
||||
maskAndApply(current.toInt(), mask, value.toInt()).toByte()
|
||||
fun maskAndApply(current: Int, mask: Int, value: Int): Int =
|
||||
(current and mask.inv()) or value
|
||||
|
||||
fun maskAndApply(current: Int, mask: Int, value: Int): Int = (current and mask.inv()) or value
|
||||
|
||||
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
+39
-61
@@ -18,9 +18,9 @@
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aaptcompiler.proto.serializeTableToPb
|
||||
import com.android.utils.FileUtils
|
||||
import com.itsaky.androidide.layoutlib.resources.ResourceType
|
||||
import com.itsaky.androidide.layoutlib.resources.ResourceVisibility
|
||||
import com.android.utils.FileUtils
|
||||
import java.io.File
|
||||
|
||||
private const val VALUES_DIRECTORY_PREFIX = "values"
|
||||
@@ -40,23 +40,22 @@ private const val PNG_EXTENSION = "png"
|
||||
* @param requirePngCrunching whether PNG file crunching is enabled
|
||||
* @param pseudolocalize Whether or not the pseudolocales en-XA and ar-XB are generated for default
|
||||
* string resources.
|
||||
* @param partialRFile file to output symbols defined in the resource file (currently only supported
|
||||
* for non-raw XML files (e.g. values or layouts) to match AAPT2's behaviour)
|
||||
* @param partialRFile file to output symbols defined in the resource file (currently only
|
||||
* supported for non-raw XML files (e.g. values or layouts) to match AAPT2's behaviour)
|
||||
* @param legacyMode Whether or not to error or warn on positional args not being specified in a
|
||||
* translatable string with parameters.
|
||||
* @param verbose Whether or not to show verbose logs.
|
||||
* @param sourcePath Specified source path to be written in the compiled resource.
|
||||
*/
|
||||
data class ResourceCompilerOptions(
|
||||
val generateSymbolsPathData: ResourcePathData? = null,
|
||||
val generateSymbolsPathData: ResourcePathData?= null,
|
||||
val visibility: ResourceVisibility? = null,
|
||||
val requirePngCrunching: Boolean = false,
|
||||
val pseudolocalize: Boolean = false,
|
||||
val partialRFile: File? = null,
|
||||
val legacyMode: Boolean = false,
|
||||
val verbose: Boolean = false,
|
||||
val sourcePath: String? = null
|
||||
)
|
||||
val sourcePath: String? = null)
|
||||
|
||||
/**
|
||||
* Shows whether the ResourceCompiler can compile the given Resource File.
|
||||
@@ -69,9 +68,8 @@ fun canCompileResourceInJvm(file: File, requirePngCrunching: Boolean): Boolean {
|
||||
if (file.isHidden) return true
|
||||
|
||||
val pathData = extractPathData(file)
|
||||
if (
|
||||
pathData.resourceDirectory == VALUES_DIRECTORY_PREFIX && pathData.extension == XML_EXTENSION
|
||||
) {
|
||||
if (pathData.resourceDirectory == VALUES_DIRECTORY_PREFIX
|
||||
&& pathData.extension == XML_EXTENSION) {
|
||||
// file is a values table.
|
||||
return true
|
||||
} else {
|
||||
@@ -108,11 +106,7 @@ fun canCompileResourceInJvm(file: File, requirePngCrunching: Boolean): Boolean {
|
||||
* See [canCompileResourceInJvm] to see what is supported.
|
||||
*/
|
||||
fun compileResource(
|
||||
file: File,
|
||||
outputDirectory: File,
|
||||
options: ResourceCompilerOptions,
|
||||
logger: BlameLogger
|
||||
) {
|
||||
file: File, outputDirectory: File, options: ResourceCompilerOptions, logger: BlameLogger) {
|
||||
|
||||
// Skip hidden files.
|
||||
if (file.isHidden) {
|
||||
@@ -136,20 +130,16 @@ fun compileResource(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCompileMethod(
|
||||
pathData: ResourcePathData,
|
||||
logger: BlameLogger
|
||||
): (ResourcePathData, File, ResourceCompilerOptions, BlameLogger) -> Unit {
|
||||
if (
|
||||
pathData.resourceDirectory == VALUES_DIRECTORY_PREFIX && pathData.extension == XML_EXTENSION
|
||||
) {
|
||||
private fun getCompileMethod(pathData: ResourcePathData, logger: BlameLogger):
|
||||
(ResourcePathData, File, ResourceCompilerOptions, BlameLogger) -> Unit {
|
||||
if (pathData.resourceDirectory == VALUES_DIRECTORY_PREFIX &&
|
||||
pathData.extension == XML_EXTENSION) {
|
||||
pathData.extension = RESOURCE_TABLE_EXTENSION
|
||||
return ::compileTable
|
||||
} else {
|
||||
val type = ResourceType.fromFolderName(pathData.resourceDirectory)
|
||||
if (type == null) {
|
||||
val errorMsg =
|
||||
"Invalid resource type '${pathData.resourceDirectory}'" +
|
||||
val errorMsg = "Invalid resource type '${pathData.resourceDirectory}'" +
|
||||
" for file ${pathData.file.absolutePath}"
|
||||
logger?.warning(errorMsg)
|
||||
error(errorMsg)
|
||||
@@ -168,9 +158,9 @@ private fun getCompileMethod(
|
||||
/**
|
||||
* Compiles a xml values file into a flattened [ResourceTable] proto.
|
||||
*
|
||||
* After all resources are extracted from the given xml, if pseudolocalization is set, pseudolocale
|
||||
* strings are created for each default string resource in the xml. The result is flattened to a
|
||||
* file in the output directory.
|
||||
* After all resources are extracted from the given xml, if pseudolocalization is set,
|
||||
* pseudolocale strings are created for each default string resource in the xml. The result is
|
||||
* flattened to a file in the output directory.
|
||||
*
|
||||
* @param pathData the file to be processed.
|
||||
* @param outputDirectory the directory to which the compiled file is to be placed.
|
||||
@@ -180,19 +170,16 @@ private fun compileTable(
|
||||
pathData: ResourcePathData,
|
||||
outputDirectory: File,
|
||||
options: ResourceCompilerOptions,
|
||||
logger: BlameLogger
|
||||
) {
|
||||
logger: BlameLogger) {
|
||||
val outputFile = File(outputDirectory, pathData.getIntermediateContainerFilename())
|
||||
logger?.info("Compiling XML table ${pathData.file.absolutePath} to $outputFile")
|
||||
|
||||
val table = ResourceTable(logger = logger)
|
||||
|
||||
val extractorOptions =
|
||||
TableExtractorOptions(
|
||||
val extractorOptions = TableExtractorOptions(
|
||||
translatable = !pathData.name.contains("donottranslate"),
|
||||
errorOnPositionalArgs = !options.legacyMode,
|
||||
visibility = options.visibility
|
||||
)
|
||||
visibility = options.visibility)
|
||||
val tableExtractor =
|
||||
TableExtractor(table, pathData.source, pathData.config, extractorOptions, logger)
|
||||
|
||||
@@ -203,8 +190,7 @@ private fun compileTable(
|
||||
// For merged values there's no need to re-write as we don't know which line failed. The
|
||||
// actual error will be raised by the table extractor.
|
||||
throw ResourceCompilationException(
|
||||
"Failed to compile values resource file ${pathData.file}",
|
||||
e
|
||||
"Failed to compile values resource file ${pathData.file}", e
|
||||
)
|
||||
}
|
||||
|
||||
@@ -235,17 +221,14 @@ private fun compileTable(
|
||||
val javaType = if (group.type == AaptResourceType.STYLEABLE) "int[]" else "int"
|
||||
group.entries.forEach { entry ->
|
||||
val visibility = getVisibility(entry.value.values, group.type)
|
||||
builder.appendLine(
|
||||
"${visibility.getName()} $javaType ${group.type.tagName} ${entry.key}"
|
||||
)
|
||||
builder.appendln("${visibility.getName()} $javaType ${group.type.tagName} ${entry.key}")
|
||||
if (group.type == AaptResourceType.STYLEABLE) {
|
||||
// We also need to write down styleable children (entries)
|
||||
group.getStyleable(entry).entries.forEach {
|
||||
val childPackage = if (!it.name.pck.isNullOrEmpty()) "_${it.name.pck}" else ""
|
||||
val childPackage =
|
||||
if (!it.name.pck.isNullOrEmpty()) "_${it.name.pck}" else ""
|
||||
// styleables and their children are always public
|
||||
builder.appendln(
|
||||
"public int styleable ${entry.key}${childPackage}_${it.name.entry}"
|
||||
)
|
||||
builder.appendln("public int styleable ${entry.key}${childPackage}_${it.name.entry}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,10 +240,7 @@ private fun compileTable(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getVisibility(
|
||||
values: Collection<ResourceEntry>,
|
||||
type: AaptResourceType
|
||||
): ResourceVisibility {
|
||||
private fun getVisibility(values: Collection<ResourceEntry>, type: AaptResourceType): ResourceVisibility {
|
||||
// all declare styleables need to be marked as public so they're visible in the R classes
|
||||
if (type == AaptResourceType.STYLEABLE) return ResourceVisibility.PUBLIC
|
||||
var foundPublic = false
|
||||
@@ -287,13 +267,11 @@ private fun compileFile(
|
||||
pathData: ResourcePathData,
|
||||
outputDirectory: File,
|
||||
options: ResourceCompilerOptions,
|
||||
logger: BlameLogger?
|
||||
) {
|
||||
logger: BlameLogger?) {
|
||||
val outputFile = File(outputDirectory, pathData.getIntermediateContainerFilename())
|
||||
logger?.info("Compiling file ${pathData.file.absolutePath} to $outputFile")
|
||||
pathData.file.inputStream().use {
|
||||
val resourceFile =
|
||||
ResourceFile(
|
||||
val resourceFile = ResourceFile(
|
||||
ResourceName("", resourceTypeFromTag(pathData.resourceDirectory)!!, pathData.name),
|
||||
pathData.config,
|
||||
pathData.source,
|
||||
@@ -331,13 +309,11 @@ private fun compileXml(
|
||||
pathData: ResourcePathData,
|
||||
outputDirectory: File,
|
||||
options: ResourceCompilerOptions,
|
||||
logger: BlameLogger?
|
||||
) {
|
||||
logger: BlameLogger?) {
|
||||
val outputFile = File(outputDirectory, pathData.getIntermediateContainerFilename())
|
||||
logger?.info("Compiling xml file ${pathData.file.absolutePath} to $outputFile")
|
||||
|
||||
val fileToProcess =
|
||||
ResourceFile(
|
||||
val fileToProcess = ResourceFile(
|
||||
ResourceName("", pathData.type!!, pathData.name),
|
||||
pathData.config,
|
||||
pathData.source,
|
||||
@@ -350,12 +326,14 @@ private fun compileXml(
|
||||
xmlProcessor.process(fileToProcess, it)
|
||||
} catch (e: Exception) {
|
||||
throw ResourceCompilationException(
|
||||
"Failed to compile resource file: " + logger?.getOutputSource(blameSource(pathData.source)),
|
||||
"Failed to compile resource file: " +
|
||||
logger?.getOutputSource(blameSource(pathData.source)),
|
||||
e
|
||||
)
|
||||
}
|
||||
|
||||
val container = Container(outputFile.outputStream(), xmlProcessor.xmlResources.size)
|
||||
val container =
|
||||
Container(outputFile.outputStream(), xmlProcessor.xmlResources.size)
|
||||
|
||||
for (resource in xmlProcessor.xmlResources) {
|
||||
container.addXmlEntry(resource)
|
||||
@@ -363,9 +341,9 @@ private fun compileXml(
|
||||
|
||||
if (options.partialRFile != null) {
|
||||
val builder = StringBuilder()
|
||||
builder.appendLine("default int ${pathData.type.tagName} ${pathData.name}")
|
||||
builder.appendln("default int ${pathData.type.tagName} ${pathData.name}")
|
||||
fileToProcess.exportedSymbols.forEach { id ->
|
||||
builder.appendLine("default int id ${id.name.entry}")
|
||||
builder.appendln("default int id ${id.name.entry}")
|
||||
}
|
||||
FileUtils.writeToFile(options.partialRFile, builder.toString())
|
||||
}
|
||||
@@ -381,8 +359,9 @@ private fun compileXml(
|
||||
*
|
||||
* If we are not running in debug mode, the png will undergo additional crunching.
|
||||
*
|
||||
* Finally, the processed file is written to the output directory. It is possible that no processing
|
||||
* is done to the png file, and if so it will just be written exactly as if it were a raw file.
|
||||
* Finally, the processed file is written to the output directory. It is possible that no
|
||||
* processing is done to the png file, and if so it will just be written exactly as if it were
|
||||
* a raw file.
|
||||
*
|
||||
* @param pathData the file to process.
|
||||
* @param outputDirectory the directory in which the processed file will be placed.
|
||||
@@ -391,8 +370,7 @@ private fun compilePng(
|
||||
pathData: ResourcePathData,
|
||||
outputDirectory: File,
|
||||
options: ResourceCompilerOptions,
|
||||
logger: BlameLogger?
|
||||
) {
|
||||
logger: BlameLogger?) {
|
||||
logger?.info("Compiling image file ${pathData.file.absolutePath}")
|
||||
if (pathData.extension == PATCH_9_EXTENSION) {
|
||||
error("Patch 9 PNG processing is not supported with the JVM Android resource compiler.")
|
||||
|
||||
Executable → Regular
Executable → Regular
+3
-3
@@ -60,17 +60,17 @@ fun extractPathData(file: File, sourcePath: String = file.absolutePath) : Resour
|
||||
else file.name
|
||||
val source = Source(sourcePath)
|
||||
// TODO(b/142481190): think about obfuscation
|
||||
val parentName = file.parentFile!!.name
|
||||
val parentName = file.parentFile.name
|
||||
val type = parentName.substringBefore("-")
|
||||
val config = if (type != parentName) {
|
||||
file.parentFile!!.name.substringAfter(type).substring(1)
|
||||
file.parentFile.name.substringAfter(type).substring(1)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
val configDescription = parse(config)
|
||||
|
||||
return ResourcePathData(
|
||||
source, extension.lowercase(), resName, type, config, file, configDescription)
|
||||
source, extension.toLowerCase(), resName, type, config, file, configDescription)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Executable → Regular
+73
-150
@@ -1,6 +1,6 @@
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import android.util.SparseArray
|
||||
import androidx.collection.mutableIntObjectMapOf
|
||||
import com.android.aapt.Resources
|
||||
import com.itsaky.androidide.layoutlib.resources.ResourceVisibility
|
||||
import java.io.File
|
||||
@@ -17,10 +17,9 @@ import java.util.TreeMap
|
||||
* resources from libraries and are not validated.
|
||||
*/
|
||||
class ResourceTable(val validateResources: Boolean = false, val logger: BlameLogger? = null) {
|
||||
|
||||
/**
|
||||
* The string pool used by this resource table. Values that reference strings must use this pool
|
||||
* to create their strings.
|
||||
* The string pool used by this resource table. Values that reference strings must use
|
||||
* this pool to create their strings.
|
||||
*/
|
||||
val stringPool = StringPool()
|
||||
|
||||
@@ -31,7 +30,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
* Set of dynamic packages that this table may reference. Their package names get encoded into the
|
||||
* resources.arsc along with their compile-time assigned IDs.
|
||||
*/
|
||||
private val includedPackages = SparseArray<String>()
|
||||
private val includedPackages = mutableIntObjectMapOf<String>()
|
||||
|
||||
enum class CollisionResult {
|
||||
KEEP_ORIGINAL,
|
||||
@@ -40,10 +39,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
}
|
||||
|
||||
data class SearchResult(
|
||||
val tablePackage: ResourceTablePackage,
|
||||
val group: ResourceGroup,
|
||||
val entry: ResourceEntry
|
||||
)
|
||||
val tablePackage: ResourceTablePackage, val group: ResourceGroup, val entry: ResourceEntry)
|
||||
|
||||
/**
|
||||
* Adds a resource to the table with the given value.
|
||||
@@ -58,20 +54,10 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
* the table.
|
||||
*/
|
||||
fun addResource(
|
||||
name: ResourceName,
|
||||
config: ConfigDescription,
|
||||
product: String,
|
||||
value: Value
|
||||
): Boolean =
|
||||
name: ResourceName, config: ConfigDescription, product: String, value: Value): Boolean =
|
||||
addResourceImpl(
|
||||
name,
|
||||
0,
|
||||
config,
|
||||
product,
|
||||
value,
|
||||
::resourceNameValidator,
|
||||
::resolveValueCollision
|
||||
)
|
||||
name, 0, config, product, value, ::resourceNameValidator, ::resolveValueCollision)
|
||||
|
||||
|
||||
/**
|
||||
* Adds a resource to the table with the given id and value.
|
||||
@@ -91,17 +77,9 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
id: Int,
|
||||
config: ConfigDescription,
|
||||
product: String,
|
||||
value: Value
|
||||
): Boolean =
|
||||
value: Value): Boolean =
|
||||
addResourceImpl(
|
||||
name,
|
||||
id,
|
||||
config,
|
||||
product,
|
||||
value,
|
||||
::resourceNameValidator,
|
||||
::resolveValueCollision
|
||||
)
|
||||
name, id, config, product, value, ::resourceNameValidator, ::resolveValueCollision)
|
||||
|
||||
/**
|
||||
* Adds a file reference resource to the table with the given file path.
|
||||
@@ -116,11 +94,9 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
* the table.
|
||||
*/
|
||||
fun addFileReference(
|
||||
name: ResourceName,
|
||||
config: ConfigDescription,
|
||||
source: Source,
|
||||
path: String
|
||||
): Boolean = addFileReferenceImpl(name, config, source, path, null, ::resourceNameValidator)
|
||||
name: ResourceName,config: ConfigDescription, source: Source, path: String): Boolean =
|
||||
addFileReferenceImpl(
|
||||
name, config, source, path, null, ::resourceNameValidator)
|
||||
|
||||
/**
|
||||
* Same as [addFileReference], but doesn't verify the name of the file reference resource. This is
|
||||
@@ -142,8 +118,8 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
config: ConfigDescription,
|
||||
source: Source,
|
||||
path: String,
|
||||
file: File
|
||||
): Boolean = addFileReferenceImpl(name, config, source, path, file, ::skipNameValidator)
|
||||
file: File): Boolean =
|
||||
addFileReferenceImpl(name, config, source, path, file, ::skipNameValidator)
|
||||
|
||||
/**
|
||||
* Same as [addResource], but doesn't verify the name of the resource. This is used when loading
|
||||
@@ -158,12 +134,9 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
* there exists a conflict with a resource already in the table.
|
||||
*/
|
||||
fun addResourceMangled(
|
||||
name: ResourceName,
|
||||
config: ConfigDescription,
|
||||
product: String,
|
||||
value: Value
|
||||
): Boolean =
|
||||
addResourceImpl(name, 0, config, product, value, ::skipNameValidator, ::resolveValueCollision)
|
||||
name: ResourceName, config: ConfigDescription, product: String, value: Value): Boolean =
|
||||
addResourceImpl(
|
||||
name, 0, config, product, value, ::skipNameValidator, ::resolveValueCollision)
|
||||
|
||||
/**
|
||||
* Same as [addResourceWithId], but doesn't verify the name of the resource. This is used when
|
||||
@@ -184,9 +157,9 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
id: Int,
|
||||
config: ConfigDescription,
|
||||
product: String,
|
||||
value: Value
|
||||
) =
|
||||
addResourceImpl(name, id, config, product, value, ::skipNameValidator, ::resolveValueCollision)
|
||||
value: Value) =
|
||||
addResourceImpl(
|
||||
name, id, config, product, value, ::skipNameValidator, ::resolveValueCollision)
|
||||
|
||||
/**
|
||||
* Sets the resource with the given name to the set visibility. If this resource has no value in
|
||||
@@ -235,13 +208,13 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the package struct with the given name, or null if such a package does not exist. The
|
||||
* empty string is a valid package and typically is used to represent the 'current' package before
|
||||
* it is known to the ResourceTable.
|
||||
* Returns the package struct with the given name, or null if such a package does not
|
||||
* exist. The empty string is a valid package and typically is used to represent the
|
||||
* 'current' package before it is known to the ResourceTable.
|
||||
*
|
||||
* @param name the name of the package.
|
||||
* @return the [ResourceTablePackage] with the requested name or {@code null} if that package does
|
||||
* not exist in the table.
|
||||
* @return the [ResourceTablePackage] with the requested name or {@code null} if that package
|
||||
* does not exist in the table.
|
||||
*/
|
||||
fun findPackage(name: String): ResourceTablePackage? {
|
||||
return packages.find { it.name == name }
|
||||
@@ -260,7 +233,6 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
tablePackage.id = id
|
||||
return tablePackage
|
||||
}
|
||||
|
||||
tablePackage.id != id -> return null
|
||||
}
|
||||
}
|
||||
@@ -269,8 +241,8 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find a package having the specified name and ID. If not found, a new package of the
|
||||
* specified parameters is created and returned.
|
||||
* Attempts to find a package having the specified name and ID. If not found, a new package
|
||||
* of the specified parameters is created and returned.
|
||||
*/
|
||||
fun createPackageAllowingDuplicateNames(name: String, id: Byte): ResourceTablePackage {
|
||||
val match = packages.find { it.name == name && it.id == id }
|
||||
@@ -291,15 +263,14 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
packages.add(newPackage)
|
||||
newPackage
|
||||
}
|
||||
|
||||
else -> tablePackage
|
||||
}
|
||||
}
|
||||
|
||||
fun sort() {
|
||||
packages.sortWith(compareBy({ it.name }, { it.id }))
|
||||
packages.sortWith(compareBy({it.name}, {it.id}))
|
||||
for (pkg in packages) {
|
||||
pkg.groups.sortWith(compareBy({ it.type.ordinal }, { it.id }))
|
||||
pkg.groups.sortWith(compareBy({it.type.ordinal}, {it.id}))
|
||||
for (group in pkg.groups) {
|
||||
for (entryByName in group.entries.values) {
|
||||
for (entry in entryByName.values) {
|
||||
@@ -315,17 +286,13 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
}
|
||||
|
||||
private fun validateName(
|
||||
nameValidator: (String) -> String,
|
||||
name: ResourceName,
|
||||
source: Source
|
||||
): Boolean {
|
||||
nameValidator: (String) -> String, name: ResourceName, source: Source): Boolean {
|
||||
val badCodePoint = nameValidator.invoke(name.entry!!)
|
||||
if (badCodePoint.isNotEmpty()) {
|
||||
logError(
|
||||
blameSource(source),
|
||||
"Resource '$name' has invalid entry name '${name.entry}'. " +
|
||||
"Invalid character '$badCodePoint'."
|
||||
)
|
||||
"Invalid character '$badCodePoint'.")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -338,8 +305,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
product: String,
|
||||
value: Value,
|
||||
nameValidator: (String) -> String,
|
||||
conflictResolver: (Value, Value) -> CollisionResult
|
||||
): Boolean {
|
||||
conflictResolver: (Value, Value) -> CollisionResult): Boolean {
|
||||
|
||||
val source = value.source
|
||||
|
||||
@@ -353,8 +319,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
logError(
|
||||
blameSource(value.source),
|
||||
"Failed to add resource '$name' with ID ${id.toString(16)} because " +
|
||||
"package '${tablePackage.name}' already has ID ${packageId.toString(16)}."
|
||||
)
|
||||
"package '${tablePackage.name}' already has ID ${packageId.toString(16)}.")
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -368,8 +333,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
logError(
|
||||
blameSource(value.source),
|
||||
"Failed to add resource '$name' with ID ${id.toString(16)} because type " +
|
||||
"'${resourceGroup.type.tagName}' already has ID ${groupId.toString(16)}."
|
||||
)
|
||||
"'${resourceGroup.type.tagName}' already has ID ${groupId.toString(16)}.")
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -380,8 +344,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
logError(
|
||||
blameSource(value.source),
|
||||
"Failed to add resource '$name' with ID ${id.toString(16)}, because resource already" +
|
||||
" has ID ${resourceIdFromParts(packageId!!, groupId!!, entryId).toString(16)}."
|
||||
)
|
||||
" has ID ${resourceIdFromParts(packageId!!, groupId!!, entryId).toString(16)}.")
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -399,11 +362,9 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
logError(
|
||||
blameSource(value.source),
|
||||
"Duplicate value for resource '$name' with config '$config' and product '$product'. " +
|
||||
"Resource was previously defined here: $previousSource."
|
||||
)
|
||||
"Resource was previously defined here: $previousSource.")
|
||||
return false
|
||||
}
|
||||
|
||||
CollisionResult.KEEP_ORIGINAL -> {}
|
||||
}
|
||||
}
|
||||
@@ -423,28 +384,19 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
source: Source,
|
||||
path: String,
|
||||
file: File?,
|
||||
nameValidator: (String) -> String
|
||||
): Boolean {
|
||||
nameValidator: (String) -> String): Boolean {
|
||||
val fileReference = FileReference(stringPool.makeRef(path))
|
||||
fileReference.source = source
|
||||
fileReference.file = file
|
||||
return addResourceImpl(
|
||||
name,
|
||||
0,
|
||||
config,
|
||||
"",
|
||||
fileReference,
|
||||
nameValidator,
|
||||
::resolveValueCollision
|
||||
)
|
||||
name, 0, config, "", fileReference, nameValidator, ::resolveValueCollision)
|
||||
}
|
||||
|
||||
private fun setVisibilityImpl(
|
||||
name: ResourceName,
|
||||
visibility: Visibility,
|
||||
id: Int,
|
||||
nameValidator: (String) -> String
|
||||
): Boolean {
|
||||
nameValidator: (String) -> String) : Boolean {
|
||||
val source = visibility.source
|
||||
if (!validateName(nameValidator, name, source)) {
|
||||
return false
|
||||
@@ -456,8 +408,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
logError(
|
||||
blameSource(source),
|
||||
"Failed to add resource '$name' with ID ${id.toString(16)} because package " +
|
||||
"'${tablePackage.name}' already has ID ${packageId.toString(16)}."
|
||||
)
|
||||
"'${tablePackage.name}' already has ID ${packageId.toString(16)}.")
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -465,14 +416,13 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
val useId = !validateResources && id.isValidDynamicId()
|
||||
|
||||
val resourceGroup =
|
||||
tablePackage.findOrCreateGroup(name.type, if (useId) id.getTypeId() else null)
|
||||
tablePackage.findOrCreateGroup(name.type, if(useId) id.getTypeId() else null)
|
||||
val groupId = resourceGroup.id
|
||||
if (checkId && groupId != null && groupId != id.getTypeId()) {
|
||||
logError(
|
||||
blameSource(source),
|
||||
"Failed to add resource '$name' with ID ${id.toString(16)} because type " +
|
||||
"'${resourceGroup.type.tagName}' already has ID ${groupId.toString(16)}."
|
||||
)
|
||||
"'${resourceGroup.type.tagName}' already has ID ${groupId.toString(16)}.")
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -483,8 +433,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
logError(
|
||||
blameSource(source),
|
||||
"Failed to add resource '$name' with ID ${id.toString(16)}, because resource already " +
|
||||
"has ID ${resourceIdFromParts(packageId!!, groupId!!, entryId).toString(16)}."
|
||||
)
|
||||
"has ID ${resourceIdFromParts(packageId!!, groupId!!, entryId).toString(16)}.")
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -504,27 +453,22 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
resourceEntry.visibility.level != ResourceVisibility.UNDEFINED -> {
|
||||
// We can't undefine a symbol. Ignore
|
||||
}
|
||||
|
||||
visibility.level == ResourceVisibility.PRIVATE &&
|
||||
resourceEntry.visibility.level == ResourceVisibility.PUBLIC -> {
|
||||
logError(
|
||||
blameSource(source),
|
||||
"Failed to add resource '$name' as private (java-symbol) because it was " +
|
||||
"previously defined as public."
|
||||
)
|
||||
"previously defined as public.")
|
||||
return false
|
||||
}
|
||||
|
||||
visibility.level == ResourceVisibility.PUBLIC &&
|
||||
resourceEntry.visibility.level == ResourceVisibility.PRIVATE -> {
|
||||
logError(
|
||||
blameSource(source),
|
||||
"Failed to add resource '$name' as public because it was previously defined as " +
|
||||
"private (java-symbol)."
|
||||
)
|
||||
"private (java-symbol).")
|
||||
return false
|
||||
}
|
||||
|
||||
else -> {
|
||||
// This symbol definition takes precedence.
|
||||
resourceEntry.visibility = visibility
|
||||
@@ -535,10 +479,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
}
|
||||
|
||||
private fun setAllowNewImpl(
|
||||
name: ResourceName,
|
||||
allowNew: AllowNew,
|
||||
nameValidator: (String) -> String
|
||||
): Boolean {
|
||||
name: ResourceName, allowNew: AllowNew, nameValidator: (String) -> String): Boolean {
|
||||
if (!validateName(nameValidator, name, allowNew.source)) {
|
||||
return false
|
||||
}
|
||||
@@ -551,10 +492,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
}
|
||||
|
||||
private fun setOverlayableImpl(
|
||||
name: ResourceName,
|
||||
overlayable: OverlayableItem,
|
||||
nameValidator: (String) -> String
|
||||
): Boolean {
|
||||
name: ResourceName, overlayable: OverlayableItem, nameValidator: (String) -> String): Boolean {
|
||||
if (!validateName(nameValidator, name, overlayable.source)) {
|
||||
return false
|
||||
}
|
||||
@@ -570,8 +508,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
logError(
|
||||
blameSource(overlayable.source),
|
||||
"Failed to add overlayable declaration for resource '$name', because resource already " +
|
||||
"has an overlayable defined here: $previousSource."
|
||||
)
|
||||
"has an overlayable defined here: $previousSource.")
|
||||
return false
|
||||
}
|
||||
entry.overlayable = overlayable
|
||||
@@ -579,20 +516,17 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun resolveValueCollision(existing: Value, incoming: Value): CollisionResult {
|
||||
fun resolveValueCollision(existing: Value, incoming: Value):CollisionResult {
|
||||
val existingAttr = existing as? AttributeResource
|
||||
val incomingAttr = incoming as? AttributeResource
|
||||
|
||||
incomingAttr
|
||||
?: return when {
|
||||
incomingAttr ?: return when {
|
||||
incoming.weak -> CollisionResult.KEEP_ORIGINAL
|
||||
existing.weak -> CollisionResult.TAKE_NEW
|
||||
else -> CollisionResult.CONFLICT
|
||||
}
|
||||
|
||||
existingAttr
|
||||
?: return when {
|
||||
existingAttr ?: return when {
|
||||
existing.weak -> CollisionResult.TAKE_NEW
|
||||
else -> CollisionResult.CONFLICT
|
||||
}
|
||||
@@ -631,18 +565,21 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
class Visibility(
|
||||
val source: Source = Source(""),
|
||||
val comment: String = "",
|
||||
val level: ResourceVisibility = ResourceVisibility.UNDEFINED
|
||||
)
|
||||
val level: ResourceVisibility = ResourceVisibility.UNDEFINED)
|
||||
|
||||
/** Represents <add-resource> in an overlay */
|
||||
class AllowNew(val source: Source, val comment: String)
|
||||
class AllowNew (
|
||||
val source: Source,
|
||||
val comment: String)
|
||||
|
||||
class Overlayable(val name: String, val actor: String, val source: Source) {
|
||||
class Overlayable (
|
||||
val name: String,
|
||||
val actor: String,
|
||||
val source: Source) {
|
||||
|
||||
constructor() : this("", "", Source(""))
|
||||
constructor(): this("","", Source(""))
|
||||
|
||||
companion object {
|
||||
|
||||
const val ACTOR_SCHEME = "overlay"
|
||||
const val ACTOR_SCHEME_URI = "$ACTOR_SCHEME://"
|
||||
}
|
||||
@@ -659,8 +596,7 @@ class OverlayableItem(
|
||||
val overlayable: Overlayable,
|
||||
val policies: Int = Policy.NONE,
|
||||
val comment: String = "",
|
||||
val source: Source = Source("")
|
||||
) {
|
||||
val source: Source = Source("")) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other is OverlayableItem) {
|
||||
@@ -671,27 +607,19 @@ class OverlayableItem(
|
||||
|
||||
/** Represents the types of overlays that are allowed to overlay the resource. */
|
||||
object Policy {
|
||||
|
||||
const val NONE = 0
|
||||
|
||||
/** The resource can be overlaid by any overlay. */
|
||||
const val PUBLIC = 1 shl 0
|
||||
|
||||
/** The resource can be overlaid by any overlay on the system partition. */
|
||||
const val SYSTEM = 1 shl 1
|
||||
|
||||
/** The resource can be overlaid by any overlay on the vendor partition. */
|
||||
const val VENDOR = 1 shl 2
|
||||
|
||||
/** The resource can be overlaid by any overlay on the product partition. */
|
||||
const val PRODUCT = 1 shl 3
|
||||
|
||||
/** The resource can be overlaid by any overlay signed with the same signature as its actor. */
|
||||
const val SIGNATURE = 1 shl 4
|
||||
|
||||
/** The resource can be overlaid by any overlay on the odm partition. */
|
||||
const val ODM = 1 shl 5
|
||||
|
||||
/** The resource can be overlaid by any overlay on the oem partition. */
|
||||
const val OEM = 1 shl 6
|
||||
}
|
||||
@@ -704,21 +632,21 @@ class ResourceTablePackage(var name: String = "", var id: Byte? = null) {
|
||||
|
||||
fun findGroup(type: AaptResourceType, groupId: Byte? = null) =
|
||||
if (groupId != null) {
|
||||
groups.find { type == it.type && groupId == it.id }
|
||||
?: groups.find { type == it.type && it.id == null }
|
||||
groups.find {type == it.type && groupId == it.id} ?:
|
||||
groups.find {type == it.type && it.id == null}
|
||||
} else {
|
||||
groups.find { type == it.type }
|
||||
groups.find {type == it.type}
|
||||
}
|
||||
|
||||
fun findOrCreateGroup(type: AaptResourceType, groupId: Byte? = null): ResourceGroup {
|
||||
return when (val group = findGroup(type, groupId)) {
|
||||
val group = findGroup(type, groupId)
|
||||
return when(group) {
|
||||
null -> {
|
||||
val newGroup = ResourceGroup(type)
|
||||
newGroup.id = groupId
|
||||
groups.add(newGroup)
|
||||
newGroup
|
||||
}
|
||||
|
||||
else -> group
|
||||
}
|
||||
}
|
||||
@@ -728,8 +656,7 @@ class ResourceTablePackage(var name: String = "", var id: Byte? = null) {
|
||||
* Represents all resource entries grouped under a resource type (eg. string, drawable, layout,
|
||||
* etc.).
|
||||
*/
|
||||
class ResourceGroup(val type: AaptResourceType) {
|
||||
|
||||
class ResourceGroup(val type : AaptResourceType) {
|
||||
var id: Byte? = null
|
||||
var visibility = ResourceVisibility.UNDEFINED
|
||||
|
||||
@@ -759,29 +686,27 @@ class ResourceGroup(val type: AaptResourceType) {
|
||||
|
||||
fun findOrCreateEntry(name: String, entryId: Short? = null): ResourceEntry {
|
||||
val entry = findEntry(name, entryId)
|
||||
return when (entry) {
|
||||
return when(entry) {
|
||||
null -> {
|
||||
val newEntry = ResourceEntry(name)
|
||||
newEntry.id = entryId
|
||||
entries.getOrPut(name) { TreeMap(nullsFirst()) }[entryId] = newEntry
|
||||
newEntry
|
||||
}
|
||||
|
||||
else -> entry
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents a resource entry, which may have varying values for each defined configuration. */
|
||||
class ResourceEntry(val name: String) {
|
||||
|
||||
class ResourceEntry(val name : String) {
|
||||
var id: Short? = null
|
||||
var visibility = Visibility(Source(""), "", ResourceVisibility.UNDEFINED)
|
||||
|
||||
var allowNew: AllowNew? = null
|
||||
var overlayable: OverlayableItem? = null
|
||||
|
||||
val values = mutableListOf<ResourceConfigValue>()
|
||||
internal val values = mutableListOf<ResourceConfigValue>()
|
||||
|
||||
fun findValue(config: ConfigDescription, product: String = ""): ResourceConfigValue? {
|
||||
return values.find { it.config == config && it.product == product }
|
||||
@@ -795,7 +720,6 @@ class ResourceEntry(val name: String) {
|
||||
values.add(newConfigValue)
|
||||
newConfigValue
|
||||
}
|
||||
|
||||
else -> configValue
|
||||
}
|
||||
}
|
||||
@@ -810,6 +734,5 @@ class ResourceEntry(val name: String) {
|
||||
*/
|
||||
data class ResourceConfigValue(
|
||||
val config: ConfigDescription,
|
||||
val product: String,
|
||||
var value: Value? = null
|
||||
)
|
||||
val product : String,
|
||||
var value: Value? = null)
|
||||
|
||||
Executable → Regular
+46
-56
@@ -22,7 +22,7 @@ import com.android.aaptcompiler.android.parseHex
|
||||
import com.android.aaptcompiler.android.stringToFloat
|
||||
import com.android.aaptcompiler.android.stringToInt
|
||||
|
||||
fun tryParseBool(string: String): BinaryPrimitive? {
|
||||
fun tryParseBool(string: String) : BinaryPrimitive? {
|
||||
val boolean = parseAsBool(string)
|
||||
boolean ?: return null
|
||||
|
||||
@@ -30,14 +30,10 @@ fun tryParseBool(string: String): BinaryPrimitive? {
|
||||
return BinaryPrimitive(ResValue(ResValue.DataType.INT_BOOLEAN, data))
|
||||
}
|
||||
|
||||
fun parseAsBool(string: String): Boolean? =
|
||||
fun parseAsBool(string: String) : Boolean? =
|
||||
when (string.trim()) {
|
||||
"true",
|
||||
"True",
|
||||
"TRUE" -> true
|
||||
"false",
|
||||
"False",
|
||||
"FALSE" -> false
|
||||
"true", "True", "TRUE" -> true
|
||||
"false", "False", "FALSE" -> false
|
||||
else -> null
|
||||
}
|
||||
|
||||
@@ -50,15 +46,15 @@ fun tryParseNullOrEmpty(value: String): Item? {
|
||||
}
|
||||
}
|
||||
|
||||
fun makeNull(): Reference {
|
||||
fun makeNull() : Reference {
|
||||
return Reference()
|
||||
}
|
||||
|
||||
fun makeEmpty(): BinaryPrimitive {
|
||||
fun makeEmpty() : BinaryPrimitive {
|
||||
return BinaryPrimitive(ResValue(ResValue.DataType.NULL, ResValue.NullFormat.EMPTY))
|
||||
}
|
||||
|
||||
fun tryParseInt(value: String): BinaryPrimitive? {
|
||||
fun tryParseInt(value: String) : BinaryPrimitive? {
|
||||
val trimmedValue = value.trim()
|
||||
val resValue = stringToInt(trimmedValue)
|
||||
return if (resValue != null) BinaryPrimitive(resValue) else null
|
||||
@@ -66,17 +62,15 @@ fun tryParseInt(value: String): BinaryPrimitive? {
|
||||
|
||||
fun parseResourceId(value: String): Int? {
|
||||
val resValue = stringToInt(value)
|
||||
if (
|
||||
resValue != null &&
|
||||
if (resValue != null &&
|
||||
resValue.dataType == ResValue.DataType.INT_HEX &&
|
||||
resValue.data.isValidDynamicId()
|
||||
) {
|
||||
resValue.data.isValidDynamicId()) {
|
||||
return resValue.data
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun tryParseFloat(value: String): BinaryPrimitive? {
|
||||
fun tryParseFloat(value: String) : BinaryPrimitive? {
|
||||
val floatResource = stringToFloat(value)
|
||||
floatResource ?: return null
|
||||
|
||||
@@ -142,12 +136,15 @@ fun tryParseColor(value: String): BinaryPrimitive? {
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
return if (error) BinaryPrimitive(ResValue()) else BinaryPrimitive(ResValue(dataType, data))
|
||||
return if (error)
|
||||
throw Exception("Unable to parse hex color '$value'.")
|
||||
else
|
||||
BinaryPrimitive(ResValue(dataType, data))
|
||||
}
|
||||
|
||||
data class ReferenceInfo(val reference: Reference, val createNew: Boolean = false)
|
||||
|
||||
fun tryParseReference(value: String): ReferenceInfo? {
|
||||
fun tryParseReference(value: String) : ReferenceInfo? {
|
||||
|
||||
val parsedReference = parseReference(value)
|
||||
if (parsedReference != null) {
|
||||
@@ -174,7 +171,7 @@ fun tryParseReference(value: String): ReferenceInfo? {
|
||||
*
|
||||
* [ReferenceInfo.createNew] will be false, as Attributes cannot be created.
|
||||
*/
|
||||
fun parseAttributeReference(value: String): ReferenceInfo? {
|
||||
fun parseAttributeReference(value: String) : ReferenceInfo? {
|
||||
val trimmedValue = value.trim()
|
||||
if (trimmedValue.isEmpty()) {
|
||||
return null
|
||||
@@ -200,10 +197,7 @@ fun parseAttributeReference(value: String): ReferenceInfo? {
|
||||
val reference = Reference()
|
||||
reference.name =
|
||||
ResourceName(
|
||||
possibleResourceName.packageName,
|
||||
AaptResourceType.ATTR,
|
||||
possibleResourceName.entry
|
||||
)
|
||||
possibleResourceName.packageName, AaptResourceType.ATTR, possibleResourceName.entry)
|
||||
reference.referenceType = Reference.Type.ATTRIBUTE
|
||||
return ReferenceInfo(reference, false)
|
||||
}
|
||||
@@ -214,7 +208,10 @@ fun parseAttributeReference(value: String): ReferenceInfo? {
|
||||
*
|
||||
* <p> The reference must be of one of the following forms:
|
||||
*
|
||||
* + "@<entry>" + "@<type>/<entry>" + "@<package>:<entry>" + "@<package>:<type>/<entry>"
|
||||
* + "@<entry>"
|
||||
* + "@<type>/<entry>"
|
||||
* + "@<package>:<entry>"
|
||||
* + "@<package>:<type>/<entry>"
|
||||
*
|
||||
* <p> Optionally, the '@' symbol can be followed by one of '+' or '*'. '+' means that the resource
|
||||
* will be created and added to the resource table. This is only usable with id resources. The '*',
|
||||
@@ -225,10 +222,11 @@ fun parseAttributeReference(value: String): ReferenceInfo? {
|
||||
* @return A [ReferenceInfo] representing the reference, or {@code null} if the input was invalid.
|
||||
*
|
||||
* + [ReferenceInfo.createNew] will be set if and only if a '+' followed the '@' and the reference
|
||||
* had a type of id. + [ReferenceInfo.reference] will be set as private if and only if a '*'
|
||||
* followed the '@' in the input.
|
||||
* had a type of id.
|
||||
* + [ReferenceInfo.reference] will be set as private if and only if a '*' followed the '@' in the
|
||||
* input.
|
||||
*/
|
||||
fun parseReference(value: String): ReferenceInfo? {
|
||||
fun parseReference(value: String) : ReferenceInfo? {
|
||||
val trimmedValue = value.trim()
|
||||
if (trimmedValue.isEmpty()) {
|
||||
return null
|
||||
@@ -271,7 +269,10 @@ data class ResourceNameInfo(val resourceName: ResourceName, val isPrivate: Boole
|
||||
*
|
||||
* <p> The resource name must be in one of the following forms:
|
||||
*
|
||||
* + "<entry>" + "<type>/<entry>" + "<package>:<entry>" + "<package>:<type>/<entry>"
|
||||
* + "<entry>"
|
||||
* + "<type>/<entry>"
|
||||
* + "<package>:<entry>"
|
||||
* + "<package>:<type>/<entry>"
|
||||
*
|
||||
* The value may optionally be preceded by a '*' to represent that the resource name is private.
|
||||
*
|
||||
@@ -280,7 +281,7 @@ data class ResourceNameInfo(val resourceName: ResourceName, val isPrivate: Boole
|
||||
* valid [ResourceName] and whether the parsed name identifies a private resource. If the value
|
||||
* failed to parsed {@code null} is returned instead.
|
||||
*/
|
||||
fun parseResourceName(value: String): ResourceNameInfo? {
|
||||
fun parseResourceName(value: String) : ResourceNameInfo? {
|
||||
|
||||
if (value.isEmpty()) {
|
||||
return null
|
||||
@@ -307,16 +308,12 @@ fun parseResourceName(value: String): ResourceNameInfo? {
|
||||
|
||||
return ResourceNameInfo(
|
||||
ResourceName(possibleResourceName.packageName, resourceType, possibleResourceName.entry),
|
||||
isPrivate
|
||||
)
|
||||
isPrivate)
|
||||
}
|
||||
|
||||
data class PossibleResourceName(
|
||||
val packageName: String,
|
||||
val typeName: String,
|
||||
val entry: String,
|
||||
val success: Boolean = true
|
||||
)
|
||||
val packageName: String, val typeName: String, val entry: String, val success: Boolean = true)
|
||||
|
||||
|
||||
fun extractResourceName(value: String): PossibleResourceName {
|
||||
var packageName = ""
|
||||
@@ -347,8 +344,8 @@ fun extractResourceName(value: String): PossibleResourceName {
|
||||
}
|
||||
val entryName = value.substring(offsetCurrent)
|
||||
|
||||
val success =
|
||||
!(hasPackageSeparator && packageName.isEmpty()) && !((hasTypeSeparator) && typeName.isEmpty())
|
||||
val success = !(hasPackageSeparator && packageName.isEmpty()) &&
|
||||
!((hasTypeSeparator) && typeName.isEmpty())
|
||||
|
||||
return PossibleResourceName(packageName, typeName, entryName, success)
|
||||
}
|
||||
@@ -356,8 +353,7 @@ fun extractResourceName(value: String): PossibleResourceName {
|
||||
fun tryParseItemForAttribute(
|
||||
value: String,
|
||||
resourceTypeMask: Int,
|
||||
onCreateReference: ((name: ResourceName) -> Boolean)? = null
|
||||
): Item? {
|
||||
onCreateReference: ((name: ResourceName) -> Boolean)? = null): Item? {
|
||||
|
||||
val nullOrEmpty = tryParseNullOrEmpty(value)
|
||||
if (nullOrEmpty != null) {
|
||||
@@ -397,16 +393,13 @@ fun tryParseItemForAttribute(
|
||||
}
|
||||
}
|
||||
|
||||
val floatMask =
|
||||
Resources.Attribute.FormatFlags.FLOAT_VALUE or
|
||||
val floatMask = Resources.Attribute.FormatFlags.FLOAT_VALUE or
|
||||
Resources.Attribute.FormatFlags.DIMENSION_VALUE or
|
||||
Resources.Attribute.FormatFlags.FRACTION_VALUE
|
||||
if ((resourceTypeMask and floatMask) != 0) {
|
||||
val floatingPoint = tryParseFloat(value)
|
||||
if (
|
||||
floatingPoint != null &&
|
||||
(androidTypeToAttributeTypeMask(floatingPoint.resValue.dataType) and resourceTypeMask) != 0
|
||||
) {
|
||||
if (floatingPoint != null &&
|
||||
(androidTypeToAttributeTypeMask(floatingPoint.resValue.dataType) and resourceTypeMask) != 0) {
|
||||
return floatingPoint
|
||||
}
|
||||
}
|
||||
@@ -578,16 +571,11 @@ fun parseStyleParentReference(str: String): ParsedParentInfo {
|
||||
|
||||
val resourceName =
|
||||
ResourceName(
|
||||
possibleResourceName.packageName,
|
||||
AaptResourceType.STYLE,
|
||||
possibleResourceName.entry
|
||||
)
|
||||
possibleResourceName.packageName, AaptResourceType.STYLE, possibleResourceName.entry)
|
||||
|
||||
if (
|
||||
!hasLeadingIdentifiers &&
|
||||
if (!hasLeadingIdentifiers &&
|
||||
resourceName.pck!!.isEmpty() &&
|
||||
possibleResourceName.typeName.isNotEmpty()
|
||||
) {
|
||||
possibleResourceName.typeName.isNotEmpty()) {
|
||||
val errorString = "Invalid parent reference '$str'"
|
||||
return ParsedParentInfo(null, errorString)
|
||||
}
|
||||
@@ -596,9 +584,11 @@ fun parseStyleParentReference(str: String): ParsedParentInfo {
|
||||
result.name = resourceName
|
||||
result.isPrivate = privateRef
|
||||
|
||||
|
||||
return ParsedParentInfo(result, "")
|
||||
}
|
||||
|
||||
|
||||
fun parseXmlAttributeName(str: String): Reference {
|
||||
val name = str.trim()
|
||||
|
||||
@@ -612,10 +602,10 @@ fun parseXmlAttributeName(str: String): Reference {
|
||||
|
||||
var packageName = ""
|
||||
var entryName = ""
|
||||
for (i in startOffset until name.length) {
|
||||
for (i in startOffset..(name.length - 1)) {
|
||||
if (name.codePointAt(i) == ':'.code) {
|
||||
packageName = name.substring(startOffset, i)
|
||||
entryName = name.substring(i + 1)
|
||||
entryName = name.substring(i+1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Executable → Regular
Executable → Regular
+1
@@ -7,4 +7,5 @@ internal object SDKConstants {
|
||||
const val SDK_LOLLIPOP = 21.toShort()
|
||||
const val SDK_MARSHMALLOW = 23.toShort()
|
||||
const val SDK_O = 26.toShort()
|
||||
const val SDK_U = 34.toShort()
|
||||
}
|
||||
Executable → Regular
Executable → Regular
+14
-28
@@ -175,9 +175,7 @@ class StringPool {
|
||||
reAssignIndices()
|
||||
}
|
||||
|
||||
private fun flatten(out: BigBuffer, utf8: Boolean, logger: ILogger?): Boolean {
|
||||
var error = false
|
||||
|
||||
private fun flatten(out: BigBuffer, utf8: Boolean, logger: ILogger?) {
|
||||
val header = ResStringPoolHeader(
|
||||
ResChunkHeader(
|
||||
ChunkType.STRING_POOL_TYPE.id.hostToDevice(),
|
||||
@@ -208,18 +206,14 @@ class StringPool {
|
||||
stringIndexBlock
|
||||
.writeInt((out.size - beginStringsIndex).hostToDevice(), currentStringIndex)
|
||||
currentStringIndex += 4
|
||||
|
||||
val stringError = !encodeString(entry.value, utf8, out, logger)
|
||||
error = stringError || error
|
||||
encodeString(entry.value, utf8, out)
|
||||
}
|
||||
|
||||
// Strings come next
|
||||
for (entry in strings) {
|
||||
stringIndexBlock.writeInt((out.size - beginStringsIndex).hostToDevice(), currentStringIndex)
|
||||
currentStringIndex += 4
|
||||
|
||||
val stringError = !encodeString(entry.value, utf8, out, logger)
|
||||
error = stringError || error
|
||||
encodeString(entry.value, utf8, out)
|
||||
}
|
||||
|
||||
out.align4()
|
||||
@@ -261,7 +255,6 @@ class StringPool {
|
||||
// now we can set the size of the output in the header
|
||||
header.header.size = (out.size - headerStart).hostToDevice()
|
||||
encodeHeader(header, headerBlock)
|
||||
return !error
|
||||
}
|
||||
|
||||
private fun encodeHeader(resHeader: ResStringPoolHeader, out: BigBuffer.BlockRef) {
|
||||
@@ -283,9 +276,7 @@ class StringPool {
|
||||
return 12
|
||||
}
|
||||
|
||||
private fun encodeString(
|
||||
str: String, utf8: Boolean, out: BigBuffer, logger: ILogger?): Boolean {
|
||||
|
||||
private fun encodeString(str: String, utf8: Boolean, out: BigBuffer) {
|
||||
if (utf8) {
|
||||
val utf16Length = str.length
|
||||
val utf8Str = str.toByteArray()
|
||||
@@ -293,11 +284,10 @@ class StringPool {
|
||||
|
||||
// Make sure the lengths to be encoded do not exceed the maximum length that can be encoded
|
||||
// using chars
|
||||
if (utf8Length > UTF8_ENCODE_LENGTH_MAX || utf16Length > UTF16_ENCODE_LENGTH_MAX) {
|
||||
val errorMsg = "String too large to encode using UTF-8. Writing the string instead as '%s'."
|
||||
logger?.error(null, errorMsg, STRING_TOO_LARGE)
|
||||
encodeString(STRING_TOO_LARGE, utf8, out, logger)
|
||||
return false
|
||||
if (utf8Length > UTF8_ENCODE_LENGTH_MAX ) {
|
||||
error("String of size $utf8Length bytes is too large to encode using UTF-8 " +
|
||||
"($UTF8_ENCODE_LENGTH_MAX bytes). " +
|
||||
"Affected string begins with: '${str.take(STRING_PREFIX_LENGTH_FOR_ERRORS)}'...")
|
||||
}
|
||||
|
||||
val blockSize = getLengthUtf8(utf8Length) + getLengthUtf8(utf16Length) + utf8Length + 1
|
||||
@@ -319,20 +309,15 @@ class StringPool {
|
||||
|
||||
// Now write null terminator
|
||||
stringBlock.writeByte(0x00, locationToWrite)
|
||||
|
||||
return true
|
||||
} else {
|
||||
val utf16Length = str.length
|
||||
|
||||
// Make sure the length to be encoded does not exceed the maximum possible length that can be
|
||||
// encoded
|
||||
if (utf16Length > UTF16_ENCODE_LENGTH_MAX) {
|
||||
val errorMsg =
|
||||
"String too large to encode using UTF-16. Writing the string instead as '%s'."
|
||||
logger?.error(null, errorMsg, STRING_TOO_LARGE)
|
||||
|
||||
encodeString(STRING_TOO_LARGE, utf8, out, logger)
|
||||
return false
|
||||
error("String of size ${str.toByteArray().size} is too large to encode using " +
|
||||
"UTF-16 ($UTF16_ENCODE_LENGTH_MAX bytes). " +
|
||||
"Affected string begins with: '${str.take(STRING_PREFIX_LENGTH_FOR_ERRORS)}'...")
|
||||
}
|
||||
|
||||
val blockSize = getLengthUtf16(utf16Length) + utf16Length*2 + 2
|
||||
@@ -351,7 +336,6 @@ class StringPool {
|
||||
|
||||
// now write null terminator
|
||||
stringBlock.writeShort(0x0000.toShort(), locationToWrite)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,7 +406,9 @@ class StringPool {
|
||||
const val TWO_CHAR_UTF16_LENGTH_SIGNIFIER = 0x8000
|
||||
const val ONE_CHAR_UTF16_ENCODE_LENGTH_MAX = 0x7fff
|
||||
|
||||
private const val STRING_TOO_LARGE = "STRING_TOO_LARGE"
|
||||
// The maximum number of chars that will be presented to the user if the size of the string
|
||||
// exceeds the maximum permitted utf-8 or utf-16 byte size.
|
||||
const val STRING_PREFIX_LENGTH_FOR_ERRORS = 42
|
||||
|
||||
val ENTRY_ON_VALUE = compareBy<Entry> {it.value}
|
||||
val STYLE_ON_VALUE = compareBy<StyleEntry> {it.value}
|
||||
|
||||
Executable → Regular
+237
-392
File diff suppressed because it is too large
Load Diff
Executable → Regular
Executable → Regular
+6
-5
@@ -675,14 +675,15 @@ fun isJavaIdentifier(string: String): Boolean {
|
||||
|
||||
val firstCodePoint = string.codePointAt(0)
|
||||
if (!isXidStart(firstCodePoint) &&
|
||||
firstCodePoint != '_'.toInt() &&
|
||||
firstCodePoint != '$'.toInt()) {
|
||||
firstCodePoint != '_'.code &&
|
||||
firstCodePoint != '$'.code
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
for (i in 1.until(string.codePointCount(0, string.length))) {
|
||||
val codePoint = string.codePointAt(i)
|
||||
if (!isXidContinue(codePoint) && codePoint != '$'.toInt()) {
|
||||
if (!isXidContinue(codePoint) && codePoint != '$'.code) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -700,13 +701,13 @@ fun isValidResourceEntryName(string: String): Boolean {
|
||||
|
||||
// Resources can start with '_'.
|
||||
val firstCodePoint = string.codePointAt(0)
|
||||
if (!isXidStart(firstCodePoint) && firstCodePoint != '_'.toInt()) {
|
||||
if (!isXidStart(firstCodePoint) && firstCodePoint != '_'.code) {
|
||||
return false
|
||||
}
|
||||
|
||||
for (i in 1.until(string.codePointCount(0, string.length))) {
|
||||
val codePoint = string.codePointAt(i)
|
||||
if (!isXidContinue(codePoint) && codePoint != '.'.toInt() && codePoint != '-'.toInt()) {
|
||||
if (!isXidContinue(codePoint) && codePoint != '.'.code && codePoint != '-'.code) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
+7
-7
@@ -107,11 +107,11 @@ class XmlStringBuilder(private val preserveSpaces: Boolean = false) {
|
||||
str: String
|
||||
): Boolean {
|
||||
when (codePoint) {
|
||||
't'.toInt() -> textBuilder.append('\t')
|
||||
'n'.toInt() -> textBuilder.append('\n')
|
||||
'#'.toInt(), '@'.toInt(), '?'.toInt(), '"'.toInt(), '\''.toInt(), '\\'.toInt() ->
|
||||
't'.code -> textBuilder.append('\t')
|
||||
'n'.code -> textBuilder.append('\n')
|
||||
'#'.code, '@'.code, '?'.code, '"'.code, '\''.code, '\\'.code ->
|
||||
textBuilder.appendCodePoint(codePoint)
|
||||
'u'.toInt() -> {
|
||||
'u'.code -> {
|
||||
if (!appendUnicodeEscapeSequence(codePoints, textBuilder)) {
|
||||
error = "Invalid unicode escape sequence in string\n\"$str\""
|
||||
return false
|
||||
@@ -160,7 +160,7 @@ class XmlStringBuilder(private val preserveSpaces: Boolean = false) {
|
||||
lastChar = textBuilder.length
|
||||
lastCodepointWasBackslash = false
|
||||
}
|
||||
codePoint == '\\'.toInt() -> {
|
||||
codePoint == '\\'.code -> {
|
||||
if (codePoints.hasNext()) {
|
||||
codePoint = codePoints.nextInt()
|
||||
if (!handleEscape(codePoint, textBuilder, codePoints, str)) {
|
||||
@@ -171,7 +171,7 @@ class XmlStringBuilder(private val preserveSpaces: Boolean = false) {
|
||||
lastCodepointWasBackslash = true
|
||||
}
|
||||
}
|
||||
codePoint == '\"'.toInt() && !preserveSpaces -> {
|
||||
codePoint == '\"'.code && !preserveSpaces -> {
|
||||
// only toggle quote when we are not preserving spaces.
|
||||
inQuote = !inQuote
|
||||
if (firstQuote == -1) {
|
||||
@@ -180,7 +180,7 @@ class XmlStringBuilder(private val preserveSpaces: Boolean = false) {
|
||||
lastQuote = textBuilder.length
|
||||
lastChar = textBuilder.length
|
||||
}
|
||||
codePoint == '\''.toInt() && !preserveSpaces && !inQuote -> {
|
||||
codePoint == '\''.code && !preserveSpaces && !inQuote -> {
|
||||
// this should be escaped when we are not preserving spaces
|
||||
error = "Invalid unicode escape sequence in string\n\"{str}\""
|
||||
return this
|
||||
|
||||
Executable → Regular
+2
-1
@@ -1,11 +1,12 @@
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.SdkConstants
|
||||
import jaxp.sun.xml.internal.stream.XMLInputFactoryImpl
|
||||
import jaxp.xml.stream.XMLEventReader
|
||||
import jaxp.xml.stream.XMLInputFactory
|
||||
import jaxp.xml.stream.events.StartElement
|
||||
|
||||
internal val xmlInputFactory = XMLInputFactory.newFactory()
|
||||
internal val xmlInputFactory = XMLInputFactoryImpl()
|
||||
|
||||
const val SCHEMA_PUBLIC_PREFIX = SdkConstants.URI_PREFIX
|
||||
const val SCHEMA_PRIVATE_PREFIX = "http://schemas.android.com/apk/prv/res/"
|
||||
|
||||
Executable → Regular
+26
@@ -179,6 +179,26 @@ object AConfiguration {
|
||||
* resource qualifier.
|
||||
*/
|
||||
const val ACONFIGURATION_NAVHIDDEN_YES : Byte = 0x0002
|
||||
/** Grammatical gender: not specified. */
|
||||
const val ACONFIGURATION_GRAMMATICAL_GENDER_ANY : Byte = 0x00
|
||||
/**
|
||||
* Grammatical gender: const value corresponding to the
|
||||
* [neuter](@dacRoot/guide/topics/resources/providing-resources.html#GrammaticalInflectionQualifier)
|
||||
* resource qualifier.
|
||||
*/
|
||||
const val ACONFIGURATION_GRAMMATICAL_GENDER_NEUTER : Byte = 0x01
|
||||
/**
|
||||
* Grammatical gender: const value corresponding to the
|
||||
* [feminine](@dacRoot/guide/topics/resources/providing-resources.html#GrammaticalInflectionQualifier)
|
||||
* resource qualifier.
|
||||
*/
|
||||
const val ACONFIGURATION_GRAMMATICAL_GENDER_FEMININE : Byte = 0x02
|
||||
/**
|
||||
* Grammatical gender: const value corresponding to the
|
||||
* [masculine](@dacRoot/guide/topics/resources/providing-resources.html#GrammaticalInflectionQualifier)
|
||||
* resource qualifier.
|
||||
*/
|
||||
const val ACONFIGURATION_GRAMMATICAL_GENDER_MASCULINE : Byte = 0x03
|
||||
/** Screen size: not specified. */
|
||||
const val ACONFIGURATION_SCREENSIZE_ANY : Byte = 0x00
|
||||
/**
|
||||
@@ -440,5 +460,11 @@ object AConfiguration {
|
||||
* 0 cannot be used, since it is used to represent an undefined MNC.
|
||||
*/
|
||||
const val ACONFIGURATION_MNC_ZERO : Int = 0xffff
|
||||
/**
|
||||
* Bit mask for
|
||||
* [grammatical gender](@dacRoot/guide/topics/resources/providing-resources.html#GrammaticalInflectionQualifier)
|
||||
* configuration.
|
||||
*/
|
||||
const val ACONFIGURATION_GRAMMATICAL_GENDER : Int = 0x20000
|
||||
}
|
||||
|
||||
|
||||
Executable → Regular
Executable → Regular
+3
-1
@@ -1,5 +1,7 @@
|
||||
package com.android.aaptcompiler.android
|
||||
|
||||
import com.itsaky.androidide.utils.intByteMapOf
|
||||
|
||||
internal val SCRIPT_CODES = arrayOf(
|
||||
/* 0 */ byteArrayOf('A'.code.toByte(), 'h'.code.toByte(), 'o'.code.toByte(), 'm'.code.toByte()),
|
||||
/* 1 */ byteArrayOf('A'.code.toByte(), 'r'.code.toByte(), 'a'.code.toByte(), 'b'.code.toByte()),
|
||||
@@ -91,7 +93,7 @@ internal val SCRIPT_CODES = arrayOf(
|
||||
/* 87 */ byteArrayOf('~'.code.toByte(), '~'.code.toByte(), '~'.code.toByte(), 'A'.code.toByte()),
|
||||
/* 88 */ byteArrayOf('~'.code.toByte(), '~'.code.toByte(), '~'.code.toByte(), 'B'.code.toByte()))
|
||||
|
||||
internal val LIKELY_SCRIPTS = mapOf<Int, Byte>(
|
||||
internal val LIKELY_SCRIPTS = intByteMapOf(
|
||||
0x61610000 to 40, // aa -> Latn
|
||||
0xa0000000.toInt() to 40, // aai -> Latn
|
||||
0xa8000000.toInt() to 40, // aak -> Latn
|
||||
|
||||
Executable → Regular
Executable → Regular
+48
@@ -2,6 +2,7 @@ package com.android.aaptcompiler.android
|
||||
|
||||
import com.android.aaptcompiler.android.AConfiguration.ACONFIGURATION_COLOR_MODE
|
||||
import com.android.aaptcompiler.android.AConfiguration.ACONFIGURATION_DENSITY
|
||||
import com.android.aaptcompiler.android.AConfiguration.ACONFIGURATION_GRAMMATICAL_GENDER
|
||||
import com.android.aaptcompiler.android.AConfiguration.ACONFIGURATION_KEYBOARD
|
||||
import com.android.aaptcompiler.android.AConfiguration.ACONFIGURATION_KEYBOARD_HIDDEN
|
||||
import com.android.aaptcompiler.android.AConfiguration.ACONFIGURATION_LAYOUTDIR
|
||||
@@ -52,6 +53,7 @@ open class ResTableConfig(
|
||||
var keyboard: Byte = 0,
|
||||
var navigation: Byte = 0,
|
||||
var inputFlags: Byte = 0,
|
||||
var grammaticalInflection: Byte = 0,
|
||||
// padding: Byte,
|
||||
// screenSize block
|
||||
var screenWidth: Int = 0,
|
||||
@@ -84,6 +86,7 @@ open class ResTableConfig(
|
||||
locale: Int,
|
||||
screenType: Int,
|
||||
input: Int,
|
||||
grammaticalInflection: Int,
|
||||
screenSize: Int,
|
||||
version: Int,
|
||||
screenConfig: Int,
|
||||
@@ -104,6 +107,7 @@ open class ResTableConfig(
|
||||
keyboardFromInput(input),
|
||||
navigationFromInput(input),
|
||||
inputFlagsFromInput(input),
|
||||
grammaticalInflection.deviceToHost().toByte(),
|
||||
screenWidthFromScreenSize(screenSize),
|
||||
screenHeightFromScreenSize(screenSize),
|
||||
sdkVersionFromVersion(version),
|
||||
@@ -132,6 +136,7 @@ open class ResTableConfig(
|
||||
other.keyboard,
|
||||
other.navigation,
|
||||
other.inputFlags,
|
||||
other.grammaticalInflection,
|
||||
other.screenWidth,
|
||||
other.screenHeight,
|
||||
other.sdkVersion,
|
||||
@@ -231,6 +236,17 @@ open class ResTableConfig(
|
||||
|
||||
appendDirLocale(result)
|
||||
|
||||
if (grammaticalInflection != GRAMMATICAL_GENDER.ANY) {
|
||||
result.append(
|
||||
when (grammaticalInflection) {
|
||||
GRAMMATICAL_GENDER.NEUTER -> "neuter"
|
||||
GRAMMATICAL_GENDER.FEMININE -> "feminine"
|
||||
GRAMMATICAL_GENDER.MASCULINE -> "masculine"
|
||||
else -> "grammaticalInflection=$grammaticalInflection"
|
||||
})
|
||||
result.append("-")
|
||||
}
|
||||
|
||||
val layoutDir = (screenLayout.toInt() and SCREEN_LAYOUT.DIR_MASK).toByte()
|
||||
if (layoutDir != SCREEN_LAYOUT.DIR_ANY) {
|
||||
result.append(
|
||||
@@ -570,6 +586,9 @@ open class ResTableConfig(
|
||||
if (compareLocales(other) != 0) {
|
||||
result = result or CONFIG_LOCALE
|
||||
}
|
||||
if (grammaticalInflection != other.grammaticalInflection) {
|
||||
result = result or CONFIG_GRAMMATICAL_GENDER
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -586,6 +605,11 @@ open class ResTableConfig(
|
||||
return localeDiff
|
||||
}
|
||||
|
||||
when {
|
||||
grammaticalInflection > other.grammaticalInflection -> return 1
|
||||
grammaticalInflection < other.grammaticalInflection -> return -1
|
||||
}
|
||||
|
||||
val screenType = getScreenType().deviceToHost()
|
||||
val oScreenType = other.getScreenType().deviceToHost()
|
||||
when {
|
||||
@@ -699,6 +723,10 @@ open class ResTableConfig(
|
||||
localeDiff > 0 -> return true
|
||||
}
|
||||
|
||||
if (grammaticalInflection.isTruthy() || other.grammaticalInflection.isTruthy()) {
|
||||
if (grammaticalInflection != other.grammaticalInflection) return grammaticalInflection.isTruthy()
|
||||
}
|
||||
|
||||
if (screenLayout.isTruthy() || other.screenLayout.isTruthy()) {
|
||||
if (screenLayout.toInt() and SCREEN_LAYOUT.DIR_MASK !=
|
||||
other.screenLayout.toInt() and SCREEN_LAYOUT.DIR_MASK) {
|
||||
@@ -881,6 +909,10 @@ open class ResTableConfig(
|
||||
return true
|
||||
}
|
||||
|
||||
if (grammaticalInflection != other.grammaticalInflection && requested.grammaticalInflection.isTruthy()) {
|
||||
return grammaticalInflection.isTruthy()
|
||||
}
|
||||
|
||||
if (screenLayout.isTruthy() || other.screenLayout.isTruthy()) {
|
||||
val myLayoutDir = screenLayout.toInt() and SCREEN_LAYOUT.DIR_MASK
|
||||
val otherLayoutDir = other.screenLayout.toInt() and SCREEN_LAYOUT.DIR_MASK
|
||||
@@ -1258,6 +1290,10 @@ open class ResTableConfig(
|
||||
}
|
||||
}
|
||||
|
||||
if (grammaticalInflection.isTruthy() && grammaticalInflection != settings.grammaticalInflection) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (getScreenConfig().isTruthy()) {
|
||||
val layoutDir = screenLayout.toInt() and SCREEN_LAYOUT.DIR_MASK
|
||||
val setLayoutDir = settings.screenLayout.toInt() and SCREEN_LAYOUT.DIR_MASK
|
||||
@@ -1478,6 +1514,7 @@ open class ResTableConfig(
|
||||
const val CONFIG_LAYOUTDIR = ACONFIGURATION_LAYOUTDIR
|
||||
const val CONFIG_SCREEN_ROUND = ACONFIGURATION_SCREEN_ROUND
|
||||
const val CONFIG_COLOR_MODE = ACONFIGURATION_COLOR_MODE
|
||||
const val CONFIG_GRAMMATICAL_GENDER = ACONFIGURATION_GRAMMATICAL_GENDER
|
||||
|
||||
const val SCREEN_CONFIG_MIN_SIZE = 32
|
||||
const val SCREEN_DP_MIN_SIZE = 36
|
||||
@@ -1552,6 +1589,7 @@ open class ResTableConfig(
|
||||
val locale = buffer.int
|
||||
val screenType = buffer.int
|
||||
val input = buffer.int
|
||||
val grammaticalInflection = buffer.int
|
||||
val screenSize = buffer.int
|
||||
val version = buffer.int
|
||||
|
||||
@@ -1587,6 +1625,7 @@ open class ResTableConfig(
|
||||
locale,
|
||||
screenType,
|
||||
input,
|
||||
grammaticalInflection,
|
||||
screenSize,
|
||||
version,
|
||||
screenConfig,
|
||||
@@ -1660,12 +1699,14 @@ open class ResTableConfig(
|
||||
const val ANY = AConfiguration.ACONFIGURATION_ORIENTATION_ANY
|
||||
const val PORT = AConfiguration.ACONFIGURATION_ORIENTATION_PORT
|
||||
const val LAND = AConfiguration.ACONFIGURATION_ORIENTATION_LAND
|
||||
@Suppress("DEPRECATION") // Legacy support
|
||||
const val SQUARE = AConfiguration.ACONFIGURATION_ORIENTATION_SQUARE
|
||||
}
|
||||
|
||||
object TOUCHSCREEN {
|
||||
const val ANY = AConfiguration.ACONFIGURATION_TOUCHSCREEN_ANY
|
||||
const val NOTOUCH = AConfiguration.ACONFIGURATION_TOUCHSCREEN_NOTOUCH
|
||||
@Suppress("DEPRECATION") // Legacy support
|
||||
const val STYLUS = AConfiguration.ACONFIGURATION_TOUCHSCREEN_STYLUS
|
||||
const val FINGER = AConfiguration.ACONFIGURATION_TOUCHSCREEN_FINGER
|
||||
}
|
||||
@@ -1717,6 +1758,13 @@ open class ResTableConfig(
|
||||
(AConfiguration.ACONFIGURATION_NAVHIDDEN_YES.toInt() shl NAVHIDDEN_SHIFT).toByte()
|
||||
}
|
||||
|
||||
object GRAMMATICAL_GENDER {
|
||||
const val ANY = AConfiguration.ACONFIGURATION_GRAMMATICAL_GENDER_ANY
|
||||
const val NEUTER = AConfiguration.ACONFIGURATION_GRAMMATICAL_GENDER_NEUTER
|
||||
const val FEMININE = AConfiguration.ACONFIGURATION_GRAMMATICAL_GENDER_FEMININE
|
||||
const val MASCULINE = AConfiguration.ACONFIGURATION_GRAMMATICAL_GENDER_MASCULINE
|
||||
}
|
||||
|
||||
// Screensize values
|
||||
object SCREENSIZE {
|
||||
const val WIDTH_ANY = 0
|
||||
|
||||
Executable → Regular
+78
-103
@@ -20,22 +20,25 @@ import com.android.aaptcompiler.StringPool
|
||||
import com.android.aaptcompiler.parseFloat
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import kotlin.text.Charsets
|
||||
|
||||
/**
|
||||
* Definitions of resource data structures. <p>Transliterated from: *
|
||||
* Definitions of resource data structures.
|
||||
* <p>Transliterated from: *
|
||||
* https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/ResourceTypes.cpp
|
||||
*/
|
||||
|
||||
/** Header that appears at the front of every data chunk in a resource. */
|
||||
/**
|
||||
* Header that appears at the front of every data chunk in a resource.
|
||||
*/
|
||||
class ResChunkHeader(
|
||||
// Type identifier for this chunk. The meaning of this value depends on the containing chunk.
|
||||
val typeId: Short,
|
||||
// Size of the chunk header (in bytes). Adding this value to the address of the chunk will be
|
||||
// the address of the associated data if any.
|
||||
val headerSize: Short
|
||||
) {
|
||||
val headerSize: Short) {
|
||||
|
||||
constructor() : this(0, 0)
|
||||
constructor(): this(0, 0)
|
||||
|
||||
// Total size of this chunk (in bytes). This is the chunkSize plus the size of any data
|
||||
// associated with this chunk. Adding the this to the address of this chunk will completely skip
|
||||
@@ -71,52 +74,48 @@ enum class ChunkType(val id: Short) {
|
||||
TABLE_OVERLAYABLE_POLICY_TYPE(0x0205),
|
||||
}
|
||||
|
||||
/** Representation of a value in a resource, supplying type information. */
|
||||
/**
|
||||
* Representation of a value in a resource, supplying type information.
|
||||
*/
|
||||
data class ResValue(val dataType: DataType, val data: Int, val size: Short = 0) {
|
||||
|
||||
constructor() : this(DataType.NULL, 0)
|
||||
|
||||
/** type of the data value. */
|
||||
// type of the data value.
|
||||
enum class DataType(val byteValue: Byte) {
|
||||
/**
|
||||
* The 'data' is either 0 or 1, specifying this resource is undefined or empty, respectively.
|
||||
*/
|
||||
// The 'data' is either 0 or 1, specifying this resource is undefined or empty, respectively.
|
||||
NULL(0X00),
|
||||
/** The 'data' holds a ResTable reference, i.e. a reference to another resource. */
|
||||
// The 'data' holds a ResTable reference, i.e. a reference to another resource.
|
||||
REFERENCE(0x01),
|
||||
/** The 'data' holds an attribute resource identifier. */
|
||||
// The 'data' holds an attribute resource identifier.
|
||||
ATTRIBUTE(0x02),
|
||||
/** The 'data' holds an index into the containing resource table's string pool. */
|
||||
// The 'data' holds an index into the containing resource table's string pool.
|
||||
STRING(0x03),
|
||||
/** The 'data' holds a single-precision floating point number. */
|
||||
// The 'data' holds a single-precision floating point number.
|
||||
FLOAT(0x04),
|
||||
/** The 'data' holds a fixed point number encoding a dimension value, e.g. 100in. */
|
||||
// The 'data' holds a fixed point number encoding a dimension value, e.g. 100in.
|
||||
DIMENSION(0x05),
|
||||
/** The 'data' holds a fixed point number encoding a fraction of a container. */
|
||||
// The 'data' holds a fixed point number encoding a fraction of a container.
|
||||
FRACTION(0x06),
|
||||
/**
|
||||
* The 'data' holds a dynamic ResTable reference, which needs to be resolved before it can be
|
||||
* used as a REFERENCE.
|
||||
*/
|
||||
// The 'data' holds a dynamic ResTable reference, which needs to be resolved before it can be
|
||||
// used as a REFERENCE.
|
||||
DYNAMIC_REFERENCE(0x07),
|
||||
/**
|
||||
* The 'data' holds an attribute resource identifier, which needs to be resolved before it can
|
||||
* be used like a ATTRIBUTE.
|
||||
*/
|
||||
// The 'data' holds an attribute resource identifier, which needs to be resolved before it can
|
||||
// be used like a ATTRIBUTE.
|
||||
DYNAMIC_ATTRIBUTE(0x08),
|
||||
/** The 'data' is a raw integer of the form n..n. */
|
||||
// The 'data' is a raw integer of the form n..n.
|
||||
INT_DEC(0x10),
|
||||
/** The 'data' is a raw integer value of the form 0xn..n. */
|
||||
// The 'data' is a raw integer value of the form 0xn..n.
|
||||
INT_HEX(0x11),
|
||||
/** The 'data' is either 0 or 1, for input 'false' or 'true' respectively. */
|
||||
// The 'data' is either 0 or 1, for input 'false' or 'true' respectively.
|
||||
INT_BOOLEAN(0x12),
|
||||
/** The 'data' is a raw integer value of the form #aarrggbb. */
|
||||
// The 'data' is a raw integer value of the form #aarrggbb.
|
||||
INT_COLOR_ARGB8(0x1c),
|
||||
/** The 'data' is a raw integer value of the form #rrggbb. */
|
||||
// The 'data' is a raw integer value of the form #rrggbb.
|
||||
INT_COLOR_RGB8(0x1d),
|
||||
/** The 'data' is a raw integer value of the form #argb */
|
||||
// The 'data' is a raw integer value of the form #argb
|
||||
INT_COLOR_ARGB4(0x1e),
|
||||
/** The 'data is a raw integer value of the form #rgb */
|
||||
// The 'data is a raw integer value of the form #rgb
|
||||
INT_COLOR_RGB4(0x1f);
|
||||
|
||||
companion object {
|
||||
@@ -134,10 +133,6 @@ data class ResValue(val dataType: DataType, val data: Int, val size: Short = 0)
|
||||
const val UNIT_SHIFT = 0
|
||||
const val UNIT_MASK = 0xf
|
||||
|
||||
// ==================================
|
||||
// The values here are same as specified in TypedValue
|
||||
// ==================================
|
||||
|
||||
// TYPE_DIMENSION: Value is raw pixels.
|
||||
const val UNIT_PX = 0
|
||||
// TYPE_DIMENSION: Value is Device Independent Pixels.
|
||||
@@ -184,12 +179,14 @@ data class ResValue(val dataType: DataType, val data: Int, val size: Short = 0)
|
||||
}
|
||||
}
|
||||
|
||||
/** Reference to a string in a string pool */
|
||||
|
||||
/**
|
||||
* Reference to a string in a string pool
|
||||
*/
|
||||
data class ResStringPoolRef(
|
||||
// Index into the string pool table (unsigned 32 bit offset from the indices immediately after
|
||||
// ResStringPoolHeader) at which to find the location of the string data in the pool
|
||||
val index: Int
|
||||
)
|
||||
val index: Int)
|
||||
|
||||
/**
|
||||
* Definition of a pool of strings.
|
||||
@@ -202,8 +199,8 @@ data class ResStringPoolRef(
|
||||
* to indicate this format is being used.
|
||||
*
|
||||
* <p> If {@code styleCount} is not zero, then immediately following the array of indices into the
|
||||
* string table is another array of indices into a style table starting at {@code stylesStart}. Each
|
||||
* entry in the style table is an array of {@code ResStringPoolSpan} structures.
|
||||
* string table is another array of indices into a style table starting at {@code stylesStart}.
|
||||
* Each entry in the style table is an array of {@code ResStringPoolSpan} structures.
|
||||
*/
|
||||
data class ResStringPoolHeader(
|
||||
val header: ResChunkHeader,
|
||||
@@ -211,10 +208,9 @@ data class ResStringPoolHeader(
|
||||
val stringCount: Int,
|
||||
// Number of style span arrays in the pool (number of 32 bit indices that follow the string
|
||||
// indices).
|
||||
val styleCount: Int
|
||||
) {
|
||||
val styleCount: Int) {
|
||||
|
||||
constructor() : this(ResChunkHeader(), 0, 0)
|
||||
constructor(): this(ResChunkHeader(), 0, 0)
|
||||
|
||||
var flags: Int = 0
|
||||
// Index from header of the string data.
|
||||
@@ -230,7 +226,9 @@ data class ResStringPoolHeader(
|
||||
}
|
||||
}
|
||||
|
||||
/** This structure defines a span of style information associated with a string in the pool. */
|
||||
/**
|
||||
* This structure defines a span of style information associated with a string in the pool.
|
||||
*/
|
||||
data class ResStringPoolSpan(
|
||||
// this is the name of the span -- that is, the name of the XML tag that defined it. The special
|
||||
// value END indicates the end of an array of spans.
|
||||
@@ -246,15 +244,13 @@ data class ResStringPoolSpan(
|
||||
}
|
||||
|
||||
/** Convenience class for accessing data in a String Pool Flattened Resource */
|
||||
class ResStringPool
|
||||
private constructor(
|
||||
class ResStringPool private constructor(
|
||||
val data: ByteBuffer,
|
||||
val header: ResStringPoolHeader,
|
||||
val stringPoolSize: Int,
|
||||
val strings: List<String>,
|
||||
val stylesPoolSize: Int,
|
||||
val styles: List<List<ResStringPoolSpan>>
|
||||
) {
|
||||
val styles: List<List<ResStringPoolSpan>>) {
|
||||
|
||||
companion object {
|
||||
fun get(buffer: ByteBuffer, length: Int): ResStringPool {
|
||||
@@ -268,8 +264,7 @@ private constructor(
|
||||
val headerSize = buffer.getShort(2).deviceToHost()
|
||||
val resourceSize = buffer.getInt(4).deviceToHost()
|
||||
|
||||
if (
|
||||
typeId != ChunkType.STRING_POOL_TYPE.id ||
|
||||
if (typeId != ChunkType.STRING_POOL_TYPE.id ||
|
||||
headerSize != ResStringPoolHeader.SIZE ||
|
||||
resourceSize < headerSize ||
|
||||
resourceSize > length
|
||||
@@ -283,10 +278,7 @@ private constructor(
|
||||
|
||||
val header =
|
||||
ResStringPoolHeader(
|
||||
chunkHeader,
|
||||
buffer.getInt(8).deviceToHost(),
|
||||
buffer.getInt(12).deviceToHost()
|
||||
)
|
||||
chunkHeader, buffer.getInt(8).deviceToHost(), buffer.getInt(12).deviceToHost())
|
||||
header.flags = buffer.getInt(16).deviceToHost()
|
||||
header.stringsStart = buffer.getInt(20).deviceToHost()
|
||||
header.stylesStart = buffer.getInt(24).deviceToHost()
|
||||
@@ -295,10 +287,8 @@ private constructor(
|
||||
val strings = mutableListOf<String>()
|
||||
if (header.stringCount != 0) {
|
||||
// we need to check overflow and ensure the string indexes can fit.
|
||||
if (
|
||||
header.stringCount * 4 < header.stringCount ||
|
||||
(header.header.headerSize + (header.stringCount * 4)) > resourceSize
|
||||
) {
|
||||
if (header.stringCount*4 < header.stringCount ||
|
||||
(header.header.headerSize + (header.stringCount*4)) > resourceSize) {
|
||||
error("Invalid StringPool: Buffer not large enough for string indices.")
|
||||
}
|
||||
|
||||
@@ -306,7 +296,7 @@ private constructor(
|
||||
|
||||
// There should at least be enough space for the smallest string.
|
||||
// (2 bytes length, null terminator)
|
||||
if (header.stringsStart + 2 >= resourceSize) {
|
||||
if (header.stringsStart+2 >= resourceSize) {
|
||||
error("Invalid StringPool: Buffer not large enough for strings.")
|
||||
}
|
||||
|
||||
@@ -324,7 +314,7 @@ private constructor(
|
||||
stringPoolSize = (header.stylesStart - header.stringsStart) / charSize
|
||||
}
|
||||
|
||||
if (stringPoolSize == 0) {
|
||||
if (stringPoolSize ==0) {
|
||||
error("Invalid StringPool: Space for strings in header is too small.")
|
||||
}
|
||||
|
||||
@@ -343,13 +333,13 @@ private constructor(
|
||||
val styles = mutableListOf<List<ResStringPoolSpan>>()
|
||||
if (header.styleCount != 0) {
|
||||
|
||||
var currentStyleIndex = headerSize.toInt() + header.stringCount * 4
|
||||
var currentStyleIndex = headerSize.toInt() + header.stringCount*4
|
||||
// invariant: integer overflow in calculating styles
|
||||
if (currentStyleIndex < headerSize.toInt()) {
|
||||
error("Invalid StringPool: Integer overflow encountered while decoding styles.")
|
||||
}
|
||||
|
||||
stylePoolSize = (resourceSize - header.stylesStart) / 4
|
||||
stylePoolSize = (resourceSize - header.stylesStart)/4
|
||||
|
||||
for (i in 0.until(header.styleCount)) {
|
||||
val styleLocation = buffer.getInt(currentStyleIndex).deviceToHost() + header.stylesStart
|
||||
@@ -370,8 +360,7 @@ private constructor(
|
||||
val firstByteUTF16 = buffer.get(stringPosition)
|
||||
++stringPosition
|
||||
|
||||
val utf16Length =
|
||||
when {
|
||||
val utf16Length = when {
|
||||
(firstByteUTF16.toInt() and StringPool.TWO_BYTE_UTF8_LENGTH_SIGNIFIER) != 0 -> {
|
||||
val secondByte = buffer.get(stringPosition).toInt() and 0xff
|
||||
++stringPosition
|
||||
@@ -385,8 +374,7 @@ private constructor(
|
||||
val firstByteUTF8 = buffer.get(stringPosition)
|
||||
++stringPosition
|
||||
|
||||
val utf8Length =
|
||||
when {
|
||||
val utf8Length = when {
|
||||
(firstByteUTF8.toInt() and StringPool.TWO_BYTE_UTF8_LENGTH_SIGNIFIER) != 0 -> {
|
||||
val secondByte = buffer.get(stringPosition).toInt() and 0xff
|
||||
++stringPosition
|
||||
@@ -420,8 +408,7 @@ private constructor(
|
||||
val firstShort = buffer.getShort(stringPosition).deviceToHost()
|
||||
stringPosition += 2
|
||||
|
||||
val utf16Length =
|
||||
when {
|
||||
val utf16Length = when {
|
||||
(firstShort.toInt() and StringPool.TWO_CHAR_UTF16_LENGTH_SIGNIFIER) != 0 -> {
|
||||
val secondShort = buffer.getShort(stringPosition).deviceToHost().toInt() and 0xffff
|
||||
stringPosition += 2
|
||||
@@ -466,7 +453,7 @@ private constructor(
|
||||
}
|
||||
|
||||
fun parseHex(codePoint: Int) =
|
||||
when (codePoint) {
|
||||
when(codePoint) {
|
||||
in '0'.code..'9'.code -> codePoint - '0'.code
|
||||
in 'A'.code..'F'.code -> codePoint - 'A'.code + 10
|
||||
in 'a'.code..'f'.code -> codePoint - 'a'.code + 10
|
||||
@@ -490,17 +477,17 @@ fun stringToInt(string: String): ResValue? {
|
||||
isNegative = true
|
||||
}
|
||||
|
||||
if (codePointCount == index || trimmedString.codePointAt(index) !in '0'.code..'9'.code) {
|
||||
if (codePointCount == index
|
||||
|| trimmedString.codePointAt(index) !in '0'.code..'9'.code
|
||||
) {
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
val isHex: Boolean
|
||||
if (
|
||||
codePointCount >= index + 2 &&
|
||||
trimmedString.codePointAt(index) == '0'.code &&
|
||||
trimmedString.codePointAt(index + 1) == 'x'.code
|
||||
) {
|
||||
if (codePointCount >= index + 2
|
||||
&& trimmedString.codePointAt(index) == '0'.code
|
||||
&& trimmedString.codePointAt(index+1) == 'x'.code) {
|
||||
isHex = true
|
||||
index += 2
|
||||
|
||||
@@ -538,7 +525,7 @@ fun stringToInt(string: String): ResValue? {
|
||||
++index
|
||||
|
||||
val decValue = codePoint - '0'.code
|
||||
value = (value * 10) + decValue
|
||||
value = (value*10) + decValue
|
||||
|
||||
val outOfBounds =
|
||||
if (isNegative) -value < Int.MIN_VALUE.toLong() else value > Int.MAX_VALUE.toLong()
|
||||
@@ -553,20 +540,14 @@ fun stringToInt(string: String): ResValue? {
|
||||
}
|
||||
|
||||
return ResValue(
|
||||
if (isHex) ResValue.DataType.INT_HEX else ResValue.DataType.INT_DEC,
|
||||
value.toInt()
|
||||
)
|
||||
if(isHex) ResValue.DataType.INT_HEX else ResValue.DataType.INT_DEC,
|
||||
value.toInt())
|
||||
}
|
||||
|
||||
private data class UnitEntry(
|
||||
val name: String,
|
||||
val dataType: ResValue.DataType,
|
||||
val unitValue: Int,
|
||||
val scale: Float = 1.0f
|
||||
)
|
||||
val name: String, val dataType: ResValue.DataType, val unitValue: Int, val scale: Float = 1.0f)
|
||||
|
||||
private val unitSuffixes =
|
||||
listOf(
|
||||
private val unitSuffixes = listOf(
|
||||
UnitEntry("px", ResValue.DataType.DIMENSION, ResValue.ComplexFormat.UNIT_PX),
|
||||
UnitEntry("dip", ResValue.DataType.DIMENSION, ResValue.ComplexFormat.UNIT_DIP),
|
||||
UnitEntry("dp", ResValue.DataType.DIMENSION, ResValue.ComplexFormat.UNIT_DIP),
|
||||
@@ -574,16 +555,11 @@ private val unitSuffixes =
|
||||
UnitEntry("pt", ResValue.DataType.DIMENSION, ResValue.ComplexFormat.UNIT_PT),
|
||||
UnitEntry("in", ResValue.DataType.DIMENSION, ResValue.ComplexFormat.UNIT_IN),
|
||||
UnitEntry("mm", ResValue.DataType.DIMENSION, ResValue.ComplexFormat.UNIT_MM),
|
||||
UnitEntry("%", ResValue.DataType.FRACTION, ResValue.ComplexFormat.UNIT_FRACTION, 1.0f / 100),
|
||||
UnitEntry("%", ResValue.DataType.FRACTION, ResValue.ComplexFormat.UNIT_FRACTION, 1.0f/100),
|
||||
UnitEntry(
|
||||
"%p",
|
||||
ResValue.DataType.FRACTION,
|
||||
ResValue.ComplexFormat.UNIT_FRACTION_PARENT,
|
||||
1.0f / 100
|
||||
)
|
||||
)
|
||||
"%p", ResValue.DataType.FRACTION, ResValue.ComplexFormat.UNIT_FRACTION_PARENT, 1.0f/100))
|
||||
|
||||
private fun parseUnitType(string: String): UnitEntry? {
|
||||
private fun parseUnitType(string: String) : UnitEntry? {
|
||||
for (entry in unitSuffixes) {
|
||||
if (string.endsWith(entry.name)) {
|
||||
return entry
|
||||
@@ -605,7 +581,7 @@ fun stringToFloat(string: String): ResValue? {
|
||||
if (entry != null) trimmedString.lastIndexOf(entry.name) else trimmedString.length
|
||||
|
||||
// no spaces allowed between suffix and floating point value
|
||||
if (suffixIndex == 0 || Character.isWhitespace(trimmedString.codePointAt(suffixIndex - 1))) {
|
||||
if (suffixIndex == 0 || Character.isWhitespace(trimmedString.codePointAt(suffixIndex-1))) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -615,7 +591,8 @@ fun stringToFloat(string: String): ResValue? {
|
||||
// i.e "0x1d.dp" should be considered: "0x1d.d p" not "0x1d. dp"
|
||||
if (parseHex(entry?.name?.codePointAt(0) ?: 0) != -1) {
|
||||
// try to parse the float value with the beginning of the suffix considered.
|
||||
if (trimmedString.contains("0x", true) && !stringToParse.contains('p')) {
|
||||
if (trimmedString.contains("0x", true) &&
|
||||
!stringToParse.contains('p')) {
|
||||
// ambiguous value string, resulting in a parse failure.
|
||||
return null
|
||||
}
|
||||
@@ -647,20 +624,19 @@ fun stringToFloat(string: String): ResValue? {
|
||||
|
||||
// Transform the float to (rounded) integer with the lower 23 bits representing the fraction
|
||||
// and bits 45 to 23 representing the whole number part.
|
||||
val bits = (parsedValue * (1 shl 23) + .5f).toLong()
|
||||
val bits = (parsedValue*(1 shl 23) + .5f).toLong()
|
||||
|
||||
val (radix, shift) =
|
||||
when {
|
||||
val (radix, shift) = when {
|
||||
bits and ((1L shl 23) - 1) == 0L ->
|
||||
// Always use 23p0 if there is no fraction, as it is easier to read.
|
||||
Pair(ResValue.ComplexFormat.RADIX_23p0, 23)
|
||||
bits and ((1L shl 23) - 1).inv() == 0L ->
|
||||
// Whole number part is zero -- can fit into 0 leading bits of precision.
|
||||
Pair(ResValue.ComplexFormat.RADIX_0p23, 0)
|
||||
bits and ((1L shl 31) - 1).inv() == 0L ->
|
||||
bits and ((1L shl 31) -1).inv() == 0L ->
|
||||
// Magnitude can fit in 8 leading bits of precision.
|
||||
Pair(ResValue.ComplexFormat.RADIX_8p15, 8)
|
||||
bits and ((1L shl 39) - 1).inv() == 0L ->
|
||||
bits and ((1L shl 39) -1).inv() == 0L ->
|
||||
// Magnitude can fit in 16 leading bits of precision.
|
||||
Pair(ResValue.ComplexFormat.RADIX_16p7, 16)
|
||||
else ->
|
||||
@@ -673,8 +649,7 @@ fun stringToFloat(string: String): ResValue? {
|
||||
mantissa = (-mantissa) and ResValue.ComplexFormat.MANTISSA_MASK
|
||||
}
|
||||
|
||||
val dataValue =
|
||||
(entry.unitValue shl ResValue.ComplexFormat.UNIT_SHIFT) or
|
||||
val dataValue = (entry.unitValue shl ResValue.ComplexFormat.UNIT_SHIFT) or
|
||||
(radix shl ResValue.ComplexFormat.RADIX_SHIFT) or
|
||||
(mantissa shl ResValue.ComplexFormat.MANTISSA_SHIFT)
|
||||
|
||||
|
||||
Executable → Regular
+1
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.aaptcompiler.android
|
||||
|
||||
import androidx.collection.mutableIntIntMapOf
|
||||
import java.nio.ByteOrder
|
||||
|
||||
private val littleEndian = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN
|
||||
|
||||
Executable → Regular
Executable → Regular
+134
-31
@@ -1,6 +1,6 @@
|
||||
package com.android.aaptcompiler.proto
|
||||
|
||||
import androidx.collection.MutableIntObjectMap
|
||||
import androidx.collection.mutableIntObjectMapOf
|
||||
import com.android.aapt.ConfigurationOuterClass
|
||||
import com.android.aapt.Resources
|
||||
import com.android.aaptcompiler.AllowNew
|
||||
@@ -45,7 +45,8 @@ import com.android.utils.ILogger
|
||||
import com.itsaky.androidide.layoutlib.resources.ResourceVisibility
|
||||
|
||||
fun deserializeConfigFromPb(
|
||||
config: ConfigurationOuterClass.Configuration, logger: ILogger?): ConfigDescription? {
|
||||
config: ConfigurationOuterClass.Configuration, logger: ILogger?
|
||||
): ConfigDescription? {
|
||||
|
||||
val mcc = config.getMcc().toShort()
|
||||
val mnc = config.getMnc().toShort()
|
||||
@@ -62,8 +63,10 @@ fun deserializeConfigFromPb(
|
||||
val screenLayoutDir = when (config.getLayoutDirection()) {
|
||||
ConfigurationOuterClass.Configuration.LayoutDirection.LAYOUT_DIRECTION_LTR ->
|
||||
ResTableConfig.SCREEN_LAYOUT.DIR_LTR
|
||||
|
||||
ConfigurationOuterClass.Configuration.LayoutDirection.LAYOUT_DIRECTION_RTL ->
|
||||
ResTableConfig.SCREEN_LAYOUT.DIR_RTL
|
||||
|
||||
else -> ResTableConfig.SCREEN_LAYOUT.DIR_ANY
|
||||
}
|
||||
|
||||
@@ -74,36 +77,46 @@ fun deserializeConfigFromPb(
|
||||
val screenLayoutSize = when (config.getScreenLayoutSize()) {
|
||||
ConfigurationOuterClass.Configuration.ScreenLayoutSize.SCREEN_LAYOUT_SIZE_SMALL ->
|
||||
ResTableConfig.SCREEN_LAYOUT.SIZE_SMALL
|
||||
|
||||
ConfigurationOuterClass.Configuration.ScreenLayoutSize.SCREEN_LAYOUT_SIZE_NORMAL ->
|
||||
ResTableConfig.SCREEN_LAYOUT.SIZE_NORMAL
|
||||
|
||||
ConfigurationOuterClass.Configuration.ScreenLayoutSize.SCREEN_LAYOUT_SIZE_LARGE ->
|
||||
ResTableConfig.SCREEN_LAYOUT.SIZE_LARGE
|
||||
|
||||
ConfigurationOuterClass.Configuration.ScreenLayoutSize.SCREEN_LAYOUT_SIZE_XLARGE ->
|
||||
ResTableConfig.SCREEN_LAYOUT.SIZE_XLARGE
|
||||
|
||||
else -> ResTableConfig.SCREEN_LAYOUT.SIZE_ANY
|
||||
}
|
||||
|
||||
val screenLayoutLong = when (config.getScreenLayoutLong()) {
|
||||
ConfigurationOuterClass.Configuration.ScreenLayoutLong.SCREEN_LAYOUT_LONG_LONG ->
|
||||
ResTableConfig.SCREEN_LAYOUT.SCREENLONG_YES
|
||||
|
||||
ConfigurationOuterClass.Configuration.ScreenLayoutLong.SCREEN_LAYOUT_LONG_NOTLONG ->
|
||||
ResTableConfig.SCREEN_LAYOUT.SCREENLONG_NO
|
||||
|
||||
else -> ResTableConfig.SCREEN_LAYOUT.SCREENLONG_ANY
|
||||
}
|
||||
|
||||
val screenRound = when (config.getScreenRound()) {
|
||||
ConfigurationOuterClass.Configuration.ScreenRound.SCREEN_ROUND_ROUND ->
|
||||
ResTableConfig.SCREEN_LAYOUT2.SCREENROUND_YES
|
||||
|
||||
ConfigurationOuterClass.Configuration.ScreenRound.SCREEN_ROUND_NOTROUND ->
|
||||
ResTableConfig.SCREEN_LAYOUT2.SCREENROUND_NO
|
||||
|
||||
else -> ResTableConfig.SCREEN_LAYOUT2.SCREENROUND_ANY
|
||||
}
|
||||
|
||||
val wideGamutColor = when (config.getWideColorGamut()) {
|
||||
ConfigurationOuterClass.Configuration.WideColorGamut.WIDE_COLOR_GAMUT_WIDECG ->
|
||||
ResTableConfig.COLOR_MODE.WIDE_GAMUT_YES
|
||||
|
||||
ConfigurationOuterClass.Configuration.WideColorGamut.WIDE_COLOR_GAMUT_NOWIDECG ->
|
||||
ResTableConfig.COLOR_MODE.WIDE_GAMUT_NO
|
||||
|
||||
else -> ResTableConfig.COLOR_MODE.WIDE_GAMUT_ANY
|
||||
}
|
||||
|
||||
@@ -116,36 +129,48 @@ fun deserializeConfigFromPb(
|
||||
val orientation = when (config.getOrientation()) {
|
||||
ConfigurationOuterClass.Configuration.Orientation.ORIENTATION_PORT ->
|
||||
ResTableConfig.ORIENTATION.PORT
|
||||
|
||||
ConfigurationOuterClass.Configuration.Orientation.ORIENTATION_LAND ->
|
||||
ResTableConfig.ORIENTATION.LAND
|
||||
|
||||
ConfigurationOuterClass.Configuration.Orientation.ORIENTATION_SQUARE ->
|
||||
ResTableConfig.ORIENTATION.SQUARE
|
||||
|
||||
else -> ResTableConfig.ORIENTATION.ANY
|
||||
}
|
||||
|
||||
val uiModeType = when (config.getUiModeType()) {
|
||||
ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_NORMAL ->
|
||||
ResTableConfig.UI_MODE.TYPE_NORMAL
|
||||
|
||||
ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_DESK ->
|
||||
ResTableConfig.UI_MODE.TYPE_DESK
|
||||
|
||||
ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_CAR ->
|
||||
ResTableConfig.UI_MODE.TYPE_CAR
|
||||
|
||||
ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_TELEVISION ->
|
||||
ResTableConfig.UI_MODE.TYPE_TELEVISION
|
||||
|
||||
ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_APPLIANCE ->
|
||||
ResTableConfig.UI_MODE.TYPE_APPLIANCE
|
||||
|
||||
ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_WATCH ->
|
||||
ResTableConfig.UI_MODE.TYPE_WATCH
|
||||
|
||||
ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_VRHEADSET ->
|
||||
ResTableConfig.UI_MODE.TYPE_VR_HEADSET
|
||||
|
||||
else -> ResTableConfig.UI_MODE.TYPE_ANY
|
||||
}
|
||||
|
||||
val uiModeNight = when (config.getUiModeNight()) {
|
||||
ConfigurationOuterClass.Configuration.UiModeNight.UI_MODE_NIGHT_NIGHT ->
|
||||
ResTableConfig.UI_MODE.NIGHT_YES
|
||||
|
||||
ConfigurationOuterClass.Configuration.UiModeNight.UI_MODE_NIGHT_NOTNIGHT ->
|
||||
ResTableConfig.UI_MODE.NIGHT_NO
|
||||
|
||||
else -> ResTableConfig.UI_MODE.NIGHT_ANY
|
||||
}
|
||||
|
||||
@@ -154,53 +179,81 @@ fun deserializeConfigFromPb(
|
||||
val touchscreen = when (config.getTouchscreen()) {
|
||||
ConfigurationOuterClass.Configuration.Touchscreen.TOUCHSCREEN_NOTOUCH ->
|
||||
ResTableConfig.TOUCHSCREEN.NOTOUCH
|
||||
|
||||
ConfigurationOuterClass.Configuration.Touchscreen.TOUCHSCREEN_STYLUS ->
|
||||
ResTableConfig.TOUCHSCREEN.STYLUS
|
||||
|
||||
ConfigurationOuterClass.Configuration.Touchscreen.TOUCHSCREEN_FINGER ->
|
||||
ResTableConfig.TOUCHSCREEN.FINGER
|
||||
|
||||
else -> ResTableConfig.TOUCHSCREEN.ANY
|
||||
}
|
||||
|
||||
val keysHidden = when (config.getKeysHidden()) {
|
||||
ConfigurationOuterClass.Configuration.KeysHidden.KEYS_HIDDEN_KEYSEXPOSED ->
|
||||
ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_NO
|
||||
|
||||
ConfigurationOuterClass.Configuration.KeysHidden.KEYS_HIDDEN_KEYSHIDDEN ->
|
||||
ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_YES
|
||||
|
||||
ConfigurationOuterClass.Configuration.KeysHidden.KEYS_HIDDEN_KEYSSOFT ->
|
||||
ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_SOFT
|
||||
|
||||
else -> ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_ANY
|
||||
}
|
||||
|
||||
val keyboard = when (config.getKeyboard()) {
|
||||
ConfigurationOuterClass.Configuration.Keyboard.KEYBOARD_NOKEYS ->
|
||||
ResTableConfig.KEYBOARD.NOKEYS
|
||||
|
||||
ConfigurationOuterClass.Configuration.Keyboard.KEYBOARD_QWERTY ->
|
||||
ResTableConfig.KEYBOARD.QWERTY
|
||||
|
||||
ConfigurationOuterClass.Configuration.Keyboard.KEYBOARD_TWELVEKEY ->
|
||||
ResTableConfig.KEYBOARD.TWELVEKEY
|
||||
|
||||
else -> ResTableConfig.KEYBOARD.ANY
|
||||
}
|
||||
|
||||
val navHidden = when (config.getNavHidden()) {
|
||||
ConfigurationOuterClass.Configuration.NavHidden.NAV_HIDDEN_NAVHIDDEN ->
|
||||
ResTableConfig.INPUT_FLAGS.NAVHIDDEN_YES
|
||||
|
||||
ConfigurationOuterClass.Configuration.NavHidden.NAV_HIDDEN_NAVEXPOSED ->
|
||||
ResTableConfig.INPUT_FLAGS.NAVHIDDEN_NO
|
||||
|
||||
else -> ResTableConfig.INPUT_FLAGS.NAVHIDDEN_ANY
|
||||
}
|
||||
|
||||
val navigation = when (config.getNavigation()) {
|
||||
ConfigurationOuterClass.Configuration.Navigation.NAVIGATION_NONAV ->
|
||||
ResTableConfig.NAVIGATION.NONAV
|
||||
|
||||
ConfigurationOuterClass.Configuration.Navigation.NAVIGATION_DPAD ->
|
||||
ResTableConfig.NAVIGATION.DPAD
|
||||
|
||||
ConfigurationOuterClass.Configuration.Navigation.NAVIGATION_TRACKBALL ->
|
||||
ResTableConfig.NAVIGATION.TRACKBALL
|
||||
|
||||
ConfigurationOuterClass.Configuration.Navigation.NAVIGATION_WHEEL ->
|
||||
ResTableConfig.NAVIGATION.WHEEL
|
||||
|
||||
else -> ResTableConfig.NAVIGATION.ANY
|
||||
}
|
||||
|
||||
val grammaticalGender = when (config.grammaticalGender) {
|
||||
ConfigurationOuterClass.Configuration.GrammaticalGender.GRAM_GENDER_NEUTER ->
|
||||
ResTableConfig.GRAMMATICAL_GENDER.NEUTER
|
||||
|
||||
ConfigurationOuterClass.Configuration.GrammaticalGender.GRAM_GENDER_FEMININE ->
|
||||
ResTableConfig.GRAMMATICAL_GENDER.FEMININE
|
||||
|
||||
ConfigurationOuterClass.Configuration.GrammaticalGender.GRAM_GENDER_MASCULINE ->
|
||||
ResTableConfig.GRAMMATICAL_GENDER.MASCULINE
|
||||
|
||||
else -> ResTableConfig.GRAMMATICAL_GENDER.ANY
|
||||
}
|
||||
|
||||
val screenWidth = config.getScreenWidth()
|
||||
val screenHeight = config.getScreenHeight()
|
||||
val sdkVersion = config.getSdkVersion().toShort()
|
||||
@@ -214,6 +267,7 @@ fun deserializeConfigFromPb(
|
||||
density = density,
|
||||
keyboard = keyboard,
|
||||
navigation = navigation,
|
||||
grammaticalInflection = grammaticalGender,
|
||||
inputFlags = (keysHidden.toInt() or navHidden.toInt()).toByte(),
|
||||
screenWidth = screenWidth,
|
||||
screenHeight = screenHeight,
|
||||
@@ -226,7 +280,9 @@ fun deserializeConfigFromPb(
|
||||
screenWidthDp = screenWidthDp,
|
||||
screenHeightDp = screenHeightDp,
|
||||
screenLayout2 = screenRound,
|
||||
colorMode = (wideGamutColor.toInt() or hdr.toInt()).toByte()))
|
||||
colorMode = (wideGamutColor.toInt() or hdr.toInt()).toByte()
|
||||
)
|
||||
)
|
||||
localeValue.writeTo(configDescription)
|
||||
|
||||
return configDescription
|
||||
@@ -250,7 +306,7 @@ fun deserializeSourceFromPb(source: Resources.Source, sourcePool: ResStringPool)
|
||||
return Source(path, line)
|
||||
}
|
||||
|
||||
fun deserializeVisibilityFromPb(level: Resources.Visibility.Level) = when(level) {
|
||||
fun deserializeVisibilityFromPb(level: Resources.Visibility.Level) = when (level) {
|
||||
Resources.Visibility.Level.PRIVATE -> ResourceVisibility.PRIVATE
|
||||
Resources.Visibility.Level.PUBLIC -> ResourceVisibility.PUBLIC
|
||||
else -> ResourceVisibility.UNDEFINED
|
||||
@@ -260,7 +316,8 @@ fun deserializeOverlayableFromPb(
|
||||
item: Resources.OverlayableItem,
|
||||
overlayable: Overlayable,
|
||||
sourcePool: ResStringPool,
|
||||
logger: ILogger?): OverlayableItem? {
|
||||
logger: ILogger?
|
||||
): OverlayableItem? {
|
||||
|
||||
var policies = 0
|
||||
for (policy in item.getPolicyList()) {
|
||||
@@ -289,45 +346,60 @@ fun deserializeOverlayableFromPb(
|
||||
}
|
||||
|
||||
fun deserializeBinPrimitiveFromPb(
|
||||
primitive: Resources.Primitive, logger: ILogger?): BinaryPrimitive? {
|
||||
primitive: Resources.Primitive, logger: ILogger?
|
||||
): BinaryPrimitive? {
|
||||
|
||||
val (type, deviceValue) = when(primitive.getOneofValueCase()) {
|
||||
val (type, deviceValue) = when (primitive.getOneofValueCase()) {
|
||||
Resources.Primitive.OneofValueCase.NULL_VALUE ->
|
||||
Pair(ResValue.DataType.NULL, ResValue.NullFormat.UNDEFINED)
|
||||
|
||||
Resources.Primitive.OneofValueCase.EMPTY_VALUE ->
|
||||
Pair(ResValue.DataType.NULL, ResValue.NullFormat.EMPTY)
|
||||
|
||||
Resources.Primitive.OneofValueCase.FLOAT_VALUE -> {
|
||||
val float = primitive.getFloatValue()
|
||||
Pair(ResValue.DataType.FLOAT, float.toRawBits())
|
||||
}
|
||||
|
||||
Resources.Primitive.OneofValueCase.DIMENSION_VALUE ->
|
||||
Pair(ResValue.DataType.DIMENSION, primitive.getDimensionValue())
|
||||
|
||||
Resources.Primitive.OneofValueCase.FRACTION_VALUE ->
|
||||
Pair(ResValue.DataType.FRACTION, primitive.getFractionValue())
|
||||
|
||||
Resources.Primitive.OneofValueCase.INT_DECIMAL_VALUE ->
|
||||
Pair(ResValue.DataType.INT_DEC, primitive.getIntDecimalValue())
|
||||
|
||||
Resources.Primitive.OneofValueCase.INT_HEXADECIMAL_VALUE ->
|
||||
Pair(ResValue.DataType.INT_HEX, primitive.getIntHexadecimalValue())
|
||||
|
||||
Resources.Primitive.OneofValueCase.BOOLEAN_VALUE -> {
|
||||
val boolValue = if (primitive.getBooleanValue()) 0xffffffff.toInt() else 0
|
||||
Pair(ResValue.DataType.INT_BOOLEAN, boolValue)
|
||||
}
|
||||
|
||||
Resources.Primitive.OneofValueCase.COLOR_ARGB8_VALUE ->
|
||||
Pair(ResValue.DataType.INT_COLOR_ARGB8, primitive.getColorArgb8Value())
|
||||
|
||||
Resources.Primitive.OneofValueCase.COLOR_RGB8_VALUE ->
|
||||
Pair(ResValue.DataType.INT_COLOR_RGB8, primitive.getColorRgb8Value())
|
||||
|
||||
Resources.Primitive.OneofValueCase.COLOR_ARGB4_VALUE ->
|
||||
Pair(ResValue.DataType.INT_COLOR_ARGB4, primitive.getColorArgb4Value())
|
||||
|
||||
Resources.Primitive.OneofValueCase.COLOR_RGB4_VALUE ->
|
||||
Pair(ResValue.DataType.INT_COLOR_RGB4, primitive.getColorRgb4Value())
|
||||
|
||||
Resources.Primitive.OneofValueCase.DIMENSION_VALUE_DEPRECATED -> {
|
||||
val float = primitive.getDimensionValueDeprecated()
|
||||
Pair(ResValue.DataType.DIMENSION, float.toRawBits())
|
||||
}
|
||||
|
||||
Resources.Primitive.OneofValueCase.FRACTION_VALUE_DEPRECATED -> {
|
||||
val float = primitive.getFractionValueDeprecated()
|
||||
Pair(ResValue.DataType.FRACTION, float.toRawBits())
|
||||
}
|
||||
|
||||
else -> {
|
||||
val errorMsg = "Value case unrecognized for Primitive proto: %s"
|
||||
logger?.error(null, errorMsg, primitive.oneofValueCase)
|
||||
@@ -344,7 +416,8 @@ fun deserializeRawFromPb(string: Resources.RawString, valuePool: StringPool) =
|
||||
RawString(valuePool.makeRef(string.getValue()))
|
||||
|
||||
fun deserializeStyledStrFromPb(
|
||||
string: Resources.StyledString, valuePool: StringPool): StyledString {
|
||||
string: Resources.StyledString, valuePool: StringPool
|
||||
): StyledString {
|
||||
|
||||
val spans = mutableListOf<Span>()
|
||||
for (span in string.getSpanList()) {
|
||||
@@ -376,19 +449,23 @@ fun deserializeReferenceFromPb(ref: Resources.Reference, logger: ILogger?): Refe
|
||||
}
|
||||
|
||||
fun deserializeFileRefFromPb(
|
||||
file: Resources.FileReference, valuePool: StringPool, config: ConfigDescription): FileReference {
|
||||
file: Resources.FileReference, valuePool: StringPool, config: ConfigDescription
|
||||
): FileReference {
|
||||
|
||||
val fileRef = FileReference(
|
||||
valuePool.makeRef(
|
||||
file.getPath(),
|
||||
StringPool.Context(StringPool.Context.Priority.HIGH.priority, config)))
|
||||
StringPool.Context(StringPool.Context.Priority.HIGH.priority, config)
|
||||
)
|
||||
)
|
||||
fileRef.type = deserializeFileTypeFromPb(file.getType())
|
||||
|
||||
return fileRef
|
||||
}
|
||||
|
||||
fun deserializeAttrFromPb(
|
||||
attr: Resources.Attribute, sourcePool: ResStringPool, logger: ILogger?): AttributeResource? {
|
||||
attr: Resources.Attribute, sourcePool: ResStringPool, logger: ILogger?
|
||||
): AttributeResource? {
|
||||
|
||||
val attrResource = AttributeResource(attr.getFormatFlags())
|
||||
attrResource.minInt = attr.getMinInt()
|
||||
@@ -404,7 +481,8 @@ fun deserializeAttrFromPb(
|
||||
reference.comment = symbol.getComment()
|
||||
|
||||
attrResource.symbols.add(
|
||||
AttributeResource.Symbol(reference, symbol.getValue(), symbol.getType().toByte()))
|
||||
AttributeResource.Symbol(reference, symbol.getValue(), symbol.getType().toByte())
|
||||
)
|
||||
}
|
||||
|
||||
return attrResource
|
||||
@@ -415,7 +493,8 @@ fun deserializeStyleFromPb(
|
||||
valuePool: StringPool,
|
||||
config: ConfigDescription,
|
||||
sourcePool: ResStringPool,
|
||||
logger: ILogger?): Style? {
|
||||
logger: ILogger?
|
||||
): Style? {
|
||||
|
||||
val styleResource = Style()
|
||||
if (style.hasParent()) {
|
||||
@@ -449,12 +528,13 @@ fun deserializeStyleFromPb(
|
||||
}
|
||||
|
||||
fun deserializeStyleableFromPb(
|
||||
styleable: Resources.Styleable, sourcePool: ResStringPool, logger: ILogger?): Styleable? {
|
||||
styleable: Resources.Styleable, sourcePool: ResStringPool, logger: ILogger?
|
||||
): Styleable? {
|
||||
|
||||
val styleableResource = Styleable()
|
||||
for (entry in styleable.getEntryList()) {
|
||||
val reference = deserializeReferenceFromPb(entry.getAttr(), logger)
|
||||
reference?: return null
|
||||
reference ?: return null
|
||||
if (entry.hasSource()) {
|
||||
reference.source = deserializeSourceFromPb(entry.getSource(), sourcePool)
|
||||
}
|
||||
@@ -469,7 +549,8 @@ fun deserializeArrayFromPb(
|
||||
valuePool: StringPool,
|
||||
config: ConfigDescription,
|
||||
sourcePool: ResStringPool,
|
||||
logger: ILogger?): ArrayResource? {
|
||||
logger: ILogger?
|
||||
): ArrayResource? {
|
||||
|
||||
val arrayResource = ArrayResource()
|
||||
for (entry in array.getElementList()) {
|
||||
@@ -499,7 +580,8 @@ fun deserializePluralFromPb(
|
||||
valuePool: StringPool,
|
||||
config: ConfigDescription,
|
||||
sourcePool: ResStringPool,
|
||||
logger: ILogger?): Plural? {
|
||||
logger: ILogger?
|
||||
): Plural? {
|
||||
|
||||
val pluralResource = Plural()
|
||||
for (entry in plural.getEntryList()) {
|
||||
@@ -526,7 +608,8 @@ fun deserializeMacroFromPb(
|
||||
valuePool: StringPool,
|
||||
config: ConfigDescription,
|
||||
sourcePool: ResStringPool,
|
||||
logger: ILogger?): Macro {
|
||||
logger: ILogger?
|
||||
): Macro {
|
||||
|
||||
val macro = Macro()
|
||||
macro.rawValue = pbMacro.rawString
|
||||
@@ -543,7 +626,8 @@ fun deserializeMacroFromPb(
|
||||
for (untranslatable in pbMacro.untranslatableSectionsList) {
|
||||
untranslatableList.add(
|
||||
UntranslatableSection(
|
||||
untranslatable.startIndex.toInt(), untranslatable.endIndex.toInt())
|
||||
untranslatable.startIndex.toInt(), untranslatable.endIndex.toInt()
|
||||
)
|
||||
)
|
||||
}
|
||||
macro.untranslatables = untranslatableList
|
||||
@@ -563,13 +647,15 @@ fun deserializeItemFromPb(
|
||||
item: Resources.Item,
|
||||
valuePool: StringPool,
|
||||
config: ConfigDescription,
|
||||
logger: ILogger?): Item? = when (item.getValueCase()) {
|
||||
logger: ILogger?
|
||||
): Item? = when (item.getValueCase()) {
|
||||
|
||||
Resources.Item.ValueCase.REF -> deserializeReferenceFromPb(item.getRef(), logger)
|
||||
Resources.Item.ValueCase.STR -> deserializeStringFromPb(item.getStr(), valuePool)
|
||||
Resources.Item.ValueCase.RAW_STR -> deserializeRawFromPb(item.getRawStr(), valuePool)
|
||||
Resources.Item.ValueCase.STYLED_STR ->
|
||||
deserializeStyledStrFromPb(item.getStyledStr(), valuePool)
|
||||
|
||||
Resources.Item.ValueCase.FILE -> deserializeFileRefFromPb(item.getFile(), valuePool, config)
|
||||
Resources.Item.ValueCase.ID -> Id()
|
||||
Resources.Item.ValueCase.PRIM -> deserializeBinPrimitiveFromPb(item.getPrim(), logger)
|
||||
@@ -585,7 +671,8 @@ fun deserializeValueFromPb(
|
||||
valuePool: StringPool,
|
||||
config: ConfigDescription,
|
||||
sourcePool: ResStringPool,
|
||||
logger: ILogger?): Value? {
|
||||
logger: ILogger?
|
||||
): Value? {
|
||||
|
||||
val valueResource = when {
|
||||
value.hasItem() -> deserializeItemFromPb(value.getItem(), valuePool, config, logger)
|
||||
@@ -595,16 +682,22 @@ fun deserializeValueFromPb(
|
||||
when (compoundValue.getValueCase()) {
|
||||
Resources.CompoundValue.ValueCase.ATTR ->
|
||||
deserializeAttrFromPb(compoundValue.getAttr(), sourcePool, logger)
|
||||
|
||||
Resources.CompoundValue.ValueCase.STYLE ->
|
||||
deserializeStyleFromPb(compoundValue.getStyle(), valuePool, config, sourcePool, logger)
|
||||
|
||||
Resources.CompoundValue.ValueCase.STYLEABLE ->
|
||||
deserializeStyleableFromPb(compoundValue.getStyleable(), sourcePool, logger)
|
||||
|
||||
Resources.CompoundValue.ValueCase.ARRAY ->
|
||||
deserializeArrayFromPb(compoundValue.getArray(), valuePool, config, sourcePool, logger)
|
||||
|
||||
Resources.CompoundValue.ValueCase.PLURAL ->
|
||||
deserializePluralFromPb(compoundValue.getPlural(), valuePool, config, sourcePool, logger)
|
||||
|
||||
Resources.CompoundValue.ValueCase.MACRO ->
|
||||
deserializeMacroFromPb(compoundValue.getMacro(), valuePool, config, sourcePool, logger)
|
||||
|
||||
else -> {
|
||||
val errorMsg = "Unrecognized compoundValue value case %s"
|
||||
logger?.error(null, errorMsg, compoundValue.valueCase)
|
||||
@@ -612,6 +705,7 @@ fun deserializeValueFromPb(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
val errorMsg = "Unrecognized case for serialized value %s"
|
||||
logger?.error(null, errorMsg, value.valueCase)
|
||||
@@ -634,12 +728,13 @@ fun deserializePackageFromPb(
|
||||
sourcePool: ResStringPool,
|
||||
overlayables: List<Overlayable>,
|
||||
logger: ILogger?,
|
||||
table: ResourceTable): Boolean {
|
||||
table: ResourceTable
|
||||
): Boolean {
|
||||
|
||||
val packageId =
|
||||
if (original.hasPackageId()) original.getPackageId().getId().toByte() else 0.toByte()
|
||||
|
||||
val idIndex = MutableIntObjectMap<ResourceName>()
|
||||
val idIndex = mutableIntObjectMapOf<ResourceName>()
|
||||
|
||||
val resourcePackage =
|
||||
table.createPackageAllowingDuplicateNames(original.getPackageName(), packageId)
|
||||
@@ -672,11 +767,12 @@ fun deserializePackageFromPb(
|
||||
// Propagate the visibility up to the type group.
|
||||
ResourceVisibility.PUBLIC -> resourceGroup.visibility = ResourceVisibility.PUBLIC
|
||||
// Propagate private, only if previously undefined.
|
||||
ResourceVisibility.PRIVATE-> {
|
||||
ResourceVisibility.PRIVATE -> {
|
||||
if (resourceGroup.visibility == ResourceVisibility.UNDEFINED) {
|
||||
resourceGroup.visibility = ResourceVisibility.PRIVATE
|
||||
}
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
|
||||
@@ -715,7 +811,8 @@ fun deserializePackageFromPb(
|
||||
overlayableItem,
|
||||
overlayables[overlayableItem.getOverlayableIdx()],
|
||||
sourcePool,
|
||||
logger)
|
||||
logger
|
||||
)
|
||||
resourceOverlayable ?: return false
|
||||
|
||||
resourceEntry.overlayable = resourceOverlayable
|
||||
@@ -724,9 +821,11 @@ fun deserializePackageFromPb(
|
||||
val resourceId = resourceIdFromParts(
|
||||
original.getPackageId().getId().toByte(),
|
||||
group.getTypeId().getId().toByte(),
|
||||
entry.getEntryId().getId().toShort())
|
||||
entry.getEntryId().getId().toShort()
|
||||
)
|
||||
if (resourceId.isValidId()) {
|
||||
idIndex.put(resourceId, ResourceName(resourcePackage.name, resourceGroup.type, resourceEntry.name))
|
||||
idIndex[resourceId] =
|
||||
ResourceName(resourcePackage.name, resourceGroup.type, resourceEntry.name)
|
||||
}
|
||||
|
||||
for (configValue in entry.getConfigValueList()) {
|
||||
@@ -744,13 +843,15 @@ fun deserializePackageFromPb(
|
||||
errorMsg,
|
||||
ResourceName(resourcePackage.name, resourceGroup.type, resourceEntry.name),
|
||||
resourceConfig,
|
||||
config.product)
|
||||
config.product
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
resourceConfigValue.value =
|
||||
deserializeValueFromPb(
|
||||
configValue.getValue(), table.stringPool, resourceConfig, sourcePool, logger)
|
||||
configValue.getValue(), table.stringPool, resourceConfig, sourcePool, logger
|
||||
)
|
||||
|
||||
resourceConfigValue.value ?: return false
|
||||
}
|
||||
@@ -780,11 +881,13 @@ fun deserializePackageFromPb(
|
||||
}
|
||||
|
||||
fun deserializeTableFromPb(
|
||||
table: Resources.ResourceTable, outTable: ResourceTable, logger: ILogger?): Boolean {
|
||||
table: Resources.ResourceTable, outTable: ResourceTable, logger: ILogger?
|
||||
): Boolean {
|
||||
|
||||
val sourcePool = ResStringPool.get(
|
||||
table.getSourcePool().getData().asReadOnlyByteBuffer(),
|
||||
table.getSourcePool().getSerializedSize())
|
||||
table.getSourcePool().getSerializedSize()
|
||||
)
|
||||
|
||||
// Deserialize the overlayable groups of a table
|
||||
val overlayables = mutableListOf<Overlayable>()
|
||||
|
||||
Executable → Regular
+142
-42
@@ -1,6 +1,7 @@
|
||||
package com.android.aaptcompiler.proto
|
||||
|
||||
import android.aapt.pb.internal.ResourcesInternal
|
||||
import androidx.collection.intIntMapOf
|
||||
import com.android.aapt.ConfigurationOuterClass
|
||||
import com.android.aapt.Resources
|
||||
import com.android.aaptcompiler.ArrayResource
|
||||
@@ -17,6 +18,7 @@ import com.android.aaptcompiler.OverlayableItem
|
||||
import com.android.aaptcompiler.Plural
|
||||
import com.android.aaptcompiler.RawString
|
||||
import com.android.aaptcompiler.Reference
|
||||
import com.android.aaptcompiler.ResourceCompilationException
|
||||
import com.android.aaptcompiler.ResourceFile
|
||||
import com.android.aaptcompiler.ResourceName
|
||||
import com.android.aaptcompiler.ResourceTable
|
||||
@@ -31,13 +33,17 @@ import com.android.aaptcompiler.android.ResTableConfig
|
||||
import com.android.aaptcompiler.android.ResValue
|
||||
import com.android.aaptcompiler.blameSource
|
||||
import com.android.aaptcompiler.buffer.BigBuffer
|
||||
import com.itsaky.androidide.layoutlib.resources.ResourceVisibility
|
||||
import com.android.utils.ILogger
|
||||
import com.google.protobuf.ByteString
|
||||
import com.itsaky.androidide.layoutlib.resources.ResourceVisibility
|
||||
|
||||
internal fun serializePoolToPb(pool: StringPool, logger: ILogger?): Resources.StringPool {
|
||||
val buffer = BigBuffer(1024)
|
||||
try {
|
||||
pool.flattenUtf8(buffer, logger)
|
||||
} catch (e: Exception) {
|
||||
throw ResourceCompilationException("Failed to flatten utf-8 string.", e)
|
||||
}
|
||||
|
||||
val builder = Resources.StringPool.newBuilder()
|
||||
builder.setData(ByteString.copyFrom(buffer.toBytes()))
|
||||
@@ -53,7 +59,8 @@ internal fun serializeSourceToPb(source: Source, sourcePool: StringPool): Resour
|
||||
sourceBuilder.setPathIdx(ref.index())
|
||||
if (source.line != null) {
|
||||
sourceBuilder.setPosition(
|
||||
Resources.SourcePosition.newBuilder().setLineNumber(source.line).build())
|
||||
Resources.SourcePosition.newBuilder().setLineNumber(source.line).build()
|
||||
)
|
||||
}
|
||||
return sourceBuilder.build()
|
||||
}
|
||||
@@ -63,10 +70,12 @@ fun serializeTableToPb(table: ResourceTable, logger: ILogger? = null): Resources
|
||||
val sourcePool = StringPool()
|
||||
|
||||
|
||||
tableBuilder.addToolFingerprint(Resources.ToolFingerprint.newBuilder()
|
||||
tableBuilder.addToolFingerprint(
|
||||
Resources.ToolFingerprint.newBuilder()
|
||||
.setTool(ToolFingerprint.TOOL_NAME)
|
||||
.setVersion(ToolFingerprint.FINGERPRINT)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
val overlayables = mutableListOf<Overlayable>()
|
||||
for (resourcePackage in table.packages) {
|
||||
val packageBuilder = Resources.Package.newBuilder()
|
||||
@@ -76,7 +85,8 @@ fun serializeTableToPb(table: ResourceTable, logger: ILogger? = null): Resources
|
||||
packageBuilder.setPackageId(
|
||||
Resources.PackageId.newBuilder()
|
||||
.setId(packageId.toInt())
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
packageBuilder.setPackageName(resourcePackage.name)
|
||||
|
||||
@@ -88,7 +98,8 @@ fun serializeTableToPb(table: ResourceTable, logger: ILogger? = null): Resources
|
||||
groupBuilder.setTypeId(
|
||||
Resources.TypeId.newBuilder()
|
||||
.setId(groupId.toInt())
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
||||
groupBuilder.setName(resourceGroup.type.tagName)
|
||||
@@ -102,7 +113,8 @@ fun serializeTableToPb(table: ResourceTable, logger: ILogger? = null): Resources
|
||||
entryBuilder.setEntryId(
|
||||
Resources.EntryId.newBuilder()
|
||||
.setId(entryId.toInt())
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
entryBuilder.setName(entry.name)
|
||||
|
||||
@@ -114,7 +126,8 @@ fun serializeTableToPb(table: ResourceTable, logger: ILogger? = null): Resources
|
||||
visibilityBuilder
|
||||
.setLevel(serializeVisibilityToPb(entry.visibility.level))
|
||||
.setComment(entry.visibility.comment)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
val entryAllowNew = entry.allowNew
|
||||
if (entryAllowNew != null) {
|
||||
@@ -125,7 +138,8 @@ fun serializeTableToPb(table: ResourceTable, logger: ILogger? = null): Resources
|
||||
entryBuilder.setAllowNew(
|
||||
allowNewBuilder
|
||||
.setComment(entryAllowNew.comment)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
||||
val entryOverlayableItem = entry.overlayable
|
||||
@@ -136,7 +150,9 @@ fun serializeTableToPb(table: ResourceTable, logger: ILogger? = null): Resources
|
||||
entryOverlayableItem,
|
||||
overlayables,
|
||||
tableBuilder,
|
||||
sourcePool))
|
||||
sourcePool
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
for (configValue in entry.values) {
|
||||
@@ -159,9 +175,10 @@ fun serializeTableToPb(table: ResourceTable, logger: ILogger? = null): Resources
|
||||
}
|
||||
|
||||
fun serializeVisibilityToPb(resourceVisibility: ResourceVisibility) =
|
||||
when(resourceVisibility) {
|
||||
when (resourceVisibility) {
|
||||
ResourceVisibility.PRIVATE,
|
||||
ResourceVisibility.PRIVATE_XML_ONLY -> Resources.Visibility.Level.PRIVATE
|
||||
|
||||
ResourceVisibility.PUBLIC -> Resources.Visibility.Level.PUBLIC
|
||||
else -> Resources.Visibility.Level.UNKNOWN
|
||||
}
|
||||
@@ -179,7 +196,9 @@ fun serializeCompiledFileToPb(file: ResourceFile): ResourcesInternal.CompiledFil
|
||||
.setResourceName(exportedResourceName.name.toString())
|
||||
.setSource(
|
||||
Resources.SourcePosition.newBuilder()
|
||||
.setLineNumber(exportedResourceName.line)))
|
||||
.setLineNumber(exportedResourceName.line)
|
||||
)
|
||||
)
|
||||
}
|
||||
return compiledFile.build()
|
||||
}
|
||||
@@ -187,7 +206,8 @@ fun serializeCompiledFileToPb(file: ResourceFile): ResourcesInternal.CompiledFil
|
||||
fun serializeConfigToPb(
|
||||
config: ConfigDescription,
|
||||
product: String?,
|
||||
logger: ILogger?): ConfigurationOuterClass.Configuration {
|
||||
logger: ILogger?
|
||||
): ConfigurationOuterClass.Configuration {
|
||||
|
||||
val configBuilder = ConfigurationOuterClass.Configuration.newBuilder()
|
||||
configBuilder.setMcc(config.mcc.toInt() and 0xffff)
|
||||
@@ -198,10 +218,13 @@ fun serializeConfigToPb(
|
||||
when ((config.screenLayout.toInt() and ResTableConfig.SCREEN_LAYOUT.DIR_MASK).toByte()) {
|
||||
ResTableConfig.SCREEN_LAYOUT.DIR_LTR ->
|
||||
ConfigurationOuterClass.Configuration.LayoutDirection.LAYOUT_DIRECTION_LTR
|
||||
|
||||
ResTableConfig.SCREEN_LAYOUT.DIR_RTL ->
|
||||
ConfigurationOuterClass.Configuration.LayoutDirection.LAYOUT_DIRECTION_RTL
|
||||
|
||||
else -> ConfigurationOuterClass.Configuration.LayoutDirection.LAYOUT_DIRECTION_UNSET
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setScreenWidth(config.screenWidth)
|
||||
configBuilder.setScreenHeight(config.screenHeight)
|
||||
@@ -213,14 +236,19 @@ fun serializeConfigToPb(
|
||||
when ((config.screenLayout.toInt() and ResTableConfig.SCREEN_LAYOUT.SIZE_MASK).toByte()) {
|
||||
ResTableConfig.SCREEN_LAYOUT.SIZE_SMALL ->
|
||||
ConfigurationOuterClass.Configuration.ScreenLayoutSize.SCREEN_LAYOUT_SIZE_SMALL
|
||||
|
||||
ResTableConfig.SCREEN_LAYOUT.SIZE_NORMAL ->
|
||||
ConfigurationOuterClass.Configuration.ScreenLayoutSize.SCREEN_LAYOUT_SIZE_NORMAL
|
||||
|
||||
ResTableConfig.SCREEN_LAYOUT.SIZE_LARGE ->
|
||||
ConfigurationOuterClass.Configuration.ScreenLayoutSize.SCREEN_LAYOUT_SIZE_LARGE
|
||||
|
||||
ResTableConfig.SCREEN_LAYOUT.SIZE_XLARGE ->
|
||||
ConfigurationOuterClass.Configuration.ScreenLayoutSize.SCREEN_LAYOUT_SIZE_XLARGE
|
||||
|
||||
else -> ConfigurationOuterClass.Configuration.ScreenLayoutSize.SCREEN_LAYOUT_SIZE_UNSET
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setScreenLayoutLong(
|
||||
when (
|
||||
@@ -228,10 +256,13 @@ fun serializeConfigToPb(
|
||||
|
||||
ResTableConfig.SCREEN_LAYOUT.SCREENLONG_YES ->
|
||||
ConfigurationOuterClass.Configuration.ScreenLayoutLong.SCREEN_LAYOUT_LONG_LONG
|
||||
|
||||
ResTableConfig.SCREEN_LAYOUT.SCREENLONG_NO ->
|
||||
ConfigurationOuterClass.Configuration.ScreenLayoutLong.SCREEN_LAYOUT_LONG_NOTLONG
|
||||
|
||||
else -> ConfigurationOuterClass.Configuration.ScreenLayoutLong.SCREEN_LAYOUT_LONG_UNSET
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setScreenRound(
|
||||
when (
|
||||
@@ -239,65 +270,87 @@ fun serializeConfigToPb(
|
||||
|
||||
ResTableConfig.SCREEN_LAYOUT2.SCREENROUND_YES ->
|
||||
ConfigurationOuterClass.Configuration.ScreenRound.SCREEN_ROUND_ROUND
|
||||
|
||||
ResTableConfig.SCREEN_LAYOUT2.SCREENROUND_NO ->
|
||||
ConfigurationOuterClass.Configuration.ScreenRound.SCREEN_ROUND_NOTROUND
|
||||
|
||||
else -> ConfigurationOuterClass.Configuration.ScreenRound.SCREEN_ROUND_UNSET
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setWideColorGamut(
|
||||
when ((config.colorMode.toInt() and ResTableConfig.COLOR_MODE.WIDE_GAMUT_MASK).toByte()) {
|
||||
ResTableConfig.COLOR_MODE.WIDE_GAMUT_YES ->
|
||||
ConfigurationOuterClass.Configuration.WideColorGamut.WIDE_COLOR_GAMUT_WIDECG
|
||||
|
||||
ResTableConfig.COLOR_MODE.WIDE_GAMUT_NO ->
|
||||
ConfigurationOuterClass.Configuration.WideColorGamut.WIDE_COLOR_GAMUT_NOWIDECG
|
||||
|
||||
else -> ConfigurationOuterClass.Configuration.WideColorGamut.WIDE_COLOR_GAMUT_UNSET
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setHdr(
|
||||
when ((config.colorMode.toInt() and ResTableConfig.COLOR_MODE.HDR_MASK).toByte()) {
|
||||
ResTableConfig.COLOR_MODE.HDR_YES -> ConfigurationOuterClass.Configuration.Hdr.HDR_HIGHDR
|
||||
ResTableConfig.COLOR_MODE.HDR_NO -> ConfigurationOuterClass.Configuration.Hdr.HDR_LOWDR
|
||||
else -> ConfigurationOuterClass.Configuration.Hdr.HDR_UNSET
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setOrientation(
|
||||
when (config.orientation) {
|
||||
ResTableConfig.ORIENTATION.PORT ->
|
||||
ConfigurationOuterClass.Configuration.Orientation.ORIENTATION_PORT
|
||||
|
||||
ResTableConfig.ORIENTATION.LAND ->
|
||||
ConfigurationOuterClass.Configuration.Orientation.ORIENTATION_LAND
|
||||
|
||||
ResTableConfig.ORIENTATION.SQUARE ->
|
||||
ConfigurationOuterClass.Configuration.Orientation.ORIENTATION_SQUARE
|
||||
|
||||
else -> ConfigurationOuterClass.Configuration.Orientation.ORIENTATION_UNSET
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setUiModeType(
|
||||
when ((config.uiMode.toInt() and ResTableConfig.UI_MODE.TYPE_MASK).toByte()) {
|
||||
ResTableConfig.UI_MODE.TYPE_NORMAL ->
|
||||
ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_NORMAL
|
||||
|
||||
ResTableConfig.UI_MODE.TYPE_DESK ->
|
||||
ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_DESK
|
||||
|
||||
ResTableConfig.UI_MODE.TYPE_CAR ->
|
||||
ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_CAR
|
||||
|
||||
ResTableConfig.UI_MODE.TYPE_TELEVISION ->
|
||||
ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_TELEVISION
|
||||
|
||||
ResTableConfig.UI_MODE.TYPE_APPLIANCE ->
|
||||
ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_APPLIANCE
|
||||
|
||||
ResTableConfig.UI_MODE.TYPE_WATCH ->
|
||||
ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_WATCH
|
||||
|
||||
ResTableConfig.UI_MODE.TYPE_VR_HEADSET ->
|
||||
ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_VRHEADSET
|
||||
|
||||
else -> ConfigurationOuterClass.Configuration.UiModeType.UI_MODE_TYPE_UNSET
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setUiModeNight(
|
||||
when ((config.uiMode.toInt() and ResTableConfig.UI_MODE.NIGHT_MASK).toByte()) {
|
||||
ResTableConfig.UI_MODE.NIGHT_YES ->
|
||||
ConfigurationOuterClass.Configuration.UiModeNight.UI_MODE_NIGHT_NIGHT
|
||||
|
||||
ResTableConfig.UI_MODE.NIGHT_NO ->
|
||||
ConfigurationOuterClass.Configuration.UiModeNight.UI_MODE_NIGHT_NOTNIGHT
|
||||
|
||||
else -> ConfigurationOuterClass.Configuration.UiModeNight.UI_MODE_NIGHT_UNSET
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setDensity(config.density)
|
||||
|
||||
@@ -305,56 +358,91 @@ fun serializeConfigToPb(
|
||||
when (config.touchscreen) {
|
||||
ResTableConfig.TOUCHSCREEN.NOTOUCH ->
|
||||
ConfigurationOuterClass.Configuration.Touchscreen.TOUCHSCREEN_NOTOUCH
|
||||
|
||||
ResTableConfig.TOUCHSCREEN.STYLUS ->
|
||||
ConfigurationOuterClass.Configuration.Touchscreen.TOUCHSCREEN_STYLUS
|
||||
|
||||
ResTableConfig.TOUCHSCREEN.FINGER ->
|
||||
ConfigurationOuterClass.Configuration.Touchscreen.TOUCHSCREEN_FINGER
|
||||
|
||||
else -> ConfigurationOuterClass.Configuration.Touchscreen.TOUCHSCREEN_UNSET
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setKeysHidden(
|
||||
when ((config.inputFlags.toInt() and ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_MASK).toByte()) {
|
||||
ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_NO ->
|
||||
ConfigurationOuterClass.Configuration.KeysHidden.KEYS_HIDDEN_KEYSEXPOSED
|
||||
|
||||
ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_YES ->
|
||||
ConfigurationOuterClass.Configuration.KeysHidden.KEYS_HIDDEN_KEYSHIDDEN
|
||||
|
||||
ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_SOFT ->
|
||||
ConfigurationOuterClass.Configuration.KeysHidden.KEYS_HIDDEN_KEYSSOFT
|
||||
|
||||
else -> ConfigurationOuterClass.Configuration.KeysHidden.KEYS_HIDDEN_UNSET
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setKeyboard(
|
||||
when (config.keyboard) {
|
||||
ResTableConfig.KEYBOARD.NOKEYS ->
|
||||
ConfigurationOuterClass.Configuration.Keyboard.KEYBOARD_NOKEYS
|
||||
|
||||
ResTableConfig.KEYBOARD.QWERTY ->
|
||||
ConfigurationOuterClass.Configuration.Keyboard.KEYBOARD_QWERTY
|
||||
|
||||
ResTableConfig.KEYBOARD.TWELVEKEY ->
|
||||
ConfigurationOuterClass.Configuration.Keyboard.KEYBOARD_TWELVEKEY
|
||||
|
||||
else -> ConfigurationOuterClass.Configuration.Keyboard.KEYBOARD_UNSET
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setNavHidden(
|
||||
when ((config.inputFlags.toInt() and ResTableConfig.INPUT_FLAGS.NAVHIDDEN_MASK).toByte()) {
|
||||
ResTableConfig.INPUT_FLAGS.NAVHIDDEN_YES ->
|
||||
ConfigurationOuterClass.Configuration.NavHidden.NAV_HIDDEN_NAVHIDDEN
|
||||
|
||||
ResTableConfig.INPUT_FLAGS.NAVHIDDEN_NO ->
|
||||
ConfigurationOuterClass.Configuration.NavHidden.NAV_HIDDEN_NAVEXPOSED
|
||||
|
||||
else -> ConfigurationOuterClass.Configuration.NavHidden.NAV_HIDDEN_UNSET
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setNavigation(
|
||||
when (config.navigation) {
|
||||
ResTableConfig.NAVIGATION.NONAV ->
|
||||
ConfigurationOuterClass.Configuration.Navigation.NAVIGATION_NONAV
|
||||
|
||||
ResTableConfig.NAVIGATION.DPAD ->
|
||||
ConfigurationOuterClass.Configuration.Navigation.NAVIGATION_DPAD
|
||||
|
||||
ResTableConfig.NAVIGATION.TRACKBALL ->
|
||||
ConfigurationOuterClass.Configuration.Navigation.NAVIGATION_TRACKBALL
|
||||
|
||||
ResTableConfig.NAVIGATION.WHEEL ->
|
||||
ConfigurationOuterClass.Configuration.Navigation.NAVIGATION_WHEEL
|
||||
|
||||
else -> ConfigurationOuterClass.Configuration.Navigation.NAVIGATION_UNSET
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setGrammaticalGender(
|
||||
when (config.grammaticalInflection) {
|
||||
ResTableConfig.GRAMMATICAL_GENDER.NEUTER ->
|
||||
ConfigurationOuterClass.Configuration.GrammaticalGender.GRAM_GENDER_NEUTER
|
||||
|
||||
ResTableConfig.GRAMMATICAL_GENDER.FEMININE ->
|
||||
ConfigurationOuterClass.Configuration.GrammaticalGender.GRAM_GENDER_FEMININE
|
||||
|
||||
ResTableConfig.GRAMMATICAL_GENDER.MASCULINE ->
|
||||
ConfigurationOuterClass.Configuration.GrammaticalGender.GRAM_GENDER_MASCULINE
|
||||
|
||||
else -> ConfigurationOuterClass.Configuration.GrammaticalGender.GRAM_GENDER_USET
|
||||
}
|
||||
)
|
||||
|
||||
configBuilder.setSdkVersion(config.sdkVersion.toInt() and 0xffff)
|
||||
|
||||
@@ -369,7 +457,8 @@ fun serializeOverlayableToPb(
|
||||
item: OverlayableItem,
|
||||
overlayables: MutableList<Overlayable>,
|
||||
table: Resources.ResourceTable.Builder,
|
||||
sourcePool: StringPool): Resources.OverlayableItem {
|
||||
sourcePool: StringPool
|
||||
): Resources.OverlayableItem {
|
||||
|
||||
// Retrieve the index of the overlayable in the list of groups that have already been serialized.
|
||||
val foundIndex = overlayables.indexOf(item.overlayable)
|
||||
@@ -427,6 +516,7 @@ fun serializeOverlayableToPb(
|
||||
fun serializeReferenceTypeToPb(type: Reference.Type) = when (type) {
|
||||
Reference.Type.RESOURCE ->
|
||||
Resources.Reference.Type.REFERENCE
|
||||
|
||||
Reference.Type.ATTRIBUTE ->
|
||||
Resources.Reference.Type.ATTRIBUTE
|
||||
}
|
||||
@@ -495,7 +585,8 @@ fun serializeBinPrimitiveToPb(primitive: BinaryPrimitive, logger: ILogger?): Res
|
||||
|
||||
if (resVal == null) {
|
||||
logger?.error(
|
||||
null, "%s, Failed to serialize primitive %s.", blameSource(primitive.source), primitive)
|
||||
null, "%s, Failed to serialize primitive %s.", blameSource(primitive.source), primitive
|
||||
)
|
||||
return primitiveBuilder.build()
|
||||
}
|
||||
|
||||
@@ -504,14 +595,17 @@ fun serializeBinPrimitiveToPb(primitive: BinaryPrimitive, logger: ILogger?): Res
|
||||
when (resVal.data) {
|
||||
ResValue.NullFormat.UNDEFINED ->
|
||||
primitiveBuilder.setNullValue(Resources.Primitive.NullType.newBuilder().build())
|
||||
|
||||
ResValue.NullFormat.EMPTY ->
|
||||
primitiveBuilder.setEmptyValue(Resources.Primitive.EmptyType.newBuilder().build())
|
||||
|
||||
else -> {
|
||||
val errorMsg = "%s, Invalid null format value '%s' for primitive %s."
|
||||
logger?.error(null, errorMsg, blameSource(primitive.source), resVal.data, primitive)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ResValue.DataType.FLOAT -> primitiveBuilder.setFloatValue(Float.fromBits(resVal.data))
|
||||
ResValue.DataType.DIMENSION -> primitiveBuilder.setDimensionValue(resVal.data)
|
||||
ResValue.DataType.FRACTION -> primitiveBuilder.setFractionValue(resVal.data)
|
||||
@@ -548,7 +642,8 @@ fun serializeAttrToPb(attribute: AttributeResource, sourcePool: StringPool): Res
|
||||
.setName(serializeReferenceToPb(symbol.symbol))
|
||||
.setValue(symbol.value)
|
||||
.setType(symbol.type.toInt())
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
||||
return attrBuilder.build()
|
||||
@@ -575,7 +670,8 @@ fun serializeStyleToPb(style: Style, sourcePool: StringPool, logger: ILogger?):
|
||||
.setKey(serializeReferenceToPb(entry.key))
|
||||
.setComment(entry.key.comment)
|
||||
.setItem(serializeItemToPb(entry.value!!, logger))
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
return styleBuilder.build()
|
||||
}
|
||||
@@ -592,13 +688,15 @@ fun serializeStyleableToPb(styleable: Styleable, sourcePool: StringPool): Resour
|
||||
entryBuilder
|
||||
.setComment(entry.comment)
|
||||
.setAttr(serializeReferenceToPb(entry))
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
return styleableBuilder.build()
|
||||
}
|
||||
|
||||
fun serializeArrayToPb(
|
||||
array: ArrayResource, sourcePool: StringPool, logger: ILogger?): Resources.Array {
|
||||
array: ArrayResource, sourcePool: StringPool, logger: ILogger?
|
||||
): Resources.Array {
|
||||
|
||||
val arrayBuilder = Resources.Array.newBuilder()
|
||||
for (element in array.elements) {
|
||||
@@ -610,13 +708,15 @@ fun serializeArrayToPb(
|
||||
entryBuilder
|
||||
.setComment(element.comment)
|
||||
.setItem(serializeItemToPb(element, logger))
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
return arrayBuilder.build()
|
||||
}
|
||||
|
||||
fun serializePluralToPb(
|
||||
plural: Plural, sourcePool: StringPool, logger: ILogger?): Resources.Plural {
|
||||
plural: Plural, sourcePool: StringPool, logger: ILogger?
|
||||
): Resources.Plural {
|
||||
|
||||
val pluralBuilder = Resources.Plural.newBuilder()
|
||||
for (type in Plural.Type.TYPES) {
|
||||
@@ -631,20 +731,20 @@ fun serializePluralToPb(
|
||||
.setComment(entry.comment)
|
||||
.setArity(serializePluralTypeToPb(type))
|
||||
.setItem(serializeItemToPb(entry, logger))
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
return pluralBuilder.build()
|
||||
}
|
||||
|
||||
fun serializeMacroToPb(macro: Macro): Resources.MacroBody {
|
||||
|
||||
val macroBuilder = Resources.MacroBody.newBuilder()
|
||||
macroBuilder.rawString = macro.rawValue!!
|
||||
|
||||
val styleString = macroBuilder.styleStringBuilder
|
||||
val styleString = Resources.StyleString.newBuilder()
|
||||
styleString.str = macro.styleString!!.str
|
||||
for (span in macro.styleString!!.spans) {
|
||||
val spansBuilder = styleString.addSpansBuilder()
|
||||
val spansBuilder = Resources.StyleString.Span.newBuilder()
|
||||
spansBuilder.name = span.name
|
||||
spansBuilder.startIndex = span.firstChar
|
||||
spansBuilder.endIndex = span.lastChar
|
||||
@@ -653,14 +753,14 @@ fun serializeMacroToPb(macro: Macro): Resources.MacroBody {
|
||||
macroBuilder.styleString = styleString.build()
|
||||
|
||||
for (untranslatables in macro.untranslatables) {
|
||||
val section = macroBuilder.addUntranslatableSectionsBuilder()
|
||||
val section = Resources.UntranslatableSection.newBuilder()
|
||||
section.startIndex = untranslatables.startIndex.toLong()
|
||||
section.endIndex = untranslatables.endIndex.toLong()
|
||||
macroBuilder.addUntranslatableSections(section.build())
|
||||
}
|
||||
|
||||
for (aliasNamespace in macro.aliasNamespaces) {
|
||||
val namespace = macroBuilder.addNamespaceStackBuilder()
|
||||
val namespace = Resources.NamespaceAlias.newBuilder()
|
||||
namespace.prefix = aliasNamespace.alias
|
||||
namespace.packageName = aliasNamespace.packageName
|
||||
namespace.isPrivate = aliasNamespace.isPrivate
|
||||
@@ -709,7 +809,7 @@ fun serializeValueToPb(value: Value, sourcePool: StringPool, logger: ILogger?):
|
||||
}
|
||||
valueBuilder.setCompoundValue(compoundBuilder.build())
|
||||
}
|
||||
if (value.source.isNotEmpty()){
|
||||
if (value.source.isNotEmpty()) {
|
||||
valueBuilder.setSource(serializeSourceToPb(value.source, sourcePool))
|
||||
}
|
||||
return valueBuilder
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
syntax = "proto3";
|
||||
|
||||
//package aapt.pb;
|
||||
|
||||
option java_package = "com.android.aapt";
|
||||
|
||||
// A description of the requirements a device must have in order for a
|
||||
// resource to be matched and selected.
|
||||
message Configuration {
|
||||
enum LayoutDirection {
|
||||
LAYOUT_DIRECTION_UNSET = 0;
|
||||
LAYOUT_DIRECTION_LTR = 1;
|
||||
LAYOUT_DIRECTION_RTL = 2;
|
||||
}
|
||||
enum ScreenLayoutSize {
|
||||
SCREEN_LAYOUT_SIZE_UNSET = 0;
|
||||
SCREEN_LAYOUT_SIZE_SMALL = 1;
|
||||
SCREEN_LAYOUT_SIZE_NORMAL = 2;
|
||||
SCREEN_LAYOUT_SIZE_LARGE = 3;
|
||||
SCREEN_LAYOUT_SIZE_XLARGE = 4;
|
||||
}
|
||||
enum ScreenLayoutLong {
|
||||
SCREEN_LAYOUT_LONG_UNSET = 0;
|
||||
SCREEN_LAYOUT_LONG_LONG = 1;
|
||||
SCREEN_LAYOUT_LONG_NOTLONG = 2;
|
||||
}
|
||||
enum ScreenRound {
|
||||
SCREEN_ROUND_UNSET = 0;
|
||||
SCREEN_ROUND_ROUND = 1;
|
||||
SCREEN_ROUND_NOTROUND = 2;
|
||||
}
|
||||
enum WideColorGamut {
|
||||
WIDE_COLOR_GAMUT_UNSET = 0;
|
||||
WIDE_COLOR_GAMUT_WIDECG = 1;
|
||||
WIDE_COLOR_GAMUT_NOWIDECG = 2;
|
||||
}
|
||||
enum Hdr {
|
||||
HDR_UNSET = 0;
|
||||
HDR_HIGHDR = 1;
|
||||
HDR_LOWDR = 2;
|
||||
}
|
||||
enum Orientation {
|
||||
ORIENTATION_UNSET = 0;
|
||||
ORIENTATION_PORT = 1;
|
||||
ORIENTATION_LAND = 2;
|
||||
ORIENTATION_SQUARE = 3;
|
||||
}
|
||||
enum UiModeType {
|
||||
UI_MODE_TYPE_UNSET = 0;
|
||||
UI_MODE_TYPE_NORMAL = 1;
|
||||
UI_MODE_TYPE_DESK = 2;
|
||||
UI_MODE_TYPE_CAR = 3;
|
||||
UI_MODE_TYPE_TELEVISION = 4;
|
||||
UI_MODE_TYPE_APPLIANCE = 5;
|
||||
UI_MODE_TYPE_WATCH = 6;
|
||||
UI_MODE_TYPE_VRHEADSET = 7;
|
||||
}
|
||||
enum UiModeNight {
|
||||
UI_MODE_NIGHT_UNSET = 0;
|
||||
UI_MODE_NIGHT_NIGHT = 1;
|
||||
UI_MODE_NIGHT_NOTNIGHT = 2;
|
||||
}
|
||||
enum Touchscreen {
|
||||
TOUCHSCREEN_UNSET = 0;
|
||||
TOUCHSCREEN_NOTOUCH = 1;
|
||||
TOUCHSCREEN_STYLUS = 2;
|
||||
TOUCHSCREEN_FINGER = 3;
|
||||
}
|
||||
enum KeysHidden {
|
||||
KEYS_HIDDEN_UNSET = 0;
|
||||
KEYS_HIDDEN_KEYSEXPOSED = 1;
|
||||
KEYS_HIDDEN_KEYSHIDDEN = 2;
|
||||
KEYS_HIDDEN_KEYSSOFT = 3;
|
||||
}
|
||||
enum Keyboard {
|
||||
KEYBOARD_UNSET = 0;
|
||||
KEYBOARD_NOKEYS = 1;
|
||||
KEYBOARD_QWERTY = 2;
|
||||
KEYBOARD_TWELVEKEY = 3;
|
||||
}
|
||||
enum NavHidden {
|
||||
NAV_HIDDEN_UNSET = 0;
|
||||
NAV_HIDDEN_NAVEXPOSED = 1;
|
||||
NAV_HIDDEN_NAVHIDDEN = 2;
|
||||
}
|
||||
enum Navigation {
|
||||
NAVIGATION_UNSET = 0;
|
||||
NAVIGATION_NONAV = 1;
|
||||
NAVIGATION_DPAD = 2;
|
||||
NAVIGATION_TRACKBALL = 3;
|
||||
NAVIGATION_WHEEL = 4;
|
||||
}
|
||||
enum GrammaticalGender {
|
||||
GRAM_GENDER_USET = 0;
|
||||
GRAM_GENDER_NEUTER = 1;
|
||||
GRAM_GENDER_FEMININE = 2;
|
||||
GRAM_GENDER_MASCULINE = 3;
|
||||
}
|
||||
//
|
||||
// Axis/dimensions that are understood by the runtime.
|
||||
//
|
||||
// Mobile country code.
|
||||
uint32 mcc = 1;
|
||||
// Mobile network code.
|
||||
uint32 mnc = 2;
|
||||
// BCP-47 locale tag.
|
||||
string locale = 3;
|
||||
// Left-to-right, right-to-left...
|
||||
LayoutDirection layout_direction = 4;
|
||||
// Screen width in pixels. Prefer screen_width_dp.
|
||||
uint32 screen_width = 5;
|
||||
// Screen height in pixels. Prefer screen_height_dp.
|
||||
uint32 screen_height = 6;
|
||||
// Screen width in density independent pixels (dp).
|
||||
uint32 screen_width_dp = 7;
|
||||
// Screen height in density independent pixels (dp).
|
||||
uint32 screen_height_dp = 8;
|
||||
// The smallest screen dimension, regardless of orientation, in dp.
|
||||
uint32 smallest_screen_width_dp = 9;
|
||||
// Whether the device screen is classified as small, normal, large, xlarge.
|
||||
ScreenLayoutSize screen_layout_size = 10;
|
||||
// Whether the device screen is long.
|
||||
ScreenLayoutLong screen_layout_long = 11;
|
||||
// Whether the screen is round (Android Wear).
|
||||
ScreenRound screen_round = 12;
|
||||
// Whether the screen supports wide color gamut.
|
||||
WideColorGamut wide_color_gamut = 13;
|
||||
// Whether the screen has high dynamic range.
|
||||
Hdr hdr = 14;
|
||||
// Which orientation the device is in (portrait, landscape).
|
||||
Orientation orientation = 15;
|
||||
// Which type of UI mode the device is in (television, car, etc.).
|
||||
UiModeType ui_mode_type = 16;
|
||||
// Whether the device is in night mode.
|
||||
UiModeNight ui_mode_night = 17;
|
||||
// The device's screen density in dots-per-inch (dpi).
|
||||
uint32 density = 18;
|
||||
// Whether a touchscreen exists, supports a stylus, or finger.
|
||||
Touchscreen touchscreen = 19;
|
||||
// Whether the keyboard hardware keys are currently hidden, exposed, or
|
||||
// if the keyboard is a software keyboard.
|
||||
KeysHidden keys_hidden = 20;
|
||||
// The type of keyboard present (none, QWERTY, 12-key).
|
||||
Keyboard keyboard = 21;
|
||||
// Whether the navigation is exposed or hidden.
|
||||
NavHidden nav_hidden = 22;
|
||||
// The type of navigation present on the device
|
||||
// (trackball, wheel, dpad, etc.).
|
||||
Navigation navigation = 23;
|
||||
// The minimum SDK version of the device.
|
||||
uint32 sdk_version = 24;
|
||||
// Grammatical gender.
|
||||
GrammaticalGender grammatical_gender = 26;
|
||||
//
|
||||
// Build-time only dimensions.
|
||||
//
|
||||
string product = 25;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# AAPT2 Protobuf sources
|
||||
|
||||
These files are taken from
|
||||
the [AAPT2 sources](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/tools/aapt2/),
|
||||
licensed under The Apache License 2.0. See the files for the license.
|
||||
@@ -0,0 +1,528 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
import "com/android/aapt/Configuration.proto";
|
||||
|
||||
// package aapt.pb;
|
||||
|
||||
option java_package = "com.android.aapt";
|
||||
|
||||
|
||||
// A string pool that wraps the binary form of the C++ class android::ResStringPool.
|
||||
message StringPool {
|
||||
bytes data = 1;
|
||||
}
|
||||
// The position of a declared entity within a file.
|
||||
message SourcePosition {
|
||||
uint32 line_number = 1;
|
||||
uint32 column_number = 2;
|
||||
}
|
||||
// Developer friendly source file information for an entity in the resource table.
|
||||
message Source {
|
||||
// The index of the string path within the source string pool of a ResourceTable.
|
||||
uint32 path_idx = 1;
|
||||
SourcePosition position = 2;
|
||||
}
|
||||
// The name and version fingerprint of a build tool.
|
||||
message ToolFingerprint {
|
||||
string tool = 1;
|
||||
string version = 2;
|
||||
}
|
||||
// References to non local resources
|
||||
message DynamicRefTable {
|
||||
PackageId package_id = 1;
|
||||
string package_name = 2;
|
||||
}
|
||||
// Top level message representing a resource table.
|
||||
message ResourceTable {
|
||||
// The string pool containing source paths referenced throughout the resource table. This does
|
||||
// not end up in the final binary ARSC file.
|
||||
StringPool source_pool = 1;
|
||||
// Resource definitions corresponding to an Android package.
|
||||
repeated Package package = 2;
|
||||
// The <overlayable> declarations within the resource table.
|
||||
repeated Overlayable overlayable = 3;
|
||||
// The version fingerprints of the tools that built the resource table.
|
||||
repeated ToolFingerprint tool_fingerprint = 4;
|
||||
repeated DynamicRefTable dynamic_ref_table = 5;
|
||||
}
|
||||
// A package ID in the range [0x00, 0xff].
|
||||
message PackageId {
|
||||
uint32 id = 1;
|
||||
}
|
||||
// Defines resources for an Android package.
|
||||
message Package {
|
||||
// The package ID of this package, in the range [0x00, 0xff].
|
||||
// - ID 0x00 is reserved for shared libraries, or when the ID is assigned at run-time.
|
||||
// - ID 0x01 is reserved for the 'android' package (framework).
|
||||
// - ID range [0x02, 0x7f) is reserved for auto-assignment to shared libraries at run-time.
|
||||
// - ID 0x7f is reserved for the application package.
|
||||
// - IDs > 0x7f are reserved for the application as well and are treated as feature splits.
|
||||
// This may not be set if no ID was assigned.
|
||||
PackageId package_id = 1;
|
||||
// The Java compatible Android package name of the app.
|
||||
string package_name = 2;
|
||||
// The series of types defined by the package.
|
||||
repeated Type type = 3;
|
||||
}
|
||||
// A type ID in the range [0x01, 0xff].
|
||||
message TypeId {
|
||||
uint32 id = 1;
|
||||
}
|
||||
// A set of resources grouped under a common type. Such types include string, layout, xml, dimen,
|
||||
// attr, etc. This maps to the second part of a resource identifier in Java (R.type.entry).
|
||||
message Type {
|
||||
// The ID of the type. This may not be set if no ID was assigned.
|
||||
TypeId type_id = 1;
|
||||
// The name of the type. This corresponds to the 'type' part of a full resource name of the form
|
||||
// package:type/entry. The set of legal type names is listed in Resource.cpp.
|
||||
string name = 2;
|
||||
// The entries defined for this type.
|
||||
repeated Entry entry = 3;
|
||||
}
|
||||
// The Visibility of a symbol/entry (public, private, undefined).
|
||||
message Visibility {
|
||||
// The visibility of the resource outside of its package.
|
||||
enum Level {
|
||||
// No visibility was explicitly specified. This is typically treated as private.
|
||||
// The distinction is important when two separate R.java files are generated: a public and
|
||||
// private one. An unknown visibility, in this case, would cause the resource to be omitted
|
||||
// from either R.java.
|
||||
UNKNOWN = 0;
|
||||
// A resource was explicitly marked as private. This means the resource can not be accessed
|
||||
// outside of its package unless the @*package:type/entry notation is used (the asterisk being
|
||||
// the private accessor). If two R.java files are generated (private + public), the resource
|
||||
// will only be emitted to the private R.java file.
|
||||
PRIVATE = 1;
|
||||
// A resource was explicitly marked as public. This means the resource can be accessed
|
||||
// from any package, and is emitted into all R.java files, public and private.
|
||||
PUBLIC = 2;
|
||||
}
|
||||
Level level = 1;
|
||||
// The path at which this entry's visibility was defined (eg. public.xml).
|
||||
Source source = 2;
|
||||
// The comment associated with the <public> tag.
|
||||
string comment = 3;
|
||||
// Indicates that the resource id may change across builds and that the public R.java identifier
|
||||
// for this resource should not be final. This is set to `true` for resources in `staging-group`
|
||||
// tags.
|
||||
bool staged_api = 4;
|
||||
}
|
||||
// Whether a resource comes from a compile-time overlay and is explicitly allowed to not overlay an
|
||||
// existing resource.
|
||||
message AllowNew {
|
||||
// Where this was defined in source.
|
||||
Source source = 1;
|
||||
// Any comment associated with the declaration.
|
||||
string comment = 2;
|
||||
}
|
||||
// Represents a set of overlayable resources.
|
||||
message Overlayable {
|
||||
// The name of the <overlayable>.
|
||||
string name = 1;
|
||||
// The location of the <overlayable> declaration in the source.
|
||||
Source source = 2;
|
||||
// The component responsible for enabling and disabling overlays targeting this <overlayable>.
|
||||
string actor = 3;
|
||||
}
|
||||
// Represents an overlayable <item> declaration within an <overlayable> tag.
|
||||
message OverlayableItem {
|
||||
enum Policy {
|
||||
NONE = 0;
|
||||
PUBLIC = 1;
|
||||
SYSTEM = 2;
|
||||
VENDOR = 3;
|
||||
PRODUCT = 4;
|
||||
SIGNATURE = 5;
|
||||
ODM = 6;
|
||||
OEM = 7;
|
||||
ACTOR = 8;
|
||||
CONFIG_SIGNATURE = 9;
|
||||
}
|
||||
// The location of the <item> declaration in source.
|
||||
Source source = 1;
|
||||
// Any comment associated with the declaration.
|
||||
string comment = 2;
|
||||
// The policy defined by the enclosing <policy> tag of this <item>.
|
||||
repeated Policy policy = 3;
|
||||
// The index into overlayable list that points to the <overlayable> tag that contains
|
||||
// this <item>.
|
||||
uint32 overlayable_idx = 4;
|
||||
}
|
||||
// The staged resource ID definition of a finalized resource.
|
||||
message StagedId {
|
||||
Source source = 1;
|
||||
uint32 staged_id = 2;
|
||||
}
|
||||
// An entry ID in the range [0x0000, 0xffff].
|
||||
message EntryId {
|
||||
uint32 id = 1;
|
||||
}
|
||||
// An entry declaration. An entry has a full resource ID that is the combination of package ID,
|
||||
// type ID, and its own entry ID. An entry on its own has no value, but values are defined for
|
||||
// various configurations/variants.
|
||||
message Entry {
|
||||
// The ID of this entry. Together with the package ID and type ID, this forms a full resource ID
|
||||
// of the form 0xPPTTEEEE, where PP is the package ID, TT is the type ID, and EEEE is the entry
|
||||
// ID.
|
||||
// This may not be set if no ID was assigned.
|
||||
EntryId entry_id = 1;
|
||||
// The name of this entry. This corresponds to the 'entry' part of a full resource name of the
|
||||
// form package:type/entry.
|
||||
string name = 2;
|
||||
// The visibility of this entry (public, private, undefined).
|
||||
Visibility visibility = 3;
|
||||
// Whether this resource, when originating from a compile-time overlay, is allowed to NOT overlay
|
||||
// any existing resources.
|
||||
AllowNew allow_new = 4;
|
||||
// Whether this resource can be overlaid by a runtime resource overlay (RRO).
|
||||
OverlayableItem overlayable_item = 5;
|
||||
// The set of values defined for this entry, each corresponding to a different
|
||||
// configuration/variant.
|
||||
repeated ConfigValue config_value = 6;
|
||||
// The staged resource ID of this finalized resource.
|
||||
StagedId staged_id = 7;
|
||||
}
|
||||
// A Configuration/Value pair.
|
||||
message ConfigValue {
|
||||
Configuration config = 1;
|
||||
Value value = 2;
|
||||
}
|
||||
// The generic meta-data for every value in a resource table.
|
||||
message Value {
|
||||
// Where the value was defined.
|
||||
Source source = 1;
|
||||
// Any comment associated with the value.
|
||||
string comment = 2;
|
||||
// Whether the value can be overridden.
|
||||
bool weak = 3;
|
||||
// The value is either an Item or a CompoundValue.
|
||||
oneof value {
|
||||
Item item = 4;
|
||||
CompoundValue compound_value = 5;
|
||||
}
|
||||
}
|
||||
// An Item is an abstract type. It represents a value that can appear inline in many places, such
|
||||
// as XML attribute values or on the right hand side of style attribute definitions. The concrete
|
||||
// type is one of the types below. Only one can be set.
|
||||
message Item {
|
||||
oneof value {
|
||||
Reference ref = 1;
|
||||
String str = 2;
|
||||
RawString raw_str = 3;
|
||||
StyledString styled_str = 4;
|
||||
FileReference file = 5;
|
||||
Id id = 6;
|
||||
Primitive prim = 7;
|
||||
}
|
||||
}
|
||||
// A CompoundValue is an abstract type. It represents a value that is a made of other values.
|
||||
// These can only usually appear as top-level resources. The concrete type is one of the types
|
||||
// below. Only one can be set.
|
||||
message CompoundValue {
|
||||
oneof value {
|
||||
Attribute attr = 1;
|
||||
Style style = 2;
|
||||
Styleable styleable = 3;
|
||||
Array array = 4;
|
||||
Plural plural = 5;
|
||||
MacroBody macro = 6;
|
||||
}
|
||||
}
|
||||
// Message holding a boolean, so it can be optionally encoded.
|
||||
message Boolean {
|
||||
bool value = 1;
|
||||
}
|
||||
// A value that is a reference to another resource. This reference can be by name or resource ID.
|
||||
message Reference {
|
||||
enum Type {
|
||||
// A plain reference (@package:type/entry).
|
||||
REFERENCE = 0;
|
||||
// A reference to a theme attribute (?package:type/entry).
|
||||
ATTRIBUTE = 1;
|
||||
}
|
||||
Type type = 1;
|
||||
// The resource ID (0xPPTTEEEE) of the resource being referred. This is optional.
|
||||
uint32 id = 2;
|
||||
// The name of the resource being referred. This is optional if the resource ID is set.
|
||||
string name = 3;
|
||||
// Whether this reference is referencing a private resource (@*package:type/entry).
|
||||
bool private = 4;
|
||||
// Whether this reference is dynamic.
|
||||
Boolean is_dynamic = 5;
|
||||
// The type flags used when compiling the reference. Used for substituting the contents of macros.
|
||||
uint32 type_flags = 6;
|
||||
// Whether raw string values would have been accepted in place of this reference definition. Used
|
||||
// for substituting the contents of macros.
|
||||
bool allow_raw = 7;
|
||||
}
|
||||
// A value that represents an ID. This is just a placeholder, as ID values are used to occupy a
|
||||
// resource ID (0xPPTTEEEE) as a unique identifier. Their value is unimportant.
|
||||
message Id {
|
||||
}
|
||||
// A value that is a string.
|
||||
message String {
|
||||
string value = 1;
|
||||
}
|
||||
// A value that is a raw string, which is unescaped/uninterpreted. This is typically used to
|
||||
// represent the value of a style attribute before the attribute is compiled and the set of
|
||||
// allowed values is known.
|
||||
message RawString {
|
||||
string value = 1;
|
||||
}
|
||||
// A string with styling information, like html tags that specify boldness, italics, etc.
|
||||
message StyledString {
|
||||
// The raw text of the string.
|
||||
string value = 1;
|
||||
// A Span marks a region of the string text that is styled.
|
||||
message Span {
|
||||
// The name of the tag, and its attributes, encoded as follows:
|
||||
// tag_name;attr1=value1;attr2=value2;[...]
|
||||
string tag = 1;
|
||||
// The first character position this span applies to, in UTF-16 offset.
|
||||
uint32 first_char = 2;
|
||||
// The last character position this span applies to, in UTF-16 offset.
|
||||
uint32 last_char = 3;
|
||||
}
|
||||
repeated Span span = 2;
|
||||
}
|
||||
// A value that is a reference to an external entity, like an XML file or a PNG.
|
||||
message FileReference {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
PNG = 1;
|
||||
BINARY_XML = 2;
|
||||
PROTO_XML = 3;
|
||||
}
|
||||
// Path to a file within the APK (typically res/type-config/entry.ext).
|
||||
string path = 1;
|
||||
// The type of file this path points to. For UAM bundle, this cannot be
|
||||
// BINARY_XML.
|
||||
Type type = 2;
|
||||
}
|
||||
// A value that represents a primitive data type (float, int, boolean, etc.).
|
||||
// Refer to Res_value in ResourceTypes.h for info on types and formatting
|
||||
message Primitive {
|
||||
message NullType {
|
||||
}
|
||||
message EmptyType {
|
||||
}
|
||||
oneof oneof_value {
|
||||
NullType null_value = 1;
|
||||
EmptyType empty_value = 2;
|
||||
float float_value = 3;
|
||||
uint32 dimension_value = 13;
|
||||
uint32 fraction_value = 14;
|
||||
int32 int_decimal_value = 6;
|
||||
uint32 int_hexadecimal_value = 7;
|
||||
bool boolean_value = 8;
|
||||
uint32 color_argb8_value = 9;
|
||||
uint32 color_rgb8_value = 10;
|
||||
uint32 color_argb4_value = 11;
|
||||
uint32 color_rgb4_value = 12;
|
||||
float dimension_value_deprecated = 4 [deprecated=true];
|
||||
float fraction_value_deprecated = 5 [deprecated=true];
|
||||
}
|
||||
}
|
||||
// A value that represents an XML attribute and what values it accepts.
|
||||
message Attribute {
|
||||
// A Symbol used to represent an enum or a flag.
|
||||
message Symbol {
|
||||
// Where the enum/flag item was defined.
|
||||
Source source = 1;
|
||||
// Any comments associated with the enum or flag.
|
||||
string comment = 2;
|
||||
// The name of the enum/flag as a reference. Enums/flag items are generated as ID resource
|
||||
// values.
|
||||
Reference name = 3;
|
||||
// The value of the enum/flag.
|
||||
uint32 value = 4;
|
||||
// The data type of the enum/flag as defined in android::Res_value.
|
||||
uint32 type = 5;
|
||||
}
|
||||
// Bitmask of formats allowed for an attribute.
|
||||
enum FormatFlags {
|
||||
NONE = 0x0; // Proto3 requires a default of 0.
|
||||
ANY = 0x0000ffff; // Allows any type except ENUM and FLAGS.
|
||||
REFERENCE = 0x01; // Allows Reference values.
|
||||
STRING = 0x02; // Allows String/StyledString values.
|
||||
INTEGER = 0x04; // Allows any integer BinaryPrimitive values.
|
||||
BOOLEAN = 0x08; // Allows any boolean BinaryPrimitive values.
|
||||
COLOR = 0x010; // Allows any color BinaryPrimitive values.
|
||||
FLOAT = 0x020; // Allows any float BinaryPrimitive values.
|
||||
DIMENSION = 0x040; // Allows any dimension BinaryPrimitive values.
|
||||
FRACTION = 0x080; // Allows any fraction BinaryPrimitive values.
|
||||
ENUM = 0x00010000; // Allows enums that are defined in the Attribute's symbols.
|
||||
// ENUM and FLAGS cannot BOTH be set.
|
||||
FLAGS = 0x00020000; // Allows flags that are defined in the Attribute's symbols.
|
||||
// ENUM and FLAGS cannot BOTH be set.
|
||||
}
|
||||
// A bitmask of types that this XML attribute accepts. Corresponds to the flags in the
|
||||
// enum FormatFlags.
|
||||
uint32 format_flags = 1;
|
||||
// The smallest integer allowed for this XML attribute. Only makes sense if the format includes
|
||||
// FormatFlags::INTEGER.
|
||||
int32 min_int = 2;
|
||||
// The largest integer allowed for this XML attribute. Only makes sense if the format includes
|
||||
// FormatFlags::INTEGER.
|
||||
int32 max_int = 3;
|
||||
// The set of enums/flags defined in this attribute. Only makes sense if the format includes
|
||||
// either FormatFlags::ENUM or FormatFlags::FLAGS. Having both is an error.
|
||||
repeated Symbol symbol = 4;
|
||||
}
|
||||
// A value that represents a style.
|
||||
message Style {
|
||||
// An XML attribute/value pair defined in the style.
|
||||
message Entry {
|
||||
// Where the entry was defined.
|
||||
Source source = 1;
|
||||
// Any comments associated with the entry.
|
||||
string comment = 2;
|
||||
// A reference to the XML attribute.
|
||||
Reference key = 3;
|
||||
// The Item defined for this XML attribute.
|
||||
Item item = 4;
|
||||
}
|
||||
// The optinal style from which this style inherits attributes.
|
||||
Reference parent = 1;
|
||||
// The source file information of the parent inheritance declaration.
|
||||
Source parent_source = 2;
|
||||
// The set of XML attribute/value pairs for this style.
|
||||
repeated Entry entry = 3;
|
||||
}
|
||||
// A value that represents a <declare-styleable> XML resource. These are not real resources and
|
||||
// only end up as Java fields in the generated R.java. They do not end up in the binary ARSC file.
|
||||
message Styleable {
|
||||
// An attribute defined for this styleable.
|
||||
message Entry {
|
||||
// Where the attribute was defined within the <declare-styleable> block.
|
||||
Source source = 1;
|
||||
// Any comments associated with the declaration.
|
||||
string comment = 2;
|
||||
// The reference to the attribute.
|
||||
Reference attr = 3;
|
||||
}
|
||||
// The set of attribute declarations.
|
||||
repeated Entry entry = 1;
|
||||
}
|
||||
// A value that represents an array of resource values.
|
||||
message Array {
|
||||
// A single element of the array.
|
||||
message Element {
|
||||
// Where the element was defined.
|
||||
Source source = 1;
|
||||
// Any comments associated with the element.
|
||||
string comment = 2;
|
||||
// The value assigned to this element.
|
||||
Item item = 3;
|
||||
}
|
||||
// The list of array elements.
|
||||
repeated Element element = 1;
|
||||
}
|
||||
// A value that represents a string and its many variations based on plurality.
|
||||
message Plural {
|
||||
// The arity of the plural.
|
||||
enum Arity {
|
||||
ZERO = 0;
|
||||
ONE = 1;
|
||||
TWO = 2;
|
||||
FEW = 3;
|
||||
MANY = 4;
|
||||
OTHER = 5;
|
||||
}
|
||||
// The plural value for a given arity.
|
||||
message Entry {
|
||||
// Where the plural was defined.
|
||||
Source source = 1;
|
||||
// Any comments associated with the plural.
|
||||
string comment = 2;
|
||||
// The arity of the plural.
|
||||
Arity arity = 3;
|
||||
// The value assigned to this plural.
|
||||
Item item = 4;
|
||||
}
|
||||
// The set of arity/plural mappings.
|
||||
repeated Entry entry = 1;
|
||||
}
|
||||
// Defines an abstract XmlNode that must be either an XmlElement, or
|
||||
// a text node represented by a string.
|
||||
message XmlNode {
|
||||
oneof node {
|
||||
XmlElement element = 1;
|
||||
string text = 2;
|
||||
}
|
||||
// Source line and column info.
|
||||
SourcePosition source = 3;
|
||||
}
|
||||
// An <element> in an XML document.
|
||||
message XmlElement {
|
||||
// Namespaces defined on this element.
|
||||
repeated XmlNamespace namespace_declaration = 1;
|
||||
// The namespace URI of this element.
|
||||
string namespace_uri = 2;
|
||||
// The name of this element.
|
||||
string name = 3;
|
||||
// The attributes of this element.
|
||||
repeated XmlAttribute attribute = 4;
|
||||
// The children of this element.
|
||||
repeated XmlNode child = 5;
|
||||
}
|
||||
// A namespace declaration on an XmlElement (xmlns:android="http://...").
|
||||
message XmlNamespace {
|
||||
string prefix = 1;
|
||||
string uri = 2;
|
||||
// Source line and column info.
|
||||
SourcePosition source = 3;
|
||||
}
|
||||
// An attribute defined on an XmlElement (android:text="...").
|
||||
message XmlAttribute {
|
||||
string namespace_uri = 1;
|
||||
string name = 2;
|
||||
string value = 3;
|
||||
// Source line and column info.
|
||||
SourcePosition source = 4;
|
||||
// The optional resource ID (0xPPTTEEEE) of the attribute.
|
||||
uint32 resource_id = 5;
|
||||
// The optional interpreted/compiled version of the `value` string.
|
||||
Item compiled_item = 6;
|
||||
}
|
||||
message MacroBody {
|
||||
string raw_string = 1;
|
||||
StyleString style_string = 2;
|
||||
repeated UntranslatableSection untranslatable_sections = 3;
|
||||
repeated NamespaceAlias namespace_stack = 4;
|
||||
SourcePosition source = 5;
|
||||
}
|
||||
message NamespaceAlias {
|
||||
string prefix = 1;
|
||||
string package_name = 2;
|
||||
bool is_private = 3;
|
||||
}
|
||||
message StyleString {
|
||||
message Span {
|
||||
string name = 1;
|
||||
uint32 start_index = 2;
|
||||
uint32 end_index = 3;
|
||||
}
|
||||
string str = 1;
|
||||
repeated Span spans = 2;
|
||||
}
|
||||
message UntranslatableSection {
|
||||
uint64 start_index = 1;
|
||||
uint64 end_index = 2;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
syntax = "proto3";
|
||||
|
||||
import "com/android/aapt/Configuration.proto";
|
||||
import "com/android/aapt/Resources.proto";
|
||||
|
||||
// package aapt.pb.internal;
|
||||
|
||||
option java_package = "android.aapt.pb.internal";
|
||||
|
||||
// The top level message representing an external resource file (layout XML, PNG, etc).
|
||||
// This is used to represent a compiled file before it is linked. Only useful to aapt2.
|
||||
message CompiledFile {
|
||||
message Symbol {
|
||||
// The name of the symbol (in the form package:type/name).
|
||||
string resource_name = 1;
|
||||
// The position in the file at which this symbol is defined. For debug use.
|
||||
SourcePosition source = 2;
|
||||
}
|
||||
// The name of the resource (in the form package:type/name).
|
||||
string resource_name = 1;
|
||||
// The configuration for which the resource is defined.
|
||||
Configuration config = 2;
|
||||
// The type of the file.
|
||||
FileReference.Type type = 3;
|
||||
// The filesystem path to where the source file originated.
|
||||
// Mainly used to display helpful error messages.
|
||||
string source_path = 4;
|
||||
// Any symbols this file auto-generates/exports (eg. @+id/foo in an XML file).
|
||||
repeated Symbol exported_symbol = 5;
|
||||
}
|
||||
Reference in New Issue
Block a user