mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
fix(xml): extract API classes from aaptcompiler to :xml:resources-api
This commit is contained in:
Generated
+1
@@ -271,6 +271,7 @@
|
||||
<module name="AndroidIDE.treeview" target="17" />
|
||||
<module name="AndroidIDE.uidesigner" target="17" />
|
||||
<module name="AndroidIDE.xml-inflater" target="17" />
|
||||
<module name="AndroidIDE.xml.resources-api.test" target="11" />
|
||||
<module name="ATS.android-tree-sitter" target="17" />
|
||||
<module name="ATS.app" target="17" />
|
||||
<module name="ATS.tree-sitter-aidl" target="17" />
|
||||
|
||||
+17
-14
@@ -19,7 +19,6 @@ package com.itsaky.androidide.projects.android
|
||||
|
||||
import com.android.SdkConstants
|
||||
import com.android.aaptcompiler.AaptResourceType
|
||||
import com.android.aaptcompiler.ResourceTable
|
||||
import com.android.builder.model.v2.ide.LibraryType.ANDROID_LIBRARY
|
||||
import com.android.builder.model.v2.ide.LibraryType.JAVA_LIBRARY
|
||||
import com.android.builder.model.v2.ide.LibraryType.PROJECT
|
||||
@@ -38,6 +37,7 @@ import com.itsaky.androidide.tooling.api.models.BasicAndroidVariantMetadata
|
||||
import com.itsaky.androidide.tooling.api.models.GradleTask
|
||||
import com.itsaky.androidide.tooling.api.util.findPackageName
|
||||
import com.itsaky.androidide.utils.withStopWatch
|
||||
import com.itsaky.androidide.xml.res.IResourceTable
|
||||
import com.itsaky.androidide.xml.resources.ResourceTableRegistry
|
||||
import com.itsaky.androidide.xml.versions.ApiVersions
|
||||
import com.itsaky.androidide.xml.versions.ApiVersionsRegistry
|
||||
@@ -314,7 +314,7 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
|
||||
}
|
||||
|
||||
/** Get the resource table for this module i.e. without resource tables for dependent modules. */
|
||||
fun getResourceTable(): ResourceTable? {
|
||||
fun getResourceTable(): IResourceTable? {
|
||||
val namespace = this.namespace ?: return null
|
||||
|
||||
val resDirs = mainSourceSet?.sourceProvider?.resDirectories ?: return null
|
||||
@@ -336,11 +336,11 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the [ResourceTable] instance for this module's compile SDK.
|
||||
* Get the [IResourceTable] instance for this module's compile SDK.
|
||||
*
|
||||
* @return The [ApiVersions] for this module.
|
||||
*/
|
||||
fun getFrameworkResourceTable(): ResourceTable? {
|
||||
fun getFrameworkResourceTable(): IResourceTable? {
|
||||
val platformDir = getPlatformDir()
|
||||
if (platformDir != null) {
|
||||
return ResourceTableRegistry.getInstance().forPlatformDir(platformDir)
|
||||
@@ -354,7 +354,7 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
|
||||
*
|
||||
* @return The set of resource tables. Empty when project is not initalized.
|
||||
*/
|
||||
fun getSourceResourceTables(): Set<ResourceTable> {
|
||||
fun getSourceResourceTables(): Set<IResourceTable> {
|
||||
val set = mutableSetOf(getResourceTable() ?: return emptySet())
|
||||
getCompileModuleProjects().filterIsInstance<AndroidModule>().forEach {
|
||||
it.getResourceTable()?.also { table -> set.add(table) }
|
||||
@@ -363,8 +363,8 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
|
||||
}
|
||||
|
||||
/** Get the resource tables for external dependencies (not local module project dependencies). */
|
||||
fun getDependencyResourceTables(): Set<ResourceTable> {
|
||||
return mutableSetOf<ResourceTable>().also {
|
||||
fun getDependencyResourceTables(): Set<IResourceTable> {
|
||||
return mutableSetOf<IResourceTable>().also {
|
||||
var deps: Int
|
||||
it.addAll(libraryMap.values.filter { library ->
|
||||
library.type == ANDROID_LIBRARY && library.androidLibraryData!!.resFolder.exists() && library.findPackageName() != UNKNOWN_PACKAGE
|
||||
@@ -390,7 +390,10 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
|
||||
*
|
||||
* @param pck The package to look for.
|
||||
*/
|
||||
fun findResourceTableForPackage(pck: String, hasGroup: AaptResourceType? = null): ResourceTable? {
|
||||
fun findResourceTableForPackage(
|
||||
pck: String,
|
||||
hasGroup: AaptResourceType? = null
|
||||
): IResourceTable? {
|
||||
return findAllResourceTableForPackage(pck, hasGroup).let {
|
||||
if (it.isNotEmpty()) {
|
||||
return it.first()
|
||||
@@ -406,18 +409,18 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
|
||||
*/
|
||||
fun findAllResourceTableForPackage(
|
||||
pck: String, hasGroup: AaptResourceType? = null
|
||||
): List<ResourceTable> {
|
||||
): List<IResourceTable> {
|
||||
if (pck == SdkConstants.ANDROID_PKG) {
|
||||
return getFrameworkResourceTable()?.let { listOf(it) } ?: emptyList()
|
||||
}
|
||||
|
||||
val tables: List<ResourceTable> = mutableListOf<ResourceTable>().apply {
|
||||
val tables: List<IResourceTable> = mutableListOf<IResourceTable>().apply {
|
||||
getResourceTable()?.let { add(it) }
|
||||
addAll(getSourceResourceTables())
|
||||
addAll(getDependencyResourceTables())
|
||||
}
|
||||
|
||||
val result = mutableListOf<ResourceTable>()
|
||||
val result = mutableListOf<IResourceTable>()
|
||||
for (table in tables) {
|
||||
val resPck = table.findPackage(pck) ?: continue
|
||||
if (hasGroup == null) {
|
||||
@@ -439,8 +442,8 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
|
||||
*
|
||||
* @return The associated resource tables.
|
||||
*/
|
||||
fun getAllResourceTables(): Set<ResourceTable> {
|
||||
return mutableSetOf<ResourceTable>().apply {
|
||||
fun getAllResourceTables(): Set<IResourceTable> {
|
||||
return mutableSetOf<IResourceTable>().apply {
|
||||
getResourceTable()?.let { add(it) }
|
||||
getFrameworkResourceTable()?.let { add(it) }
|
||||
addAll(getSourceResourceTables())
|
||||
@@ -449,7 +452,7 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
|
||||
}
|
||||
|
||||
/** Get the resource table for the attrs_manifest.xml file. */
|
||||
fun getManifestAttrTable(): ResourceTable? {
|
||||
fun getManifestAttrTable(): IResourceTable? {
|
||||
val platform = getPlatformDir() ?: return null
|
||||
return ResourceTableRegistry.getInstance().getManifestAttrTable(platform)
|
||||
}
|
||||
|
||||
@@ -177,6 +177,7 @@ include(
|
||||
":xml:aaptcompiler",
|
||||
":xml:dom",
|
||||
":xml:lsp",
|
||||
":xml:resources-api",
|
||||
":xml:utils",
|
||||
)
|
||||
|
||||
|
||||
@@ -25,8 +25,9 @@ plugins {
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation(libs.androidx.annotation)
|
||||
implementation(libs.androidx.collection)
|
||||
api(libs.androidx.annotation)
|
||||
api(libs.androidx.collection)
|
||||
|
||||
implementation(libs.google.guava)
|
||||
implementation(libs.google.gson)
|
||||
|
||||
|
||||
+22
-19
@@ -60,6 +60,9 @@ import com.android.aaptcompiler.tryParseInt
|
||||
import com.android.aaptcompiler.tryParseReference
|
||||
import com.itsaky.androidide.inflater.drawable.DrawableParserFactory
|
||||
import com.itsaky.androidide.inflater.utils.module
|
||||
import com.itsaky.androidide.xml.res.IResourceEntry
|
||||
import com.itsaky.androidide.xml.res.IResourceTable
|
||||
import com.itsaky.androidide.xml.res.IResourceTablePackage
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
@@ -72,16 +75,16 @@ private const val DEFAULT_STRING_VALUE = "AndroidIDE"
|
||||
private val stringResolver =
|
||||
fun(it: Value?): String? {
|
||||
return when (it) {
|
||||
is BasicString -> it.ref.value()
|
||||
is RawString -> it.value.value()
|
||||
is StyledString -> it.ref.value()
|
||||
is com.android.aaptcompiler.BasicString -> it.ref.value()
|
||||
is com.android.aaptcompiler.RawString -> it.value.value()
|
||||
is com.android.aaptcompiler.StyledString -> it.ref.value()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private val intResolver =
|
||||
fun(it: Value?): Int? {
|
||||
return if (it is BinaryPrimitive) {
|
||||
return if (it is com.android.aaptcompiler.BinaryPrimitive) {
|
||||
it.resValue.data
|
||||
} else null
|
||||
}
|
||||
@@ -89,14 +92,14 @@ private val intResolver =
|
||||
val colorResolver: (Value?) -> Int? =
|
||||
fun(it): Int? {
|
||||
// TODO(itsaky) : Implement color state list parser
|
||||
if (it is BinaryPrimitive) {
|
||||
if (it is com.android.aaptcompiler.BinaryPrimitive) {
|
||||
return it.resValue.data
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
inline fun <reified T> ((Value?) -> T?).arrayResolver(value: Value?): Array<T>? {
|
||||
return if (value is ArrayResource) {
|
||||
return if (value is com.android.aaptcompiler.ArrayResource) {
|
||||
Array(value.elements.size) { invoke(value.elements[it]) ?: return null }
|
||||
} else emptyArray()
|
||||
}
|
||||
@@ -151,7 +154,7 @@ fun parseInteger(value: String, def: Int = 0): Int {
|
||||
return def
|
||||
}
|
||||
if (value.isDigitsOnly()) {
|
||||
tryParseInt(value)?.resValue?.apply {
|
||||
com.android.aaptcompiler.tryParseInt(value)?.resValue?.apply {
|
||||
return data
|
||||
}
|
||||
}
|
||||
@@ -169,14 +172,14 @@ fun parseBoolean(value: String, def: Boolean = false): Boolean {
|
||||
return def
|
||||
}
|
||||
|
||||
tryParseBool(value)?.resValue?.apply {
|
||||
com.android.aaptcompiler.tryParseBool(value)?.resValue?.apply {
|
||||
return data == -1
|
||||
}
|
||||
|
||||
if (value[0] == '@') {
|
||||
val resolver: (Value?) -> Boolean? =
|
||||
fun(resValue): Boolean {
|
||||
return if (resValue is BinaryPrimitive) {
|
||||
return if (resValue is com.android.aaptcompiler.BinaryPrimitive) {
|
||||
resValue.resValue.data == -1
|
||||
} else def
|
||||
}
|
||||
@@ -190,7 +193,7 @@ fun parseBoolean(value: String, def: Boolean = false): Boolean {
|
||||
fun parseDrawable(context: Context, value: String, def: Drawable = unknownDrawable()): Drawable {
|
||||
val drawableResolver: (Value?) -> Drawable? =
|
||||
fun(it): Drawable? {
|
||||
if (it is FileReference) {
|
||||
if (it is com.android.aaptcompiler.FileReference) {
|
||||
val file = File(it.path.value())
|
||||
if (!file.exists() || file.extension != EXT_XML) {
|
||||
return null
|
||||
@@ -229,7 +232,7 @@ fun parseLayoutReference(value: String): File? {
|
||||
|
||||
val layoutResolver: (Value?) -> File? =
|
||||
fun(it): File? {
|
||||
return if (it is FileReference) {
|
||||
return if (it is com.android.aaptcompiler.FileReference) {
|
||||
File(it.source.path)
|
||||
} else null
|
||||
}
|
||||
@@ -310,7 +313,7 @@ fun parseDimension(
|
||||
return complexToDimension(data, displayMetrics)
|
||||
} else if (c == '@') {
|
||||
val resolver: (Value?) -> Float? = {
|
||||
if (it is BinaryPrimitive) {
|
||||
if (it is com.android.aaptcompiler.BinaryPrimitive) {
|
||||
complexToDimension(it.resValue.data, displayMetrics)
|
||||
} else null
|
||||
}
|
||||
@@ -357,8 +360,8 @@ fun parseGravity(value: String, def: Int = defaultGravity()): Int {
|
||||
return parseFlag(attr = attr, value = value, def = def)
|
||||
}
|
||||
|
||||
fun parseFlag(attr: AttributeResource, value: String, def: Int = -1): Int {
|
||||
return tryParseFlagSymbol(attr, value)?.resValue?.data ?: def
|
||||
fun parseFlag(attr: com.android.aaptcompiler.AttributeResource, value: String, def: Int = -1): Int {
|
||||
return com.android.aaptcompiler.tryParseFlagSymbol(attr, value)?.resValue?.data ?: def
|
||||
}
|
||||
|
||||
fun defaultGravity(): Int {
|
||||
@@ -441,7 +444,7 @@ fun <T> resolveQualifiedResourceReference(
|
||||
}
|
||||
|
||||
fun <T> resolveResourceReference(
|
||||
table: ResourceTable,
|
||||
table: IResourceTable,
|
||||
type: AaptResourceType,
|
||||
pck: String,
|
||||
name: String,
|
||||
@@ -449,7 +452,7 @@ fun <T> resolveResourceReference(
|
||||
resolver: (Value?) -> T?
|
||||
): T {
|
||||
val result =
|
||||
table.findResource(ResourceName(pck = pck, type = type, entry = name))
|
||||
table.findResource(com.android.aaptcompiler.ResourceName(pck = pck, type = type, entry = name))
|
||||
?: run { throw IllegalArgumentException("$type resource '$name' not found") }
|
||||
return resolveResourceReference(
|
||||
table,
|
||||
@@ -463,9 +466,9 @@ fun <T> resolveResourceReference(
|
||||
}
|
||||
|
||||
fun <T> resolveResourceReference(
|
||||
table: ResourceTable,
|
||||
pck: ResourceTablePackage,
|
||||
entry: ResourceEntry,
|
||||
table: IResourceTable,
|
||||
pck: IResourceTablePackage,
|
||||
entry: IResourceEntry,
|
||||
type: AaptResourceType,
|
||||
name: String,
|
||||
def: T,
|
||||
|
||||
+13
-13
@@ -21,21 +21,21 @@ import com.android.SdkConstants
|
||||
import com.android.aaptcompiler.AaptResourceType
|
||||
import com.android.aaptcompiler.AttributeResource
|
||||
import com.android.aaptcompiler.ConfigDescription
|
||||
import com.android.aaptcompiler.ResourceEntry
|
||||
import com.android.aaptcompiler.ResourceGroup
|
||||
import com.android.aaptcompiler.ResourceName
|
||||
import com.android.aaptcompiler.ResourceTable
|
||||
import com.android.aaptcompiler.ResourceTablePackage
|
||||
import com.itsaky.androidide.inflater.utils.module
|
||||
import com.itsaky.androidide.xml.res.IResourceEntry
|
||||
import com.itsaky.androidide.xml.res.IResourceGroup
|
||||
import com.itsaky.androidide.xml.res.IResourceTable
|
||||
import com.itsaky.androidide.xml.res.IResourceTablePackage
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
private val log = LoggerFactory.getLogger("ParseLookupUtils")
|
||||
|
||||
internal data class LookupResult(
|
||||
val table: ResourceTable,
|
||||
val group: ResourceGroup,
|
||||
val pack: ResourceTablePackage,
|
||||
val entry: ResourceEntry
|
||||
val table: IResourceTable,
|
||||
val group: IResourceGroup,
|
||||
val pack: IResourceTablePackage,
|
||||
val entry: IResourceEntry
|
||||
)
|
||||
|
||||
internal fun lookupUnqualifedResource(
|
||||
@@ -57,10 +57,10 @@ internal fun lookupUnqualifedResource(
|
||||
}
|
||||
|
||||
internal fun findUnqualifiedResourceEntry(type: AaptResourceType, name: String): LookupResult? {
|
||||
var resTable: ResourceTable? = null
|
||||
var resGrp: ResourceGroup? = null
|
||||
var resPck: ResourceTablePackage? = null
|
||||
var resEntry: ResourceEntry? = null
|
||||
var resTable: IResourceTable? = null
|
||||
var resGrp: IResourceGroup? = null
|
||||
var resPck: IResourceTablePackage? = null
|
||||
var resEntry: IResourceEntry? = null
|
||||
for (t in module.getAllResourceTables()) {
|
||||
val entries =
|
||||
t.packages.mapNotNull {
|
||||
@@ -93,7 +93,7 @@ internal fun findQualifedResourceEntry(
|
||||
pack: String,
|
||||
type: AaptResourceType,
|
||||
name: String
|
||||
): ResourceEntry? {
|
||||
): IResourceEntry? {
|
||||
return module
|
||||
.findResourceTableForPackage(pack, type)
|
||||
?.findResource(ResourceName(pack, type, name))
|
||||
|
||||
+4
-7
@@ -18,10 +18,7 @@
|
||||
package com.itsaky.androidide.inflater.utils
|
||||
|
||||
import com.android.aaptcompiler.AaptResourceType
|
||||
import com.android.aaptcompiler.BlameLogger
|
||||
import com.android.aaptcompiler.ResourceFile
|
||||
import com.android.aaptcompiler.ResourceFile.Type.ProtoXml
|
||||
import com.android.aaptcompiler.ResourceName
|
||||
import com.android.aaptcompiler.XmlProcessor
|
||||
import com.android.aaptcompiler.extractPathData
|
||||
import com.itsaky.androidide.aapt.logging.IDELogger
|
||||
@@ -86,7 +83,7 @@ fun newAttribute(
|
||||
* @return The pair of [XmlProcessor] (processed) instance and the [AndroidModule] instance for the
|
||||
* given file.
|
||||
*/
|
||||
fun processXmlFile(file: File, expectedType: AaptResourceType): Pair<XmlProcessor, AndroidModule> {
|
||||
fun processXmlFile(file: File, expectedType: com.android.aaptcompiler.AaptResourceType): Pair<XmlProcessor, AndroidModule> {
|
||||
val pathData = extractPathData(file)
|
||||
if (pathData.type != expectedType) {
|
||||
throw InflateException("File is not a layout file.")
|
||||
@@ -100,14 +97,14 @@ fun processXmlFile(file: File, expectedType: AaptResourceType): Pair<XmlProcesso
|
||||
IProjectManager.getInstance().getWorkspace()?.findModuleForFile(file, false) as? AndroidModule
|
||||
?: throw InflateException("Cannot find module for given file. Is the project initialized?")
|
||||
val resFile =
|
||||
ResourceFile(
|
||||
ResourceName(module.namespace, pathData.type!!, pathData.name),
|
||||
com.android.aaptcompiler.ResourceFile(
|
||||
com.android.aaptcompiler.ResourceName(module.namespace, pathData.type!!, pathData.name),
|
||||
pathData.config,
|
||||
pathData.source,
|
||||
ProtoXml
|
||||
)
|
||||
|
||||
val processor = XmlProcessor(pathData.source, BlameLogger(IDELogger))
|
||||
val processor = XmlProcessor(pathData.source, com.android.aaptcompiler.BlameLogger(IDELogger))
|
||||
processor.process(resFile, file.inputStream())
|
||||
return processor to module
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# aaptcompiler
|
||||
|
||||
This module has been adapted
|
||||
from [Android Studio sources](https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:build-system/aaptcompiler/;l=1?q=aaptcompiler&sq=).
|
||||
|
||||
## Modifications
|
||||
|
||||
Some of the classes/files have been moved to the `:xml:resources-api` module. Also, interfaces have been introduced
|
||||
in order to provide a more generic API for accessing module resources.
|
||||
@@ -22,11 +22,8 @@ import com.itsaky.androidide.build.config.BuildConfig
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("kotlin-android")
|
||||
id("com.google.protobuf")
|
||||
}
|
||||
|
||||
|
||||
|
||||
android {
|
||||
namespace = "${BuildConfig.packageName}.aaptcompiler"
|
||||
|
||||
@@ -37,22 +34,6 @@ 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)
|
||||
@@ -61,6 +42,8 @@ dependencies {
|
||||
implementation(projects.logging.logger)
|
||||
implementation(projects.utilities.shared)
|
||||
|
||||
api(projects.xml.resourcesApi)
|
||||
|
||||
api(libs.aapt2.annotations)
|
||||
api(libs.aapt2.common)
|
||||
api(libs.google.protobuf)
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
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"
|
||||
private const val ATTR_TAG = "attr"
|
||||
private const val ATTR_PRIVATE_TAG = "^attr-private"
|
||||
private const val BOOL_TAG = "bool"
|
||||
private const val COLOR_TAG = "color"
|
||||
private const val CONFIG_VARYING_TAG = "configVarying"
|
||||
private const val DIMEN_TAG = "dimen"
|
||||
private const val DRAWABLE_TAG = "drawable"
|
||||
private const val FONT_TAG = "font"
|
||||
private const val FRACTION_TAG = "fraction"
|
||||
private const val ID_TAG = "id"
|
||||
private const val INTEGER_TAG = "integer"
|
||||
private const val INTERPOLATOR_TAG = "interpolator"
|
||||
private const val LAYOUT_TAG = "layout"
|
||||
private const val MACRO_TAG = "macro"
|
||||
private const val MENU_TAG = "menu"
|
||||
private const val MIPMAP_TAG = "mipmap"
|
||||
private const val NAVIGATION_TAG = "navigation"
|
||||
private const val PLURALS_TAG = "plurals"
|
||||
private const val RAW_TAG = "raw"
|
||||
private const val STRING_TAG = "string"
|
||||
private const val STYLE_TAG = "style"
|
||||
private const val STYLEABLE_TAG = "styleable"
|
||||
private const val TRANSITION_TAG = "transition"
|
||||
private const val XML_TAG = "xml"
|
||||
|
||||
fun resourceTypeFromTag(tag: String) =
|
||||
when(tag) {
|
||||
ANIM_TAG -> AaptResourceType.ANIM
|
||||
ANIMATOR_TAG -> AaptResourceType.ANIMATOR
|
||||
ARRAY_TAG -> AaptResourceType.ARRAY
|
||||
ATTR_TAG -> AaptResourceType.ATTR
|
||||
ATTR_PRIVATE_TAG -> AaptResourceType.ATTR_PRIVATE
|
||||
BOOL_TAG -> AaptResourceType.BOOL
|
||||
COLOR_TAG -> AaptResourceType.COLOR
|
||||
CONFIG_VARYING_TAG -> AaptResourceType.CONFIG_VARYING
|
||||
DIMEN_TAG -> AaptResourceType.DIMEN
|
||||
DRAWABLE_TAG -> AaptResourceType.DRAWABLE
|
||||
FONT_TAG -> AaptResourceType.FONT
|
||||
FRACTION_TAG -> AaptResourceType.FRACTION
|
||||
ID_TAG -> AaptResourceType.ID
|
||||
INTEGER_TAG -> AaptResourceType.INTEGER
|
||||
INTERPOLATOR_TAG -> AaptResourceType.INTERPOLATOR
|
||||
LAYOUT_TAG -> AaptResourceType.LAYOUT
|
||||
MACRO_TAG -> AaptResourceType.MACRO
|
||||
MENU_TAG -> AaptResourceType.MENU
|
||||
MIPMAP_TAG -> AaptResourceType.MIPMAP
|
||||
NAVIGATION_TAG -> AaptResourceType.NAVIGATION
|
||||
PLURALS_TAG -> AaptResourceType.PLURALS
|
||||
RAW_TAG -> AaptResourceType.RAW
|
||||
STRING_TAG -> AaptResourceType.STRING
|
||||
STYLE_TAG -> AaptResourceType.STYLE
|
||||
STYLEABLE_TAG -> AaptResourceType.STYLEABLE
|
||||
TRANSITION_TAG -> AaptResourceType.TRANSITION
|
||||
XML_TAG -> AaptResourceType.XML
|
||||
else -> null
|
||||
}
|
||||
|
||||
enum class AaptResourceType(val tagName: String) {
|
||||
ANIM(ANIM_TAG),
|
||||
ANIMATOR(ANIMATOR_TAG),
|
||||
ARRAY(ARRAY_TAG),
|
||||
ATTR(ATTR_TAG),
|
||||
ATTR_PRIVATE(ATTR_PRIVATE_TAG),
|
||||
BOOL(BOOL_TAG),
|
||||
COLOR(COLOR_TAG),
|
||||
CONFIG_VARYING(CONFIG_VARYING_TAG),
|
||||
DIMEN(DIMEN_TAG),
|
||||
DRAWABLE(DRAWABLE_TAG),
|
||||
FONT(FONT_TAG),
|
||||
FRACTION(FRACTION_TAG),
|
||||
ID(ID_TAG),
|
||||
INTEGER(INTEGER_TAG),
|
||||
INTERPOLATOR(INTERPOLATOR_TAG),
|
||||
LAYOUT(LAYOUT_TAG),
|
||||
MACRO(MACRO_TAG),
|
||||
MENU(MENU_TAG),
|
||||
MIPMAP(MIPMAP_TAG),
|
||||
NAVIGATION(NAVIGATION_TAG),
|
||||
PLURALS(PLURALS_TAG),
|
||||
RAW(RAW_TAG),
|
||||
STRING(STRING_TAG),
|
||||
STYLE(STYLE_TAG),
|
||||
STYLEABLE(STYLEABLE_TAG),
|
||||
TRANSITION(TRANSITION_TAG),
|
||||
UNKNOWN(""),
|
||||
XML(XML_TAG)
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.
|
||||
*/
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aaptcompiler.android.ResTableConfig
|
||||
|
||||
|
||||
class ConfigDescription(base: ResTableConfig = ResTableConfig()): ResTableConfig(base) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other is ConfigDescription) {
|
||||
return compareTo(other) == 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun compatible(first: Int, second: Int) = first == 0 || second == 0 || first == second
|
||||
}
|
||||
|
||||
const val WILDCARD_NAME: String = "any"
|
||||
|
||||
fun parse(config: String): ConfigDescription {
|
||||
val parts = config.split('-').map { it.lowercase()}
|
||||
var index = 0
|
||||
|
||||
val configDescription = ConfigDescription()
|
||||
val locale = LocaleValue()
|
||||
|
||||
if (parts.isEmpty() || config.isEmpty()) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
|
||||
if (parseMcc(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseMnc(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
// Locale spans a few '-' separators, so we let it control the index
|
||||
index += locale.initFromParts(parts, index)
|
||||
locale.writeTo(configDescription)
|
||||
if (index == parts.size) {
|
||||
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) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseSmallestScreenWidthDp(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseScreenWidthDp(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseScreenHeightDp(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseScreenLayoutSize(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseScreenLayoutLong(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseScreenRound(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseWideColorGamut(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseHdr(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseOrientation(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseUiModeType(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseUiModeNight(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseDensity(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseTouchscreen(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseKeysHidden(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseKeyboard(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseNavHidden(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseNavigation(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseScreenSize(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseVersion(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
throw error("Unrecognized part '${parts[index]}' in configuration $config")
|
||||
}
|
||||
|
||||
private fun applyVersionForCompatibility(config: ConfigDescription): ConfigDescription {
|
||||
val minSdk = when {
|
||||
config.uiModeType() == ResTableConfig.UI_MODE.TYPE_VR_HEADSET ||
|
||||
config.wideColorGamut() != ResTableConfig.COLOR_MODE.WIDE_GAMUT_ANY ||
|
||||
config.hdr() != ResTableConfig.COLOR_MODE.HDR_ANY -> SDKConstants.SDK_O
|
||||
config.layoutRound() != 0.toByte() -> SDKConstants.SDK_MARSHMALLOW
|
||||
config.density == ResTableConfig.DENSITY.ANY -> SDKConstants.SDK_LOLLIPOP
|
||||
config.smallestScreenWidthDp != 0 ||
|
||||
config.screenWidthDp != 0 ||
|
||||
config.screenHeightDp != 0-> SDKConstants.SDK_HONEYCOMB_MR2
|
||||
config.uiModeType() != ResTableConfig.UI_MODE.TYPE_ANY ||
|
||||
config.uiModeNight() != ResTableConfig.UI_MODE.NIGHT_ANY -> SDKConstants.SDK_FROYO
|
||||
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
|
||||
}
|
||||
|
||||
if (minSdk > config.sdkVersion) {
|
||||
config.sdkVersion = minSdk
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
@@ -46,7 +46,8 @@ internal fun mergeSpans(string: StyledString): List<UnifiedSpan> {
|
||||
}
|
||||
|
||||
internal fun pseudolocalizeStyledString(
|
||||
original: StyledString, method: Pseudolocalizer.Method, pool: StringPool): StyledString {
|
||||
original: StyledString, method: Pseudolocalizer.Method, pool: StringPool
|
||||
): StyledString {
|
||||
|
||||
val localizer = Pseudolocalizer(method)
|
||||
|
||||
@@ -136,7 +137,8 @@ internal fun pseudolocalizeStyledString(
|
||||
}
|
||||
|
||||
internal fun pseudolocalizeBasicString(
|
||||
original: BasicString, method: Pseudolocalizer.Method, pool: StringPool): BasicString {
|
||||
original: BasicString, method: Pseudolocalizer.Method, pool: StringPool
|
||||
): BasicString {
|
||||
try {
|
||||
val localizer = Pseudolocalizer(method)
|
||||
|
||||
@@ -170,7 +172,8 @@ internal fun pseudolocalizeBasicString(
|
||||
}
|
||||
|
||||
internal fun pseudolocalizePlural(
|
||||
original: Plural, method: Pseudolocalizer.Method, pool: StringPool): Plural {
|
||||
original: Plural, method: Pseudolocalizer.Method, pool: StringPool
|
||||
): Plural {
|
||||
|
||||
val localizedPlural = Plural()
|
||||
|
||||
|
||||
@@ -272,6 +272,7 @@ class PseudoMethodAccent: PseudoMethodImpl() {
|
||||
var currentChar = source[currentIndex]
|
||||
val htmlPartial = StringBuilder()
|
||||
|
||||
@Suppress("KotlinConstantConditions")
|
||||
htmlTag@ while (currentIndex < size) {
|
||||
|
||||
if (currentChar == '&') {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aaptcompiler.ResourceFile.Type.ProtoXml
|
||||
import com.android.aaptcompiler.ResourceFile.Type.Unknown
|
||||
import com.android.aaptcompiler.proto.serializeTableToPb
|
||||
import com.itsaky.androidide.layoutlib.resources.ResourceType
|
||||
import com.itsaky.androidide.layoutlib.resources.ResourceVisibility
|
||||
@@ -106,11 +108,12 @@ 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) {
|
||||
logger?.warning("Omitting file ${file.absolutePath} because it is hidden.")
|
||||
logger.warning("Omitting file ${file.absolutePath} because it is hidden.")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -122,7 +125,7 @@ fun compileResource(
|
||||
try {
|
||||
compileFunction(pathData, outputDirectory, options, logger)
|
||||
} catch (e: Exception) {
|
||||
logger?.info("Failed to compile file", blameSource(pathData.source))
|
||||
logger.info("Failed to compile file", blameSource(pathData.source))
|
||||
val message =
|
||||
"Resource compilation failed (${e.message}. Cause: ${e.cause}). " +
|
||||
"Check logs for more details."
|
||||
@@ -141,7 +144,7 @@ private fun getCompileMethod(pathData: ResourcePathData, logger: BlameLogger):
|
||||
if (type == null) {
|
||||
val errorMsg = "Invalid resource type '${pathData.resourceDirectory}'" +
|
||||
" for file ${pathData.file.absolutePath}"
|
||||
logger?.warning(errorMsg)
|
||||
logger.warning(errorMsg)
|
||||
error(errorMsg)
|
||||
}
|
||||
if (type != ResourceType.RAW) {
|
||||
@@ -170,9 +173,10 @@ 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")
|
||||
logger.info("Compiling XML table ${pathData.file.absolutePath} to $outputFile")
|
||||
|
||||
val table = ResourceTable(logger = logger)
|
||||
|
||||
@@ -221,14 +225,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.appendln("${visibility.getName()} $javaType ${group.type.tagName} ${entry.key}")
|
||||
builder.appendLine("${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 ""
|
||||
// styleables and their children are always public
|
||||
builder.appendln("public int styleable ${entry.key}${childPackage}_${it.name.entry}")
|
||||
builder.appendLine("public int styleable ${entry.key}${childPackage}_${it.name.entry}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,7 +279,7 @@ private fun compileFile(
|
||||
ResourceName("", resourceTypeFromTag(pathData.resourceDirectory)!!, pathData.name),
|
||||
pathData.config,
|
||||
pathData.source,
|
||||
ResourceFile.Type.Unknown
|
||||
Unknown
|
||||
)
|
||||
|
||||
val container = Container(outputFile.outputStream(), 1)
|
||||
@@ -317,7 +321,7 @@ private fun compileXml(
|
||||
ResourceName("", pathData.type!!, pathData.name),
|
||||
pathData.config,
|
||||
pathData.source,
|
||||
ResourceFile.Type.ProtoXml
|
||||
ProtoXml
|
||||
)
|
||||
|
||||
pathData.file.inputStream().use {
|
||||
@@ -341,9 +345,9 @@ private fun compileXml(
|
||||
|
||||
if (options.partialRFile != null) {
|
||||
val builder = StringBuilder()
|
||||
builder.appendln("default int ${pathData.type.tagName} ${pathData.name}")
|
||||
builder.appendLine("default int ${pathData.type!!.tagName} ${pathData.name}")
|
||||
fileToProcess.exportedSymbols.forEach { id ->
|
||||
builder.appendln("default int id ${id.name.entry}")
|
||||
builder.appendLine("default int id ${id.name.entry}")
|
||||
}
|
||||
FileUtils.writeToFile(options.partialRFile, builder.toString())
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@ package com.android.aaptcompiler
|
||||
import androidx.collection.mutableIntObjectMapOf
|
||||
import com.android.aapt.Resources
|
||||
import com.itsaky.androidide.layoutlib.resources.ResourceVisibility
|
||||
import com.itsaky.androidide.xml.res.IResourceEntry
|
||||
import com.itsaky.androidide.xml.res.IResourceGroup
|
||||
import com.itsaky.androidide.xml.res.IResourceTable
|
||||
import com.itsaky.androidide.xml.res.IResourceTablePackage
|
||||
import com.itsaky.androidide.xml.res.ISearchResult
|
||||
import java.io.File
|
||||
import java.util.SortedMap
|
||||
import java.util.TreeMap
|
||||
@@ -16,7 +21,8 @@ import java.util.TreeMap
|
||||
* names validated. While [addResourceMangled] and [addFileReferenceMangled] are used to add
|
||||
* resources from libraries and are not validated.
|
||||
*/
|
||||
class ResourceTable(val validateResources: Boolean = false, val logger: BlameLogger? = null) {
|
||||
class ResourceTable(val validateResources: Boolean = false, val logger: BlameLogger? = null) :
|
||||
IResourceTable {
|
||||
/**
|
||||
* The string pool used by this resource table. Values that reference strings must use
|
||||
* this pool to create their strings.
|
||||
@@ -24,7 +30,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
val stringPool = StringPool()
|
||||
|
||||
/** The list of packages in this table. */
|
||||
val packages = mutableListOf<ResourceTablePackage>()
|
||||
override val packages = mutableListOf<ResourceTablePackage>()
|
||||
|
||||
/**
|
||||
* Set of dynamic packages that this table may reference. Their package names get encoded into the
|
||||
@@ -39,7 +45,10 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
}
|
||||
|
||||
data class SearchResult(
|
||||
val tablePackage: ResourceTablePackage, val group: ResourceGroup, val entry: ResourceEntry)
|
||||
override val tablePackage: ResourceTablePackage,
|
||||
override val group: ResourceGroup,
|
||||
override val entry: ResourceEntry
|
||||
) : ISearchResult
|
||||
|
||||
/**
|
||||
* Adds a resource to the table with the given value.
|
||||
@@ -54,9 +63,11 @@ 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
|
||||
)
|
||||
|
||||
|
||||
/**
|
||||
@@ -77,9 +88,11 @@ 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.
|
||||
@@ -94,9 +107,11 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
* the table.
|
||||
*/
|
||||
fun addFileReference(
|
||||
name: ResourceName,config: ConfigDescription, source: Source, path: String): Boolean =
|
||||
name: ResourceName, config: ConfigDescription, source: Source, path: String
|
||||
): Boolean =
|
||||
addFileReferenceImpl(
|
||||
name, config, source, path, null, ::resourceNameValidator)
|
||||
name, config, source, path, null, ::resourceNameValidator
|
||||
)
|
||||
|
||||
/**
|
||||
* Same as [addFileReference], but doesn't verify the name of the file reference resource. This is
|
||||
@@ -118,7 +133,8 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
config: ConfigDescription,
|
||||
source: Source,
|
||||
path: String,
|
||||
file: File): Boolean =
|
||||
file: File
|
||||
): Boolean =
|
||||
addFileReferenceImpl(name, config, source, path, file, ::skipNameValidator)
|
||||
|
||||
/**
|
||||
@@ -134,9 +150,11 @@ 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 =
|
||||
name: ResourceName, config: ConfigDescription, product: String, value: Value
|
||||
): Boolean =
|
||||
addResourceImpl(
|
||||
name, 0, config, product, value, ::skipNameValidator, ::resolveValueCollision)
|
||||
name, 0, config, product, value, ::skipNameValidator, ::resolveValueCollision
|
||||
)
|
||||
|
||||
/**
|
||||
* Same as [addResourceWithId], but doesn't verify the name of the resource. This is used when
|
||||
@@ -157,9 +175,11 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
id: Int,
|
||||
config: ConfigDescription,
|
||||
product: String,
|
||||
value: Value) =
|
||||
value: Value
|
||||
) =
|
||||
addResourceImpl(
|
||||
name, id, config, product, value, ::skipNameValidator, ::resolveValueCollision)
|
||||
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
|
||||
@@ -194,7 +214,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
fun setOverlayableMangled(name: ResourceName, overlayable: OverlayableItem) =
|
||||
setOverlayableImpl(name, overlayable, ::skipNameValidator)
|
||||
|
||||
fun findResource(name: ResourceName): SearchResult? {
|
||||
override fun findResource(name: ResourceName): SearchResult? {
|
||||
val tablePackage = findPackage(name.pck!!)
|
||||
tablePackage ?: return null
|
||||
|
||||
@@ -216,7 +236,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
* @return the [ResourceTablePackage] with the requested name or {@code null} if that package
|
||||
* does not exist in the table.
|
||||
*/
|
||||
fun findPackage(name: String): ResourceTablePackage? {
|
||||
override fun findPackage(name: String): ResourceTablePackage? {
|
||||
return packages.find { it.name == name }
|
||||
}
|
||||
|
||||
@@ -233,6 +253,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
tablePackage.id = id
|
||||
return tablePackage
|
||||
}
|
||||
|
||||
tablePackage.id != id -> return null
|
||||
}
|
||||
}
|
||||
@@ -263,6 +284,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
packages.add(newPackage)
|
||||
newPackage
|
||||
}
|
||||
|
||||
else -> tablePackage
|
||||
}
|
||||
}
|
||||
@@ -286,13 +308,15 @@ 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
|
||||
@@ -305,7 +329,8 @@ 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
|
||||
|
||||
@@ -319,7 +344,8 @@ 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
|
||||
}
|
||||
|
||||
@@ -333,7 +359,8 @@ 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
|
||||
}
|
||||
|
||||
@@ -344,7 +371,8 @@ 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
|
||||
}
|
||||
|
||||
@@ -362,9 +390,11 @@ 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 -> {}
|
||||
}
|
||||
}
|
||||
@@ -384,19 +414,22 @@ 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
|
||||
@@ -408,7 +441,8 @@ 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
|
||||
}
|
||||
|
||||
@@ -422,7 +456,8 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog
|
||||
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
|
||||
}
|
||||
|
||||
@@ -433,7 +468,8 @@ 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
|
||||
}
|
||||
|
||||
@@ -453,22 +489,27 @@ 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
|
||||
@@ -479,7 +520,8 @@ 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
|
||||
}
|
||||
@@ -492,7 +534,8 @@ 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
|
||||
}
|
||||
@@ -508,7 +551,8 @@ 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
|
||||
@@ -565,17 +609,20 @@ 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)
|
||||
val comment: String
|
||||
)
|
||||
|
||||
class Overlayable(
|
||||
val name: String,
|
||||
val actor: String,
|
||||
val source: Source) {
|
||||
val source: Source
|
||||
) {
|
||||
|
||||
constructor() : this("", "", Source(""))
|
||||
|
||||
@@ -596,7 +643,8 @@ 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) {
|
||||
@@ -608,32 +656,40 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents all groups by type under a single package. */
|
||||
class ResourceTablePackage(var name: String = "", var id: Byte? = null) {
|
||||
class ResourceTablePackage(override var name: String = "", var id: Byte? = null) :
|
||||
IResourceTablePackage {
|
||||
|
||||
internal val groups = mutableListOf<ResourceGroup>()
|
||||
|
||||
fun findGroup(type: AaptResourceType, groupId: Byte? = null) =
|
||||
override fun findGroup(type: AaptResourceType, groupId: Byte?) =
|
||||
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 }
|
||||
}
|
||||
@@ -647,6 +703,7 @@ class ResourceTablePackage(var name: String = "", var id: Byte? = null) {
|
||||
groups.add(newGroup)
|
||||
newGroup
|
||||
}
|
||||
|
||||
else -> group
|
||||
}
|
||||
}
|
||||
@@ -656,7 +713,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) : IResourceGroup {
|
||||
var id: Byte? = null
|
||||
var visibility = ResourceVisibility.UNDEFINED
|
||||
|
||||
@@ -675,7 +732,7 @@ class ResourceGroup(val type : AaptResourceType) {
|
||||
return styleableContainer[0].value!! as Styleable
|
||||
}
|
||||
|
||||
fun findEntry(name: String, entryId: Short? = null): ResourceEntry? {
|
||||
override fun findEntry(name: String, entryId: Short?): ResourceEntry? {
|
||||
val nameGroup = entries[name] ?: return null
|
||||
return if (entryId != null) {
|
||||
nameGroup[entryId] ?: nameGroup[null]
|
||||
@@ -684,6 +741,17 @@ class ResourceGroup(val type : AaptResourceType) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun findEntries(entryId: Short?, predicate: (String) -> Boolean): List<IResourceEntry> {
|
||||
return entries.mapNotNull { (key, value) ->
|
||||
if (!predicate(key)) return@mapNotNull null
|
||||
if (entryId != null) {
|
||||
value[entryId] ?: value[null]
|
||||
} else {
|
||||
value[value.firstKey()]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun findOrCreateEntry(name: String, entryId: Short? = null): ResourceEntry {
|
||||
val entry = findEntry(name, entryId)
|
||||
return when (entry) {
|
||||
@@ -693,13 +761,14 @@ class ResourceGroup(val type : AaptResourceType) {
|
||||
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(override val name: String) : IResourceEntry {
|
||||
var id: Short? = null
|
||||
var visibility = Visibility(Source(""), "", ResourceVisibility.UNDEFINED)
|
||||
|
||||
@@ -708,7 +777,7 @@ class ResourceEntry(val name : String) {
|
||||
|
||||
val values = mutableListOf<ResourceConfigValue>()
|
||||
|
||||
fun findValue(config: ConfigDescription, product: String = ""): ResourceConfigValue? {
|
||||
override fun findValue(config: ConfigDescription, product: String): ResourceConfigValue? {
|
||||
return values.find { it.config == config && it.product == product }
|
||||
}
|
||||
|
||||
@@ -720,19 +789,8 @@ class ResourceEntry(val name : String) {
|
||||
values.add(newConfigValue)
|
||||
newConfigValue
|
||||
}
|
||||
|
||||
else -> configValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a single value for an entry for a given Configuration.
|
||||
*
|
||||
* @property config The configuration for which this value is defined.
|
||||
* @property product The product name for which this value is defined.
|
||||
* @property value The actual Value.
|
||||
*/
|
||||
data class ResourceConfigValue(
|
||||
val config: ConfigDescription,
|
||||
val product : String,
|
||||
var value: Value? = null)
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aapt.Resources
|
||||
import com.android.aapt.Resources.Attribute.FormatFlags
|
||||
import com.android.aaptcompiler.AaptResourceType.ID
|
||||
import com.android.aaptcompiler.AaptResourceType.STYLE
|
||||
import com.android.aaptcompiler.StringPool.Context
|
||||
import com.android.aaptcompiler.StringPool.Context.Priority.NORMAL
|
||||
import com.android.aaptcompiler.android.stringToInt
|
||||
import com.itsaky.androidide.layoutlib.resources.ResourceVisibility
|
||||
import java.io.InputStream
|
||||
@@ -148,7 +153,8 @@ class TableExtractor(
|
||||
val source: Source,
|
||||
val config: ConfigDescription,
|
||||
val options: TableExtractorOptions,
|
||||
val logger: BlameLogger) {
|
||||
val logger: BlameLogger
|
||||
) {
|
||||
|
||||
fun extract(inputFile: InputStream) {
|
||||
var eventReader : XMLEventReader? = null
|
||||
@@ -349,7 +355,7 @@ class TableExtractor(
|
||||
// Grab the name of the resource. This will be validated later, as not all XML resources
|
||||
// require a name.
|
||||
parsedResource.name =
|
||||
parsedResource.name.copy(type = AaptResourceType.ID, entry = nameAttribute.value)
|
||||
parsedResource.name.copy(type = ID, entry = nameAttribute.value)
|
||||
parseItem(element, eventReader, parsedResource, resourceFormat)
|
||||
|
||||
val item = parsedResource.value
|
||||
@@ -361,7 +367,7 @@ class TableExtractor(
|
||||
// A null reference also means there is no inner element when ids are in the form:
|
||||
// <id name="name"/>
|
||||
parsedResource.value = Id()
|
||||
(item is Reference && item.name.type != AaptResourceType.ID) || item !is Reference -> {
|
||||
(item is Reference && item.name.type != ID) || item !is Reference -> {
|
||||
// if an inner element exists, the inner element must be a reference to another id
|
||||
logError(
|
||||
blameSource(parsedResource.source),
|
||||
@@ -518,7 +524,8 @@ class TableExtractor(
|
||||
return StyledString(
|
||||
table.stringPool.makeRef(
|
||||
flattenedXml.styleString,
|
||||
StringPool.Context(StringPool.Context.Priority.NORMAL.priority, config)),
|
||||
Context(NORMAL.priority, config)
|
||||
),
|
||||
flattenedXml.untranslatableSections)
|
||||
}
|
||||
|
||||
@@ -543,7 +550,8 @@ class TableExtractor(
|
||||
// use trimmed escaped string.
|
||||
return BasicString(
|
||||
table.stringPool.makeRef(
|
||||
flattenedXml.styleString.str, StringPool.Context(config = config)),
|
||||
flattenedXml.styleString.str, Context(config = config)
|
||||
),
|
||||
flattenedXml.untranslatableSections)
|
||||
}
|
||||
|
||||
@@ -566,7 +574,7 @@ class TableExtractor(
|
||||
.removeSurrounding("\"")
|
||||
}
|
||||
return RawString(
|
||||
table.stringPool.makeRef(raw, StringPool.Context(config=config)))
|
||||
table.stringPool.makeRef(raw, Context(config=config)))
|
||||
}
|
||||
|
||||
return null
|
||||
@@ -708,12 +716,12 @@ class TableExtractor(
|
||||
val resValue = stringToInt(valueAttribute.value)
|
||||
if (resValue == null) {
|
||||
logError(
|
||||
blameSource(elementSource), "Invalid value '$resValue' for <$tag>. Must be an integer.")
|
||||
blameSource(elementSource), "Invalid value 'null' for <$tag>. Must be an integer.")
|
||||
return null
|
||||
}
|
||||
|
||||
val reference = Reference()
|
||||
reference.name = ResourceName("", AaptResourceType.ID, nameAttribute.value)
|
||||
reference.name = ResourceName("", ID, nameAttribute.value)
|
||||
return AttributeResource.Symbol(reference, resValue.data, resValue.dataType.byteValue)
|
||||
}
|
||||
|
||||
@@ -729,7 +737,8 @@ class TableExtractor(
|
||||
* failed.
|
||||
*/
|
||||
private fun parseStyleItem(
|
||||
element: StartElement, eventReader: XMLEventReader, style: Style): Boolean {
|
||||
element: StartElement, eventReader: XMLEventReader, style: Style
|
||||
): Boolean {
|
||||
val itemSource = source.withLine(element.location.lineNumber)
|
||||
|
||||
val nameAttribute = element.getAttributeByName(QName("name"))
|
||||
@@ -811,9 +820,10 @@ class TableExtractor(
|
||||
}
|
||||
else -> {
|
||||
// besides XLIFF, any other namespaced tags are unsupported and ignored.
|
||||
logger?.warning(
|
||||
logger.warning(
|
||||
"Ignoring element '$elementName' with unknown namespace '${elementName.namespaceURI}'.",
|
||||
blameSource(source.withLine(element.location.lineNumber)))
|
||||
blameSource(source.withLine(element.location.lineNumber))
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -873,9 +883,10 @@ class TableExtractor(
|
||||
|
||||
// Symbols should have the default config
|
||||
if (parsedResource.config != ConfigDescription()) {
|
||||
logger?.warning(
|
||||
logger.warning(
|
||||
"Ignoring configuration '${parsedResource.config}' for <${element.name}> tag.",
|
||||
blameSource(source, element.location))
|
||||
blameSource(source, element.location)
|
||||
)
|
||||
}
|
||||
|
||||
if (!parseSymbolImpl(element, eventReader, parsedResource)) {
|
||||
@@ -1002,9 +1013,10 @@ class TableExtractor(
|
||||
// Attributes only end up in default configuration
|
||||
val defaultConfig = ConfigDescription()
|
||||
if (parsedResource.config != defaultConfig) {
|
||||
logger?.warning(
|
||||
logger.warning(
|
||||
"Ignoring configuration '${parsedResource.config}' for <${element.name}> tag.",
|
||||
blameSource(source, element.location))
|
||||
blameSource(source, element.location)
|
||||
)
|
||||
parsedResource.config = defaultConfig
|
||||
}
|
||||
|
||||
@@ -1142,11 +1154,9 @@ class TableExtractor(
|
||||
val symbolName = symbol.symbol.name.toString()
|
||||
if (symbolMap.contains(symbolName)) {
|
||||
val newSource =
|
||||
logger?.getOriginalSource(blameSource(symbol.symbol.source))
|
||||
?: blameSource(symbol.symbol.source)
|
||||
logger.getOriginalSource(blameSource(symbol.symbol.source))
|
||||
val previousSource =
|
||||
logger?.getOriginalSource(blameSource(symbolMap[symbolName]!!.symbol.source))
|
||||
?: blameSource(symbolMap[symbolName]!!.symbol.source)
|
||||
logger.getOriginalSource(blameSource(symbolMap[symbolName]!!.symbol.source))
|
||||
val errorMsg =
|
||||
"Duplicate symbol '$symbolName' defined here: $newSource" +
|
||||
" and here: $previousSource"
|
||||
@@ -1174,7 +1184,7 @@ class TableExtractor(
|
||||
}
|
||||
|
||||
val resource = AttributeResource(
|
||||
if (typeMask == 0) Resources.Attribute.FormatFlags.ANY_VALUE else typeMask)
|
||||
if (typeMask == 0) FormatFlags.ANY_VALUE else typeMask)
|
||||
resource.weak = isWeak
|
||||
resource.symbols.addAll(symbolMap.values)
|
||||
resource.minInt = min ?: Int.MIN_VALUE
|
||||
@@ -1365,7 +1375,8 @@ class TableExtractor(
|
||||
element: StartElement,
|
||||
eventReader: XMLEventReader,
|
||||
parsedResource: ParsedResource,
|
||||
type: AaptResourceType): Boolean {
|
||||
type: AaptResourceType
|
||||
): Boolean {
|
||||
|
||||
parsedResource.name = parsedResource.name.copy(type = type)
|
||||
|
||||
@@ -1394,7 +1405,7 @@ class TableExtractor(
|
||||
if (marker != -1) {
|
||||
style.parentInferred = true
|
||||
style.parent =
|
||||
Reference(ResourceName("", AaptResourceType.STYLE, styleName.substring(0, marker)))
|
||||
Reference(ResourceName("", STYLE, styleName.substring(0, marker)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1458,9 +1469,10 @@ class TableExtractor(
|
||||
// Declare-stylable only ends up in the default config
|
||||
val defaultConfig = ConfigDescription()
|
||||
if (parsedResource.config != defaultConfig) {
|
||||
logger?.warning(
|
||||
logger.warning(
|
||||
"Ignoring configuration '${parsedResource.config}' for <${element.name}> tag.",
|
||||
blameSource(source, element.location))
|
||||
blameSource(source, element.location)
|
||||
)
|
||||
parsedResource.config = defaultConfig
|
||||
}
|
||||
|
||||
@@ -1554,9 +1566,10 @@ class TableExtractor(
|
||||
|
||||
val defaultConfig = ConfigDescription()
|
||||
if (parsedResource.config != defaultConfig) {
|
||||
logger?.warning(
|
||||
logger.warning(
|
||||
"Ignoring configuration '${parsedResource.config}' for <${element.name}> tag.",
|
||||
blameSource(source, element.location))
|
||||
blameSource(source, element.location)
|
||||
)
|
||||
}
|
||||
|
||||
val nameAttribute = element.getAttributeByName(QName(null, "name"))
|
||||
@@ -1883,9 +1896,10 @@ class TableExtractor(
|
||||
}
|
||||
|
||||
if (parsedResource.config != ConfigDescription()) {
|
||||
logger?.warning(
|
||||
logger.warning(
|
||||
"Ignoring configuration '${parsedResource.config}' for <${element.name}> tag.",
|
||||
blameSource(source, element.location))
|
||||
blameSource(source, element.location)
|
||||
)
|
||||
}
|
||||
|
||||
val typeAttribute = element.getAttributeByName(QName("type"))
|
||||
@@ -1919,7 +1933,7 @@ class TableExtractor(
|
||||
parsedResource.resourceId = id
|
||||
}
|
||||
|
||||
if (parsedType == AaptResourceType.ID) {
|
||||
if (parsedType == ID) {
|
||||
// An ID marked as public is also the definition of an ID.
|
||||
parsedResource.value = Id()
|
||||
}
|
||||
@@ -1944,9 +1958,10 @@ class TableExtractor(
|
||||
}
|
||||
|
||||
if (parsedResource.config != ConfigDescription()) {
|
||||
logger?.warning(
|
||||
logger.warning(
|
||||
"Ignoring configuration '${parsedResource.config}' for <${element.name}> tag.",
|
||||
blameSource(source, element.location))
|
||||
blameSource(source, element.location)
|
||||
)
|
||||
}
|
||||
|
||||
val typeAttribute = element.getAttributeByName(QName("type"))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aaptcompiler.ResourceFile.Type.ProtoXml
|
||||
import java.io.InputStream
|
||||
import java.lang.RuntimeException
|
||||
import jaxp.xml.namespace.QName
|
||||
@@ -389,7 +390,7 @@ class XmlProcessor(val source: Source, val logger: BlameLogger?) {
|
||||
|
||||
// Now to add the new attribute to the parent xml element.
|
||||
parentBuilder.addAttribute(
|
||||
nameValue.entry,
|
||||
nameValue.entry!!,
|
||||
attrUri,
|
||||
"@${resource.name}",
|
||||
attrElement.location.lineNumber,
|
||||
@@ -529,7 +530,7 @@ class XmlProcessor(val source: Source, val logger: BlameLogger?) {
|
||||
primaryFile.name.copy(entry = newEntryName),
|
||||
primaryFile.configuration,
|
||||
primaryFile.source.withLine(element.location.lineNumber),
|
||||
ResourceFile.Type.ProtoXml
|
||||
ProtoXml
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ 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 = XMLInputFactoryImpl()
|
||||
|
||||
@@ -25,6 +25,8 @@ import com.android.aaptcompiler.ResourceTable
|
||||
import com.android.aaptcompiler.Source
|
||||
import com.android.aaptcompiler.Span
|
||||
import com.android.aaptcompiler.StringPool
|
||||
import com.android.aaptcompiler.StringPool.Context
|
||||
import com.android.aaptcompiler.StringPool.Context.Priority.HIGH
|
||||
import com.android.aaptcompiler.Style
|
||||
import com.android.aaptcompiler.StyleString
|
||||
import com.android.aaptcompiler.Styleable
|
||||
@@ -48,10 +50,10 @@ fun deserializeConfigFromPb(
|
||||
config: ConfigurationOuterClass.Configuration, logger: ILogger?
|
||||
): ConfigDescription? {
|
||||
|
||||
val mcc = config.getMcc().toShort()
|
||||
val mnc = config.getMnc().toShort()
|
||||
val mcc = config.mcc.toShort()
|
||||
val mnc = config.mnc.toShort()
|
||||
|
||||
val localeString = config.getLocale()
|
||||
val localeString = config.locale
|
||||
val localeValue = LocaleValue()
|
||||
if (localeString.isNotEmpty()) {
|
||||
if (!localeValue.initFromBcp47Tag(localeString)) {
|
||||
@@ -70,9 +72,9 @@ fun deserializeConfigFromPb(
|
||||
else -> ResTableConfig.SCREEN_LAYOUT.DIR_ANY
|
||||
}
|
||||
|
||||
val smallestScreenWidthDp = config.getSmallestScreenWidthDp()
|
||||
val screenWidthDp = config.getScreenWidthDp()
|
||||
val screenHeightDp = config.getScreenHeightDp()
|
||||
val smallestScreenWidthDp = config.smallestScreenWidthDp
|
||||
val screenWidthDp = config.screenWidthDp
|
||||
val screenHeightDp = config.screenHeightDp
|
||||
|
||||
val screenLayoutSize = when (config.getScreenLayoutSize()) {
|
||||
ConfigurationOuterClass.Configuration.ScreenLayoutSize.SCREEN_LAYOUT_SIZE_SMALL ->
|
||||
@@ -174,7 +176,7 @@ fun deserializeConfigFromPb(
|
||||
else -> ResTableConfig.UI_MODE.NIGHT_ANY
|
||||
}
|
||||
|
||||
val density = config.getDensity()
|
||||
val density = config.density
|
||||
|
||||
val touchscreen = when (config.getTouchscreen()) {
|
||||
ConfigurationOuterClass.Configuration.Touchscreen.TOUCHSCREEN_NOTOUCH ->
|
||||
@@ -254,9 +256,9 @@ fun deserializeConfigFromPb(
|
||||
else -> ResTableConfig.GRAMMATICAL_GENDER.ANY
|
||||
}
|
||||
|
||||
val screenWidth = config.getScreenWidth()
|
||||
val screenHeight = config.getScreenHeight()
|
||||
val sdkVersion = config.getSdkVersion().toShort()
|
||||
val screenWidth = config.screenWidth
|
||||
val screenHeight = config.screenHeight
|
||||
val sdkVersion = config.sdkVersion.toShort()
|
||||
|
||||
val configDescription = ConfigDescription(
|
||||
ResTableConfig(
|
||||
@@ -301,8 +303,8 @@ fun deserializeReferenceTypeFromPb(type: Resources.Reference.Type) = when (type)
|
||||
}
|
||||
|
||||
fun deserializeSourceFromPb(source: Resources.Source, sourcePool: ResStringPool): Source {
|
||||
val path = sourcePool.strings[source.getPathIdx()]
|
||||
val line = source.getPosition().getLineNumber()
|
||||
val path = sourcePool.strings[source.pathIdx]
|
||||
val line = source.position.lineNumber
|
||||
return Source(path, line)
|
||||
}
|
||||
|
||||
@@ -320,7 +322,7 @@ fun deserializeOverlayableFromPb(
|
||||
): OverlayableItem? {
|
||||
|
||||
var policies = 0
|
||||
for (policy in item.getPolicyList()) {
|
||||
for (policy in item.policyList) {
|
||||
policies = policies or when (policy) {
|
||||
Resources.OverlayableItem.Policy.PUBLIC -> OverlayableItem.Policy.PUBLIC
|
||||
Resources.OverlayableItem.Policy.SYSTEM -> OverlayableItem.Policy.SYSTEM
|
||||
@@ -337,11 +339,11 @@ fun deserializeOverlayableFromPb(
|
||||
}
|
||||
|
||||
val source = if (item.hasSource()) {
|
||||
deserializeSourceFromPb(item.getSource(), sourcePool)
|
||||
deserializeSourceFromPb(item.source, sourcePool)
|
||||
} else {
|
||||
Source.EMPTY
|
||||
}
|
||||
val comment = item.getComment()
|
||||
val comment = item.comment
|
||||
return OverlayableItem(overlayable, policies, comment, source)
|
||||
}
|
||||
|
||||
@@ -349,7 +351,7 @@ fun deserializeBinPrimitiveFromPb(
|
||||
primitive: Resources.Primitive, logger: ILogger?
|
||||
): BinaryPrimitive? {
|
||||
|
||||
val (type, deviceValue) = when (primitive.getOneofValueCase()) {
|
||||
val (type, deviceValue) = when (primitive.oneofValueCase) {
|
||||
Resources.Primitive.OneofValueCase.NULL_VALUE ->
|
||||
Pair(ResValue.DataType.NULL, ResValue.NullFormat.UNDEFINED)
|
||||
|
||||
@@ -410,25 +412,25 @@ fun deserializeBinPrimitiveFromPb(
|
||||
}
|
||||
|
||||
fun deserializeStringFromPb(string: Resources.String, valuePool: StringPool) =
|
||||
BasicString(valuePool.makeRef(string.getValue()))
|
||||
BasicString(valuePool.makeRef(string.value))
|
||||
|
||||
fun deserializeRawFromPb(string: Resources.RawString, valuePool: StringPool) =
|
||||
RawString(valuePool.makeRef(string.getValue()))
|
||||
RawString(valuePool.makeRef(string.value))
|
||||
|
||||
fun deserializeStyledStrFromPb(
|
||||
string: Resources.StyledString, valuePool: StringPool
|
||||
): StyledString {
|
||||
|
||||
val spans = mutableListOf<Span>()
|
||||
for (span in string.getSpanList()) {
|
||||
spans.add(Span(span.getTag(), span.getFirstChar(), span.getLastChar()))
|
||||
for (span in string.spanList) {
|
||||
spans.add(Span(span.tag, span.firstChar, span.lastChar))
|
||||
}
|
||||
return StyledString(valuePool.makeRef(StyleString(string.getValue(), spans)), listOf())
|
||||
return StyledString(valuePool.makeRef(StyleString(string.value, spans)), listOf())
|
||||
}
|
||||
|
||||
fun deserializeReferenceFromPb(ref: Resources.Reference, logger: ILogger?): Reference? {
|
||||
val reference = if (ref.getName().isNotEmpty()) {
|
||||
val refName = parseResourceName(ref.getName())
|
||||
val reference = if (ref.name.isNotEmpty()) {
|
||||
val refName = parseResourceName(ref.name)
|
||||
if (refName == null) {
|
||||
val errorMsg = "%s cannot be parsed as a Resource Name."
|
||||
logger?.error(null, errorMsg, ref.name)
|
||||
@@ -440,10 +442,10 @@ fun deserializeReferenceFromPb(ref: Resources.Reference, logger: ILogger?): Refe
|
||||
}
|
||||
|
||||
reference.referenceType = deserializeReferenceTypeFromPb(ref.getType())
|
||||
reference.isPrivate = ref.getPrivate()
|
||||
reference.isPrivate = ref.private
|
||||
|
||||
if (ref.getId() != 0) {
|
||||
reference.id = ref.getId()
|
||||
if (ref.id != 0) {
|
||||
reference.id = ref.id
|
||||
}
|
||||
return reference
|
||||
}
|
||||
@@ -454,8 +456,8 @@ fun deserializeFileRefFromPb(
|
||||
|
||||
val fileRef = FileReference(
|
||||
valuePool.makeRef(
|
||||
file.getPath(),
|
||||
StringPool.Context(StringPool.Context.Priority.HIGH.priority, config)
|
||||
file.path,
|
||||
Context(HIGH.priority, config)
|
||||
)
|
||||
)
|
||||
fileRef.type = deserializeFileTypeFromPb(file.getType())
|
||||
@@ -467,21 +469,21 @@ fun deserializeAttrFromPb(
|
||||
attr: Resources.Attribute, sourcePool: ResStringPool, logger: ILogger?
|
||||
): AttributeResource? {
|
||||
|
||||
val attrResource = AttributeResource(attr.getFormatFlags())
|
||||
attrResource.minInt = attr.getMinInt()
|
||||
attrResource.maxInt = attr.getMaxInt()
|
||||
val attrResource = AttributeResource(attr.formatFlags)
|
||||
attrResource.minInt = attr.minInt
|
||||
attrResource.maxInt = attr.maxInt
|
||||
|
||||
for (symbol in attr.getSymbolList()) {
|
||||
val reference = deserializeReferenceFromPb(symbol.getName(), logger)
|
||||
for (symbol in attr.symbolList) {
|
||||
val reference = deserializeReferenceFromPb(symbol.name, logger)
|
||||
reference ?: return null
|
||||
|
||||
if (symbol.hasSource()) {
|
||||
reference.source = deserializeSourceFromPb(symbol.getSource(), sourcePool)
|
||||
reference.source = deserializeSourceFromPb(symbol.source, sourcePool)
|
||||
}
|
||||
reference.comment = symbol.getComment()
|
||||
reference.comment = symbol.comment
|
||||
|
||||
attrResource.symbols.add(
|
||||
AttributeResource.Symbol(reference, symbol.getValue(), symbol.getType().toByte())
|
||||
AttributeResource.Symbol(reference, symbol.value, symbol.type.toByte())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -498,29 +500,29 @@ fun deserializeStyleFromPb(
|
||||
|
||||
val styleResource = Style()
|
||||
if (style.hasParent()) {
|
||||
val parentRef = deserializeReferenceFromPb(style.getParent(), logger)
|
||||
val parentRef = deserializeReferenceFromPb(style.parent, logger)
|
||||
parentRef ?: return null
|
||||
|
||||
parentRef.source = if (style.hasParentSource()) {
|
||||
deserializeSourceFromPb(style.getParentSource(), sourcePool)
|
||||
deserializeSourceFromPb(style.parentSource, sourcePool)
|
||||
} else {
|
||||
Source.EMPTY
|
||||
}
|
||||
styleResource.parent = parentRef
|
||||
}
|
||||
|
||||
for (entry in style.getEntryList()) {
|
||||
val key = deserializeReferenceFromPb(entry.getKey(), logger)
|
||||
for (entry in style.entryList) {
|
||||
val key = deserializeReferenceFromPb(entry.key, logger)
|
||||
key ?: return null
|
||||
|
||||
val value = deserializeItemFromPb(entry.getItem(), valuePool, config, logger)
|
||||
val value = deserializeItemFromPb(entry.item, valuePool, config, logger)
|
||||
value ?: return null
|
||||
if (entry.hasSource()) {
|
||||
key.source = deserializeSourceFromPb(entry.getSource(), sourcePool)
|
||||
value.source = deserializeSourceFromPb(entry.getSource(), sourcePool)
|
||||
key.source = deserializeSourceFromPb(entry.source, sourcePool)
|
||||
value.source = deserializeSourceFromPb(entry.source, sourcePool)
|
||||
}
|
||||
key.comment = entry.getComment()
|
||||
value.comment = entry.getComment()
|
||||
key.comment = entry.comment
|
||||
value.comment = entry.comment
|
||||
styleResource.entries.add(Style.Entry(key, value))
|
||||
}
|
||||
|
||||
@@ -532,13 +534,13 @@ fun deserializeStyleableFromPb(
|
||||
): Styleable? {
|
||||
|
||||
val styleableResource = Styleable()
|
||||
for (entry in styleable.getEntryList()) {
|
||||
val reference = deserializeReferenceFromPb(entry.getAttr(), logger)
|
||||
for (entry in styleable.entryList) {
|
||||
val reference = deserializeReferenceFromPb(entry.attr, logger)
|
||||
reference ?: return null
|
||||
if (entry.hasSource()) {
|
||||
reference.source = deserializeSourceFromPb(entry.getSource(), sourcePool)
|
||||
reference.source = deserializeSourceFromPb(entry.source, sourcePool)
|
||||
}
|
||||
reference.comment = entry.getComment()
|
||||
reference.comment = entry.comment
|
||||
styleableResource.entries.add(reference)
|
||||
}
|
||||
return styleableResource
|
||||
@@ -553,14 +555,14 @@ fun deserializeArrayFromPb(
|
||||
): ArrayResource? {
|
||||
|
||||
val arrayResource = ArrayResource()
|
||||
for (entry in array.getElementList()) {
|
||||
val item = deserializeItemFromPb(entry.getItem(), valuePool, config, logger)
|
||||
for (entry in array.elementList) {
|
||||
val item = deserializeItemFromPb(entry.item, valuePool, config, logger)
|
||||
item ?: return null
|
||||
|
||||
if (entry.hasSource()) {
|
||||
item.source = deserializeSourceFromPb(entry.getSource(), sourcePool)
|
||||
item.source = deserializeSourceFromPb(entry.source, sourcePool)
|
||||
}
|
||||
item.comment = entry.getComment()
|
||||
item.comment = entry.comment
|
||||
arrayResource.elements.add(item)
|
||||
}
|
||||
return arrayResource
|
||||
@@ -584,18 +586,18 @@ fun deserializePluralFromPb(
|
||||
): Plural? {
|
||||
|
||||
val pluralResource = Plural()
|
||||
for (entry in plural.getEntryList()) {
|
||||
for (entry in plural.entryList) {
|
||||
val type = deserializePluralTypeFromPb(entry.getArity())
|
||||
val item = deserializeItemFromPb(entry.getItem(), valuePool, config, logger)
|
||||
val item = deserializeItemFromPb(entry.item, valuePool, config, logger)
|
||||
|
||||
item ?: return null
|
||||
|
||||
item.source = if (entry.hasSource()) {
|
||||
deserializeSourceFromPb(entry.getSource(), sourcePool)
|
||||
deserializeSourceFromPb(entry.source, sourcePool)
|
||||
} else {
|
||||
Source.EMPTY
|
||||
}
|
||||
item.comment = entry.getComment()
|
||||
item.comment = entry.comment
|
||||
|
||||
pluralResource.setValue(type, item)
|
||||
}
|
||||
@@ -648,7 +650,7 @@ fun deserializeItemFromPb(
|
||||
valuePool: StringPool,
|
||||
config: ConfigDescription,
|
||||
logger: ILogger?
|
||||
): Item? = when (item.getValueCase()) {
|
||||
): Item? = when (item.valueCase) {
|
||||
|
||||
Resources.Item.ValueCase.REF -> deserializeReferenceFromPb(item.getRef(), logger)
|
||||
Resources.Item.ValueCase.STR -> deserializeStringFromPb(item.getStr(), valuePool)
|
||||
@@ -679,7 +681,7 @@ fun deserializeValueFromPb(
|
||||
value.hasCompoundValue() -> {
|
||||
val compoundValue = value.getCompoundValue()
|
||||
|
||||
when (compoundValue.getValueCase()) {
|
||||
when (compoundValue.valueCase) {
|
||||
Resources.CompoundValue.ValueCase.ATTR ->
|
||||
deserializeAttrFromPb(compoundValue.getAttr(), sourcePool, logger)
|
||||
|
||||
@@ -714,11 +716,11 @@ fun deserializeValueFromPb(
|
||||
}
|
||||
valueResource ?: return null
|
||||
|
||||
valueResource.weak = value.getWeak()
|
||||
valueResource.weak = value.weak
|
||||
if (value.hasSource()) {
|
||||
valueResource.source = deserializeSourceFromPb(value.getSource(), sourcePool)
|
||||
valueResource.source = deserializeSourceFromPb(value.source, sourcePool)
|
||||
}
|
||||
valueResource.comment = value.getComment()
|
||||
valueResource.comment = value.comment
|
||||
|
||||
return valueResource
|
||||
}
|
||||
@@ -732,14 +734,14 @@ fun deserializePackageFromPb(
|
||||
): Boolean {
|
||||
|
||||
val packageId =
|
||||
if (original.hasPackageId()) original.getPackageId().getId().toByte() else 0.toByte()
|
||||
if (original.hasPackageId()) original.packageId.id.toByte() else 0.toByte()
|
||||
|
||||
val idIndex = mutableIntObjectMapOf<ResourceName>()
|
||||
|
||||
val resourcePackage =
|
||||
table.createPackageAllowingDuplicateNames(original.getPackageName(), packageId)
|
||||
for (group in original.getTypeList()) {
|
||||
val resType = resourceTypeFromTag(group.getName())
|
||||
table.createPackageAllowingDuplicateNames(original.packageName, packageId)
|
||||
for (group in original.typeList) {
|
||||
val resType = resourceTypeFromTag(group.name)
|
||||
|
||||
if (resType == null) {
|
||||
val errorMsg = "Unrecognized Resource Type: %s."
|
||||
@@ -749,18 +751,18 @@ fun deserializePackageFromPb(
|
||||
|
||||
val resourceGroup = resourcePackage.findOrCreateGroup(resType)
|
||||
if (group.hasTypeId()) {
|
||||
resourceGroup.id = group.getTypeId().getId().toByte()
|
||||
resourceGroup.id = group.typeId.id.toByte()
|
||||
}
|
||||
|
||||
for (entry in group.getEntryList()) {
|
||||
val resourceEntry = resourceGroup.findOrCreateEntry(entry.getName())
|
||||
for (entry in group.entryList) {
|
||||
val resourceEntry = resourceGroup.findOrCreateEntry(entry.name)
|
||||
if (entry.hasEntryId()) {
|
||||
resourceEntry.id = entry.getEntryId().getId().toShort()
|
||||
resourceEntry.id = entry.entryId.id.toShort()
|
||||
}
|
||||
|
||||
// Deserialize the symbol status (public/private with metadata)
|
||||
if (entry.hasVisibility()) {
|
||||
val visibility = entry.getVisibility()
|
||||
val visibility = entry.visibility
|
||||
|
||||
val visibilityLevel = deserializeVisibilityFromPb(visibility.getLevel())
|
||||
when (visibilityLevel) {
|
||||
@@ -777,30 +779,30 @@ fun deserializePackageFromPb(
|
||||
}
|
||||
|
||||
val visibilitySource = if (visibility.hasSource()) {
|
||||
deserializeSourceFromPb(visibility.getSource(), sourcePool)
|
||||
deserializeSourceFromPb(visibility.source, sourcePool)
|
||||
} else {
|
||||
Source.EMPTY
|
||||
}
|
||||
val visibilityComment = visibility.getComment()
|
||||
val visibilityComment = visibility.comment
|
||||
|
||||
resourceEntry.visibility = Visibility(visibilitySource, visibilityComment, visibilityLevel)
|
||||
}
|
||||
|
||||
if (entry.hasAllowNew()) {
|
||||
val allowNew = entry.getAllowNew()
|
||||
val allowNew = entry.allowNew
|
||||
val allowNewSource = if (allowNew.hasSource()) {
|
||||
deserializeSourceFromPb(allowNew.getSource(), sourcePool)
|
||||
deserializeSourceFromPb(allowNew.source, sourcePool)
|
||||
} else {
|
||||
Source.EMPTY
|
||||
}
|
||||
val allowNewComment = allowNew.getComment()
|
||||
val allowNewComment = allowNew.comment
|
||||
resourceEntry.allowNew = AllowNew(allowNewSource, allowNewComment)
|
||||
}
|
||||
|
||||
if (entry.hasOverlayableItem()) {
|
||||
// Find the overlayable to which this item belongs.
|
||||
val overlayableItem = entry.getOverlayableItem()
|
||||
if (overlayableItem.getOverlayableIdx() >= overlayables.size) {
|
||||
val overlayableItem = entry.overlayableItem
|
||||
if (overlayableItem.overlayableIdx >= overlayables.size) {
|
||||
val errorMsg = "Illegal value for overlayable id '%s'. Because only '%s' overlayables" +
|
||||
"exist in proto."
|
||||
logger?.error(null, errorMsg, overlayableItem.overlayableIdx, overlayables.size)
|
||||
@@ -809,7 +811,7 @@ fun deserializePackageFromPb(
|
||||
val resourceOverlayable =
|
||||
deserializeOverlayableFromPb(
|
||||
overlayableItem,
|
||||
overlayables[overlayableItem.getOverlayableIdx()],
|
||||
overlayables[overlayableItem.overlayableIdx],
|
||||
sourcePool,
|
||||
logger
|
||||
)
|
||||
@@ -819,23 +821,23 @@ fun deserializePackageFromPb(
|
||||
}
|
||||
|
||||
val resourceId = resourceIdFromParts(
|
||||
original.getPackageId().getId().toByte(),
|
||||
group.getTypeId().getId().toByte(),
|
||||
entry.getEntryId().getId().toShort()
|
||||
original.packageId.id.toByte(),
|
||||
group.typeId.id.toByte(),
|
||||
entry.entryId.id.toShort()
|
||||
)
|
||||
if (resourceId.isValidId()) {
|
||||
idIndex[resourceId] =
|
||||
ResourceName(resourcePackage.name, resourceGroup.type, resourceEntry.name)
|
||||
}
|
||||
|
||||
for (configValue in entry.getConfigValueList()) {
|
||||
val config = configValue.getConfig()
|
||||
for (configValue in entry.configValueList) {
|
||||
val config = configValue.config
|
||||
|
||||
val resourceConfig = deserializeConfigFromPb(config, logger)
|
||||
resourceConfig ?: return false
|
||||
|
||||
val resourceConfigValue =
|
||||
resourceEntry.findOrCreateValue(resourceConfig, config.getProduct())
|
||||
resourceEntry.findOrCreateValue(resourceConfig, config.product)
|
||||
if (resourceConfigValue.value.isTruthy()) {
|
||||
val errorMsg = "Value already exists for name %s, config %s, and product %s."
|
||||
logger?.error(
|
||||
@@ -850,7 +852,7 @@ fun deserializePackageFromPb(
|
||||
|
||||
resourceConfigValue.value =
|
||||
deserializeValueFromPb(
|
||||
configValue.getValue(), table.stringPool, resourceConfig, sourcePool, logger
|
||||
configValue.value, table.stringPool, resourceConfig, sourcePool, logger
|
||||
)
|
||||
|
||||
resourceConfigValue.value ?: return false
|
||||
@@ -885,22 +887,22 @@ fun deserializeTableFromPb(
|
||||
): Boolean {
|
||||
|
||||
val sourcePool = ResStringPool.get(
|
||||
table.getSourcePool().getData().asReadOnlyByteBuffer(),
|
||||
table.getSourcePool().getSerializedSize()
|
||||
table.sourcePool.data.asReadOnlyByteBuffer(),
|
||||
table.sourcePool.serializedSize
|
||||
)
|
||||
|
||||
// Deserialize the overlayable groups of a table
|
||||
val overlayables = mutableListOf<Overlayable>()
|
||||
for (overlayable in table.getOverlayableList()) {
|
||||
for (overlayable in table.overlayableList) {
|
||||
val overlayableSource = if (overlayable.hasSource()) {
|
||||
deserializeSourceFromPb(overlayable.getSource(), sourcePool)
|
||||
deserializeSourceFromPb(overlayable.source, sourcePool)
|
||||
} else {
|
||||
Source.EMPTY
|
||||
}
|
||||
overlayables.add(Overlayable(overlayable.getName(), overlayable.getActor(), overlayableSource))
|
||||
overlayables.add(Overlayable(overlayable.name, overlayable.actor, overlayableSource))
|
||||
}
|
||||
|
||||
for (resourcePackage in table.getPackageList()) {
|
||||
for (resourcePackage in table.packageList) {
|
||||
if (!deserializePackageFromPb(resourcePackage, sourcePool, overlayables, logger, outTable)) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
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
|
||||
@@ -59,7 +58,7 @@ 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()
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.itsaky.androidide.aapt
|
||||
|
||||
import com.android.aaptcompiler.ResourceEntry
|
||||
import com.android.aaptcompiler.ResourceGroup
|
||||
|
||||
/** @author Akash Yadav */
|
||||
|
||||
/** Returns all [ResourceEntry]s which match the given predicate. */
|
||||
fun ResourceGroup.findEntries(
|
||||
entryId: Short? = null,
|
||||
test: (String) -> Boolean
|
||||
): List<ResourceEntry> {
|
||||
val result = mutableListOf<ResourceEntry>()
|
||||
entries.forEach {
|
||||
if (test(it.key)) {
|
||||
val element =
|
||||
if (entryId != null) {
|
||||
it.value[entryId] ?: it.value[null]
|
||||
} else {
|
||||
it.value[it.value.firstKey()]
|
||||
}
|
||||
|
||||
if (element != null) {
|
||||
result.add(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aaptcompiler.BlameLogger.Source
|
||||
import com.android.utils.ILogger
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
@@ -73,5 +74,5 @@ fun getMockBlameLogger(mockLogger: BlameLoggerTest.MockLogger) =
|
||||
BlameLogger(
|
||||
mockLogger
|
||||
) {
|
||||
BlameLogger.Source(it.sourcePath + ".rewritten", it.line + 1, it.column + 2)
|
||||
Source(it.sourcePath + ".rewritten", it.line + 1, it.column + 2)
|
||||
}
|
||||
|
||||
+4
-2
@@ -32,7 +32,8 @@ class PseudolocaleGeneratorTest {
|
||||
val spans = listOf(
|
||||
Span("i", 1, 10),
|
||||
Span("b", 2, 3),
|
||||
Span("b", 6, 7))
|
||||
Span("b", 6, 7)
|
||||
)
|
||||
val original = StyledString(pool.makeRef(StyleString("Hello world!", spans)), listOf())
|
||||
|
||||
val newString1 = pseudolocalizeStyledString(original, Pseudolocalizer.Method.NONE, pool)
|
||||
@@ -124,7 +125,8 @@ class PseudolocaleGeneratorTest {
|
||||
Span("b", 16, 19),
|
||||
Span("em", 29, 47),
|
||||
Span("i", 38, 40),
|
||||
Span("b", 44, 47))
|
||||
Span("b", 44, 47)
|
||||
)
|
||||
val originalText = "This sentence is not what you think it is at all."
|
||||
val original = StyledString(pool.makeRef(StyleString(originalText, originalSpans)), listOf())
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.android.aaptcompiler
|
||||
import com.android.aapt.Resources
|
||||
import com.android.aaptcompiler.android.ResValue
|
||||
import com.android.aaptcompiler.proto.deserializeConfigFromPb
|
||||
import com.android.aaptcompiler.proto.deserializeFileTypeFromPb
|
||||
import com.android.aaptcompiler.proto.deserializeTableFromPb
|
||||
import com.android.aaptcompiler.testutils.ContainerReader
|
||||
import com.android.aaptcompiler.testutils.FileEntry
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aapt.Resources
|
||||
import com.android.aapt.Resources.Attribute.FormatFlags
|
||||
import com.android.aaptcompiler.AaptResourceType.ATTR
|
||||
import com.android.aaptcompiler.AaptResourceType.ID
|
||||
import com.android.aaptcompiler.AaptResourceType.STYLEABLE
|
||||
import com.android.aaptcompiler.android.ResTableConfig
|
||||
import com.android.aaptcompiler.android.ResValue
|
||||
import com.android.aaptcompiler.android.ResValue.DataType.INT_BOOLEAN
|
||||
import com.itsaky.androidide.layoutlib.resources.ResourceVisibility
|
||||
import com.google.common.truth.Truth
|
||||
import org.junit.Test
|
||||
@@ -35,14 +39,14 @@ class ResourceTableTest {
|
||||
|
||||
Truth.assertThat(
|
||||
table.addResource(
|
||||
ResourceName("android", AaptResourceType.ID, "hey,there"),
|
||||
ResourceName("android", ID, "hey,there"),
|
||||
ConfigDescription(),
|
||||
"",
|
||||
id)).isFalse()
|
||||
|
||||
Truth.assertThat(
|
||||
table.addResource(
|
||||
ResourceName("android", AaptResourceType.ID, "hey:there"),
|
||||
ResourceName("android", ID, "hey:there"),
|
||||
ConfigDescription(),
|
||||
"",
|
||||
id)).isFalse()
|
||||
@@ -86,23 +90,23 @@ class ResourceTableTest {
|
||||
val table = ResourceTable()
|
||||
|
||||
val styleableOne = Styleable()
|
||||
styleableOne.entries.add(0, Reference(ResourceName("", AaptResourceType.ATTR, "child_one")))
|
||||
styleableOne.entries.add(1, Reference(ResourceName("android", AaptResourceType.ATTR, "child_two")))
|
||||
styleableOne.entries.add(0, Reference(ResourceName("", ATTR, "child_one")))
|
||||
styleableOne.entries.add(1, Reference(ResourceName("android", ATTR, "child_two")))
|
||||
|
||||
Truth.assertThat(
|
||||
table.addResource(
|
||||
ResourceName("", AaptResourceType.STYLEABLE, "styleable_parent_one"),
|
||||
ResourceName("", STYLEABLE, "styleable_parent_one"),
|
||||
ConfigDescription(),
|
||||
"",
|
||||
styleableOne)).isTrue()
|
||||
|
||||
val styleableTwo = Styleable()
|
||||
styleableTwo.entries.add(0, Reference(ResourceName("", AaptResourceType.ATTR, "child_one")))
|
||||
styleableTwo.entries.add(1, Reference(ResourceName("android", AaptResourceType.ATTR, "child_three")))
|
||||
styleableTwo.entries.add(0, Reference(ResourceName("", ATTR, "child_one")))
|
||||
styleableTwo.entries.add(1, Reference(ResourceName("android", ATTR, "child_three")))
|
||||
|
||||
Truth.assertThat(
|
||||
table.addResource(
|
||||
ResourceName("", AaptResourceType.STYLEABLE, "styleable_parent_two"),
|
||||
ResourceName("", STYLEABLE, "styleable_parent_two"),
|
||||
ConfigDescription(),
|
||||
"",
|
||||
styleableTwo)).isTrue()
|
||||
@@ -139,7 +143,7 @@ class ResourceTableTest {
|
||||
val table = ResourceTable()
|
||||
val config = ConfigDescription()
|
||||
val languageConfig =
|
||||
ConfigDescription(ResTableConfig(language = byteArrayOf('p'.toByte(), 'l'.toByte())))
|
||||
ConfigDescription(ResTableConfig(language = byteArrayOf('p'.code.toByte(), 'l'.code.toByte())))
|
||||
|
||||
val id1 = Id()
|
||||
id1.source = Source("test/path/file.xml", 10)
|
||||
@@ -223,11 +227,11 @@ class ResourceTableTest {
|
||||
val config = ConfigDescription()
|
||||
|
||||
val name = parseResourceName("android:attr/foo")!!.resourceName
|
||||
val weak1 = AttributeResource(Resources.Attribute.FormatFlags.STRING_VALUE)
|
||||
val weak1 = AttributeResource(FormatFlags.STRING_VALUE)
|
||||
weak1.weak = true
|
||||
val weak2 = AttributeResource(
|
||||
Resources.Attribute.FormatFlags.STRING_VALUE or
|
||||
Resources.Attribute.FormatFlags.REFERENCE_VALUE)
|
||||
FormatFlags.STRING_VALUE or
|
||||
FormatFlags.REFERENCE_VALUE)
|
||||
weak2.weak = true
|
||||
|
||||
Truth.assertThat(table.addResource(name, config, "", weak1)).isTrue()
|
||||
@@ -340,7 +344,8 @@ class ResourceTableTest {
|
||||
overlayable,
|
||||
OverlayableItem.Policy.PRODUCT or OverlayableItem.Policy.VENDOR,
|
||||
"comment",
|
||||
Source("res/values/overlayable.xml", 42))
|
||||
Source("res/values/overlayable.xml", 42)
|
||||
)
|
||||
|
||||
val name = parseResourceName("android:string/foo")!!.resourceName
|
||||
table.setOverlayable(name, overlayableItem)
|
||||
@@ -436,14 +441,16 @@ class ResourceTableTest {
|
||||
0x7f0100ff,
|
||||
ConfigDescription(),
|
||||
"",
|
||||
BinaryPrimitive(ResValue(ResValue.DataType.INT_BOOLEAN, 0)))).isTrue()
|
||||
BinaryPrimitive(ResValue(INT_BOOLEAN, 0))
|
||||
)).isTrue()
|
||||
Truth.assertThat(
|
||||
table.addResourceWithId(
|
||||
name,
|
||||
0x7f010100,
|
||||
ConfigDescription(),
|
||||
"",
|
||||
BinaryPrimitive(ResValue(ResValue.DataType.INT_BOOLEAN, 1)))).isTrue()
|
||||
BinaryPrimitive(ResValue(INT_BOOLEAN, 1))
|
||||
)).isTrue()
|
||||
|
||||
Truth.assertThat(
|
||||
table.setVisibilityWithId(
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aapt.Resources
|
||||
import com.android.aapt.Resources.Attribute.FormatFlags
|
||||
import com.android.aaptcompiler.AaptResourceType.COLOR
|
||||
import com.android.aaptcompiler.AaptResourceType.ID
|
||||
import com.android.aaptcompiler.AaptResourceType.INTEGER
|
||||
import com.android.aaptcompiler.AaptResourceType.STRING
|
||||
import com.android.aaptcompiler.android.ResValue
|
||||
import com.android.aaptcompiler.android.ResValue.DataType.FLOAT
|
||||
import com.android.aaptcompiler.android.ResValue.DataType.INT_BOOLEAN
|
||||
import com.android.aaptcompiler.android.ResValue.DataType.INT_DEC
|
||||
import com.android.aaptcompiler.android.ResValue.DataType.NULL
|
||||
import com.android.aaptcompiler.android.ResValue.NullFormat
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
@@ -25,19 +35,19 @@ class ResourceUtilsTest {
|
||||
var result = parseResourceName("android:color/foo")
|
||||
assertThat(result).isNotNull()
|
||||
assertThat(result?.resourceName)
|
||||
.isEqualTo(ResourceName("android", AaptResourceType.COLOR, "foo"))
|
||||
.isEqualTo(ResourceName("android", COLOR, "foo"))
|
||||
assertThat(result?.isPrivate).isFalse()
|
||||
|
||||
result = parseResourceName("color/foo")
|
||||
assertThat(result).isNotNull()
|
||||
assertThat(result?.resourceName)
|
||||
.isEqualTo(ResourceName("", AaptResourceType.COLOR, "foo"))
|
||||
.isEqualTo(ResourceName("", COLOR, "foo"))
|
||||
assertThat(result?.isPrivate).isFalse()
|
||||
|
||||
result = parseResourceName("*android:string/foo")
|
||||
assertThat(result).isNotNull()
|
||||
assertThat(result?.resourceName)
|
||||
.isEqualTo(ResourceName("android", AaptResourceType.STRING, "foo"))
|
||||
.isEqualTo(ResourceName("android", STRING, "foo"))
|
||||
assertThat(result?.isPrivate).isTrue()
|
||||
|
||||
result = parseResourceName("")
|
||||
@@ -49,7 +59,7 @@ class ResourceUtilsTest {
|
||||
val result = parseReference("@color/bar")
|
||||
assertThat(result).isNotNull()
|
||||
assertThat(result?.reference?.name)
|
||||
.isEqualTo(ResourceName("", AaptResourceType.COLOR, "bar"))
|
||||
.isEqualTo(ResourceName("", COLOR, "bar"))
|
||||
assertThat(result?.createNew).isFalse()
|
||||
assertThat(result?.reference?.isPrivate).isFalse()
|
||||
}
|
||||
@@ -59,7 +69,7 @@ class ResourceUtilsTest {
|
||||
val result = parseReference("@android:integer/foo")
|
||||
assertThat(result).isNotNull()
|
||||
assertThat(result?.reference?.name)
|
||||
.isEqualTo(ResourceName("android", AaptResourceType.INTEGER, "foo"))
|
||||
.isEqualTo(ResourceName("android", INTEGER, "foo"))
|
||||
assertThat(result?.createNew).isFalse()
|
||||
assertThat(result?.reference?.isPrivate).isFalse()
|
||||
}
|
||||
@@ -69,7 +79,7 @@ class ResourceUtilsTest {
|
||||
val result = parseReference("\t @android:integer/foo\n \n\t")
|
||||
assertThat(result).isNotNull()
|
||||
assertThat(result?.reference?.name)
|
||||
.isEqualTo(ResourceName("android", AaptResourceType.INTEGER, "foo"))
|
||||
.isEqualTo(ResourceName("android", INTEGER, "foo"))
|
||||
assertThat(result?.createNew).isFalse()
|
||||
assertThat(result?.reference?.isPrivate).isFalse()
|
||||
}
|
||||
@@ -79,7 +89,7 @@ class ResourceUtilsTest {
|
||||
val result = parseReference("@+android:id/foo")
|
||||
assertThat(result).isNotNull()
|
||||
assertThat(result?.reference?.name)
|
||||
.isEqualTo(ResourceName("android", AaptResourceType.ID, "foo"))
|
||||
.isEqualTo(ResourceName("android", ID, "foo"))
|
||||
assertThat(result?.createNew).isTrue()
|
||||
assertThat(result?.reference?.isPrivate).isFalse()
|
||||
}
|
||||
@@ -89,7 +99,7 @@ class ResourceUtilsTest {
|
||||
val result = parseReference("@*android:id/foo")
|
||||
assertThat(result).isNotNull()
|
||||
assertThat(result?.reference?.name)
|
||||
.isEqualTo(ResourceName("android", AaptResourceType.ID, "foo"))
|
||||
.isEqualTo(ResourceName("android", ID, "foo"))
|
||||
assertThat(result?.createNew).isFalse()
|
||||
assertThat(result?.reference?.isPrivate).isTrue()
|
||||
}
|
||||
@@ -128,29 +138,29 @@ class ResourceUtilsTest {
|
||||
@Test
|
||||
fun testEmptyIsBinaryPrimitive() {
|
||||
assertThat(makeEmpty())
|
||||
.isEqualTo(BinaryPrimitive(ResValue(ResValue.DataType.NULL, ResValue.NullFormat.EMPTY)))
|
||||
.isEqualTo(BinaryPrimitive(ResValue(NULL, NullFormat.EMPTY)))
|
||||
assertThat(tryParseNullOrEmpty("@empty"))
|
||||
.isEqualTo(BinaryPrimitive(ResValue(ResValue.DataType.NULL, ResValue.NullFormat.EMPTY)))
|
||||
.isEqualTo(BinaryPrimitive(ResValue(NULL, NullFormat.EMPTY)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testItemsWithWhitespaceAreParsedCorrectly() {
|
||||
var result =
|
||||
tryParseItemForAttribute(" 12\n ", Resources.Attribute.FormatFlags.INTEGER_VALUE)
|
||||
tryParseItemForAttribute(" 12\n ", FormatFlags.INTEGER_VALUE)
|
||||
assertThat(result).isNotNull()
|
||||
assertThat(result)
|
||||
.isEqualTo(BinaryPrimitive(ResValue(ResValue.DataType.INT_DEC, 12)))
|
||||
.isEqualTo(BinaryPrimitive(ResValue(INT_DEC, 12)))
|
||||
result =
|
||||
tryParseItemForAttribute(" true\n ", Resources.Attribute.FormatFlags.BOOLEAN_VALUE)
|
||||
tryParseItemForAttribute(" true\n ", FormatFlags.BOOLEAN_VALUE)
|
||||
assertThat(result).isNotNull()
|
||||
assertThat(result)
|
||||
.isEqualTo(BinaryPrimitive(ResValue(ResValue.DataType.INT_BOOLEAN, -1)))
|
||||
.isEqualTo(BinaryPrimitive(ResValue(INT_BOOLEAN, -1)))
|
||||
|
||||
val expectedFloat = 12.0f
|
||||
result =
|
||||
tryParseItemForAttribute(" 12.0\n ", Resources.Attribute.FormatFlags.FLOAT_VALUE)
|
||||
tryParseItemForAttribute(" 12.0\n ", FormatFlags.FLOAT_VALUE)
|
||||
assertThat(result).isNotNull()
|
||||
assertThat(result)
|
||||
.isEqualTo(BinaryPrimitive(ResValue(ResValue.DataType.FLOAT, expectedFloat.toRawBits())))
|
||||
.isEqualTo(BinaryPrimitive(ResValue(FLOAT, expectedFloat.toRawBits())))
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.android.aaptcompiler
|
||||
|
||||
import com.android.aaptcompiler.android.ResValue
|
||||
import com.android.aapt.Resources
|
||||
import com.android.aaptcompiler.AaptResourceType.RAW
|
||||
import com.itsaky.androidide.layoutlib.resources.ResourceVisibility
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Assert.assertThrows
|
||||
@@ -573,7 +574,7 @@ class TableExtractorTest {
|
||||
val nullRef = getValue("integer/foo") as? Reference
|
||||
assertThat(nullRef).isNotNull()
|
||||
nullRef!!
|
||||
assertThat(nullRef.name).isEqualTo(ResourceName("", AaptResourceType.RAW, ""))
|
||||
assertThat(nullRef.name).isEqualTo(ResourceName("", RAW, ""))
|
||||
assertThat(nullRef.id).isNull()
|
||||
assertThat(nullRef.referenceType).isEqualTo(Reference.Type.RESOURCE)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aaptcompiler.ResourceFile.Type.ProtoXml
|
||||
import com.android.aaptcompiler.testutils.parseNameOrFail
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
@@ -41,7 +42,8 @@ class XmlProcessorTest {
|
||||
parseNameOrFail("layout/test"),
|
||||
parse(configDescription),
|
||||
Source(""),
|
||||
ResourceFile.Type.ProtoXml)
|
||||
ProtoXml
|
||||
)
|
||||
try {
|
||||
processor.process(file, input.byteInputStream())
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aaptcompiler.ResourceFile.Type.ProtoXml
|
||||
import com.android.aaptcompiler.testutils.parseNameOrFail
|
||||
import com.google.common.truth.Truth
|
||||
import org.junit.Test
|
||||
@@ -10,7 +11,8 @@ class XmlResourceBuilderTest {
|
||||
parseNameOrFail("layout/foo"),
|
||||
ConfigDescription(),
|
||||
Source(""),
|
||||
ResourceFile.Type.ProtoXml)
|
||||
ProtoXml
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testBasicXmlFlattening() {
|
||||
|
||||
+167
-75
@@ -2,9 +2,8 @@ package com.android.aaptcompiler.android
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import org.junit.Test
|
||||
import java.lang.AssertionError
|
||||
|
||||
class ResTable_configTest {
|
||||
class ResTableConfigTest {
|
||||
|
||||
@Test
|
||||
fun testBlockMethods() {
|
||||
@@ -35,7 +34,8 @@ class ResTable_configTest {
|
||||
// screenConfig2 block
|
||||
0x2d2e2f30.hostToDevice(),
|
||||
// localeNumberSystem block
|
||||
byteArrayOf(0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38))
|
||||
byteArrayOf(0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38)
|
||||
)
|
||||
|
||||
Truth.assertThat(config.size).isEqualTo(52)
|
||||
// Blocks are Little Endian and therefore the lower bits come first in the block. In other words
|
||||
@@ -107,7 +107,8 @@ class ResTable_configTest {
|
||||
}
|
||||
|
||||
private fun matchTestUnequal(
|
||||
default: ResTableConfig, first: ResTableConfig, second: ResTableConfig) {
|
||||
default: ResTableConfig, first: ResTableConfig, second: ResTableConfig
|
||||
) {
|
||||
// Default should match everything.
|
||||
Truth.assertThat(default.match(first)).isTrue()
|
||||
Truth.assertThat(default.match(second)).isTrue()
|
||||
@@ -123,7 +124,8 @@ class ResTable_configTest {
|
||||
}
|
||||
|
||||
private fun matchTestOneWay(
|
||||
default: ResTableConfig, matches: ResTableConfig, noMatch: ResTableConfig) {
|
||||
default: ResTableConfig, matches: ResTableConfig, noMatch: ResTableConfig
|
||||
) {
|
||||
// Default should match everything.
|
||||
Truth.assertThat(default.match(matches)).isTrue()
|
||||
Truth.assertThat(default.match(noMatch)).isTrue()
|
||||
@@ -177,7 +179,8 @@ class ResTable_configTest {
|
||||
// test that having multiple specified layout values doesn't interfere with matching.
|
||||
val screenLayout = ResTableConfig(
|
||||
screenLayout = (ResTableConfig.SCREEN_LAYOUT.SIZE_LARGE.toInt() or
|
||||
ResTableConfig.SCREEN_LAYOUT.SCREENLONG_YES.toInt()).toByte())
|
||||
ResTableConfig.SCREEN_LAYOUT.SCREENLONG_YES.toInt()).toByte()
|
||||
)
|
||||
|
||||
Truth.assertThat(screenSize1.match(screenLayout)).isTrue()
|
||||
Truth.assertThat(screenLayout.match(screenSize1)).isFalse()
|
||||
@@ -196,7 +199,8 @@ class ResTable_configTest {
|
||||
|
||||
val uiMode = ResTableConfig(
|
||||
uiMode = (ResTableConfig.UI_MODE.NIGHT_YES.toInt() or
|
||||
ResTableConfig.UI_MODE.TYPE_APPLIANCE.toInt()).toByte())
|
||||
ResTableConfig.UI_MODE.TYPE_APPLIANCE.toInt()).toByte()
|
||||
)
|
||||
|
||||
// test that having multiple specified uiMode values doesn't interfere with matching.
|
||||
Truth.assertThat(uiType2.match(uiMode)).isTrue()
|
||||
@@ -223,7 +227,8 @@ class ResTable_configTest {
|
||||
|
||||
val colorMode = ResTableConfig(
|
||||
colorMode = (ResTableConfig.COLOR_MODE.HDR_NO.toInt() or
|
||||
ResTableConfig.COLOR_MODE.WIDE_GAMUT_YES.toInt()).toByte())
|
||||
ResTableConfig.COLOR_MODE.WIDE_GAMUT_YES.toInt()).toByte()
|
||||
)
|
||||
|
||||
// test that having multiple specified colorMode values doesn't interfere with matching.
|
||||
Truth.assertThat(hdr2.match(colorMode)).isTrue()
|
||||
@@ -319,19 +324,24 @@ class ResTable_configTest {
|
||||
@Test
|
||||
fun testLocaleIsMoreSpecificThan() {
|
||||
val default = ResTableConfig()
|
||||
val languageOnly = ResTableConfig(language = byteArrayOf('e'.toByte(), 'n'.toByte()))
|
||||
val countryOnly = ResTableConfig(country = byteArrayOf('U'.toByte(), 'S'.toByte()))
|
||||
val languageOnly = ResTableConfig(language = byteArrayOf('e'.code.toByte(), 'n'.code.toByte()))
|
||||
val countryOnly = ResTableConfig(country = byteArrayOf('U'.code.toByte(), 'S'.code.toByte()))
|
||||
val languageAndCountry = ResTableConfig(
|
||||
language = byteArrayOf('e'.toByte(), 'n'.toByte()),
|
||||
country = byteArrayOf('U'.toByte(), 'S'.toByte()))
|
||||
language = byteArrayOf('e'.code.toByte(), 'n'.code.toByte()),
|
||||
country = byteArrayOf('U'.code.toByte(), 'S'.code.toByte())
|
||||
)
|
||||
val localeVariant = ResTableConfig(
|
||||
localeVariant = byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08))
|
||||
localeVariant = byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08)
|
||||
)
|
||||
val scriptComputed = ResTableConfig(
|
||||
localeScriptWasComputed = true, localeScript = byteArrayOf(0x01, 0x02, 0x03, 0x04))
|
||||
localeScriptWasComputed = true, localeScript = byteArrayOf(0x01, 0x02, 0x03, 0x04)
|
||||
)
|
||||
val localeScript = ResTableConfig(
|
||||
localeScript = byteArrayOf(0x01, 0x02, 0x03, 0x04))
|
||||
localeScript = byteArrayOf(0x01, 0x02, 0x03, 0x04)
|
||||
)
|
||||
val numberingSystem = ResTableConfig(
|
||||
localeNumberSystem = byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08))
|
||||
localeNumberSystem = byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08)
|
||||
)
|
||||
|
||||
// configs are consistent with themselves.
|
||||
testLocaleSpecificityEqual(default, default)
|
||||
@@ -396,7 +406,7 @@ class ResTable_configTest {
|
||||
Truth.assertThat(config.isMoreSpecificThan(config)).isFalse()
|
||||
}
|
||||
|
||||
for (i in 0.until(greatestToLeast.size)) {
|
||||
for (i in greatestToLeast.indices) {
|
||||
for (j in (i + 1).until(greatestToLeast.size)) {
|
||||
val greater = greatestToLeast[i]
|
||||
val lesser = greatestToLeast[j]
|
||||
@@ -406,7 +416,8 @@ class ResTable_configTest {
|
||||
} catch (e: AssertionError) {
|
||||
throw AssertionError(
|
||||
"Failed with greater = \"$greater\" at index $i and lesser = \"$lesser\" at index $j.",
|
||||
e)
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -463,7 +474,8 @@ class ResTable_configTest {
|
||||
screenHeight,
|
||||
sdkVersion,
|
||||
minorVersion,
|
||||
default)
|
||||
default
|
||||
)
|
||||
}
|
||||
|
||||
private fun testLocaleCompareTransitive(vararg firstToLast: ResTableConfig) {
|
||||
@@ -472,7 +484,7 @@ class ResTable_configTest {
|
||||
Truth.assertThat(config.compareLocales(config)).isEqualTo(0)
|
||||
}
|
||||
|
||||
for (i in 0.until(firstToLast.size)) {
|
||||
for (i in firstToLast.indices) {
|
||||
for (j in (i + 1).until(firstToLast.size)) {
|
||||
val less = firstToLast[i]
|
||||
val more = firstToLast[j]
|
||||
@@ -481,7 +493,8 @@ class ResTable_configTest {
|
||||
Truth.assertThat(more.compareLocales(less)).isGreaterThan(0)
|
||||
} catch (e: AssertionError) {
|
||||
throw AssertionError(
|
||||
"Failed with less = \"$less\" at index $i and more = \"$more\" at index $j.", e)
|
||||
"Failed with less = \"$less\" at index $i and more = \"$more\" at index $j.", e
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -493,41 +506,56 @@ class ResTable_configTest {
|
||||
val defaultWithVariant = ResTableConfig(localeVariant = byteArrayOf(1, 2, 3, 4, 5, 6, 7, 8))
|
||||
val localeNoCountry1 = ResTableConfig(language = ResTableConfig.ENGLISH)
|
||||
val localeNoCountryWithScript1 = ResTableConfig(
|
||||
language = ResTableConfig.ENGLISH, localeScript = byteArrayOf(1, 2, 3, 4))
|
||||
language = ResTableConfig.ENGLISH, localeScript = byteArrayOf(1, 2, 3, 4)
|
||||
)
|
||||
val localeNoCountryWithScript2 = ResTableConfig(
|
||||
language = ResTableConfig.ENGLISH, localeScript = byteArrayOf(1, 2, 3, 5))
|
||||
val localeNoCountry2 = ResTableConfig(language = byteArrayOf('f'.toByte(), 'r'.toByte()))
|
||||
language = ResTableConfig.ENGLISH, localeScript = byteArrayOf(1, 2, 3, 5)
|
||||
)
|
||||
val localeNoCountry2 = ResTableConfig(
|
||||
language = byteArrayOf(
|
||||
'f'.code.toByte(),
|
||||
'r'.code.toByte()
|
||||
)
|
||||
)
|
||||
val localeNoCountryWithScript3 = ResTableConfig(
|
||||
language = byteArrayOf('f'.toByte(), 'r'.toByte()), localeScript = byteArrayOf(1, 2, 3, 4))
|
||||
language = byteArrayOf('f'.code.toByte(), 'r'.code.toByte()),
|
||||
localeScript = byteArrayOf(1, 2, 3, 4)
|
||||
)
|
||||
val localeNoLang = ResTableConfig(country = ResTableConfig.UNITED_STATES)
|
||||
val localeBasic = ResTableConfig(
|
||||
language = ResTableConfig.ENGLISH, country = ResTableConfig.UNITED_STATES)
|
||||
language = ResTableConfig.ENGLISH, country = ResTableConfig.UNITED_STATES
|
||||
)
|
||||
val localeBasicWithScript = ResTableConfig(
|
||||
language = ResTableConfig.ENGLISH,
|
||||
country = ResTableConfig.UNITED_STATES,
|
||||
localeScript = byteArrayOf(1, 2, 3, 4))
|
||||
localeScript = byteArrayOf(1, 2, 3, 4)
|
||||
)
|
||||
val localeBasicWithScriptAndVariant = ResTableConfig(
|
||||
language = ResTableConfig.ENGLISH,
|
||||
country = ResTableConfig.UNITED_STATES,
|
||||
localeScript = byteArrayOf(1, 2, 3, 4),
|
||||
localeVariant = byteArrayOf(1, 2, 3, 4, 5, 6, 7, 8))
|
||||
localeVariant = byteArrayOf(1, 2, 3, 4, 5, 6, 7, 8)
|
||||
)
|
||||
val localeBasicWithScriptAndVariant2 = ResTableConfig(
|
||||
language = ResTableConfig.ENGLISH,
|
||||
country = ResTableConfig.UNITED_STATES,
|
||||
localeScript = byteArrayOf(1, 2, 3, 4),
|
||||
localeVariant = byteArrayOf(11, 12, 13, 14, 15, 16, 17, 18))
|
||||
localeVariant = byteArrayOf(11, 12, 13, 14, 15, 16, 17, 18)
|
||||
)
|
||||
val localeBasicWithScriptVariantAndNumberSystem = ResTableConfig(
|
||||
language = ResTableConfig.ENGLISH,
|
||||
country = ResTableConfig.UNITED_STATES,
|
||||
localeScript = byteArrayOf(1, 2, 3, 4),
|
||||
localeVariant = byteArrayOf(11, 12, 13, 14, 15, 16, 17, 18),
|
||||
localeNumberSystem = byteArrayOf(1, 2, 3, 4, 5, 6, 7, 8))
|
||||
localeNumberSystem = byteArrayOf(1, 2, 3, 4, 5, 6, 7, 8)
|
||||
)
|
||||
val localeBasicWithScriptVariantAndNumberSystem2 = ResTableConfig(
|
||||
language = ResTableConfig.ENGLISH,
|
||||
country = ResTableConfig.UNITED_STATES,
|
||||
localeScript = byteArrayOf(1, 2, 3, 4),
|
||||
localeVariant = byteArrayOf(11, 12, 13, 14, 15, 16, 17, 18),
|
||||
localeNumberSystem = byteArrayOf(11, 12, 13, 14, 15, 16, 17, 18))
|
||||
localeNumberSystem = byteArrayOf(11, 12, 13, 14, 15, 16, 17, 18)
|
||||
)
|
||||
|
||||
testLocaleCompareTransitive(
|
||||
default,
|
||||
@@ -543,14 +571,16 @@ class ResTable_configTest {
|
||||
localeBasicWithScriptAndVariant,
|
||||
localeBasicWithScriptAndVariant2,
|
||||
localeBasicWithScriptVariantAndNumberSystem,
|
||||
localeBasicWithScriptVariantAndNumberSystem2)
|
||||
localeBasicWithScriptVariantAndNumberSystem2
|
||||
)
|
||||
|
||||
// Ensure computed scripts do not affect results.
|
||||
val localeBasicWithComputedScript = ResTableConfig(
|
||||
language = ResTableConfig.ENGLISH,
|
||||
country = ResTableConfig.UNITED_STATES,
|
||||
localeScriptWasComputed = true,
|
||||
localeScript = byteArrayOf(1, 2, 3, 4))
|
||||
localeScript = byteArrayOf(1, 2, 3, 4)
|
||||
)
|
||||
Truth.assertThat(localeBasic.compareLocales(localeBasicWithComputedScript)).isEqualTo(0)
|
||||
}
|
||||
|
||||
@@ -560,7 +590,7 @@ class ResTable_configTest {
|
||||
Truth.assertThat(config.compareTo(config)).isEqualTo(0)
|
||||
}
|
||||
|
||||
for (i in 0.until(firstToLast.size)) {
|
||||
for (i in firstToLast.indices) {
|
||||
for (j in (i + 1).until(firstToLast.size)) {
|
||||
val less = firstToLast[i]
|
||||
val more = firstToLast[j]
|
||||
@@ -569,7 +599,8 @@ class ResTable_configTest {
|
||||
Truth.assertThat(more.compareTo(less)).isGreaterThan(0)
|
||||
} catch (e: AssertionError) {
|
||||
throw AssertionError(
|
||||
"Failed with less = \"$less\" at index $i and more = \"$more\" at index $j.", e)
|
||||
"Failed with less = \"$less\" at index $i and more = \"$more\" at index $j.", e
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -585,7 +616,8 @@ class ResTable_configTest {
|
||||
val uiMode = ResTableConfig(uiMode = ResTableConfig.UI_MODE.NIGHT_YES)
|
||||
val colorMode = ResTableConfig(colorMode = ResTableConfig.COLOR_MODE.WIDE_GAMUT_NO)
|
||||
val screenLayout2 = ResTableConfig(
|
||||
screenLayout2 = ResTableConfig.SCREEN_LAYOUT2.SCREENROUND_YES)
|
||||
screenLayout2 = ResTableConfig.SCREEN_LAYOUT2.SCREENROUND_YES
|
||||
)
|
||||
val screenLayout = ResTableConfig(screenLayout = ResTableConfig.SCREEN_LAYOUT.SIZE_LARGE)
|
||||
val version = ResTableConfig(sdkVersion = 22)
|
||||
val screenSize = ResTableConfig(screenWidth = 480, screenHeight = 320)
|
||||
@@ -612,7 +644,8 @@ class ResTable_configTest {
|
||||
screenType,
|
||||
screenType2,
|
||||
locale,
|
||||
imsi)
|
||||
imsi
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -624,7 +657,8 @@ class ResTable_configTest {
|
||||
sdkVersion = 23,
|
||||
screenWidth = 480,
|
||||
screenHeight = 640,
|
||||
screenLayout = ResTableConfig.SCREEN_LAYOUT.SIZE_LARGE)
|
||||
screenLayout = ResTableConfig.SCREEN_LAYOUT.SIZE_LARGE
|
||||
)
|
||||
|
||||
Truth.assertThat(default.diff(default)).isEqualTo(0)
|
||||
Truth.assertThat(first.diff(first)).isEqualTo(0)
|
||||
@@ -682,14 +716,15 @@ class ResTable_configTest {
|
||||
}
|
||||
|
||||
private fun isBetterLocaleTransitive(
|
||||
requested: ResTableConfig, vararg leastToGreatest: ResTableConfig) {
|
||||
requested: ResTableConfig, vararg leastToGreatest: ResTableConfig
|
||||
) {
|
||||
|
||||
for (config in leastToGreatest) {
|
||||
// no config is better than itself.
|
||||
Truth.assertThat(config.isLocaleBetterThan(config, requested)).isFalse()
|
||||
}
|
||||
|
||||
for (i in 0.until(leastToGreatest.size)) {
|
||||
for (i in leastToGreatest.indices) {
|
||||
for (j in (i + 1).until(leastToGreatest.size)) {
|
||||
val worse = leastToGreatest[i]
|
||||
val better = leastToGreatest[j]
|
||||
@@ -698,7 +733,8 @@ class ResTable_configTest {
|
||||
Truth.assertThat(better.isLocaleBetterThan(worse, requested)).isTrue()
|
||||
} catch (e: AssertionError) {
|
||||
throw AssertionError(
|
||||
"Failed with worse = \"$worse\" at index $i and better = \"$better\" at index $j.", e)
|
||||
"Failed with worse = \"$worse\" at index $i and better = \"$better\" at index $j.", e
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -710,7 +746,8 @@ class ResTable_configTest {
|
||||
language = ResTableConfig.FILIPINO,
|
||||
country = byteArrayOf(1, 2),
|
||||
localeVariant = byteArrayOf(3, 4, 5, 6, 7, 8, 9, 10),
|
||||
localeNumberSystem = byteArrayOf(11, 12, 13, 14, 15, 16, 17, 18))
|
||||
localeNumberSystem = byteArrayOf(11, 12, 13, 14, 15, 16, 17, 18)
|
||||
)
|
||||
|
||||
val default = ResTableConfig()
|
||||
val country = ResTableConfig(country = byteArrayOf(1, 2))
|
||||
@@ -721,16 +758,19 @@ class ResTable_configTest {
|
||||
val localeNumberSystem = ResTableConfig(
|
||||
language = ResTableConfig.FILIPINO,
|
||||
country = byteArrayOf(1, 2),
|
||||
localeNumberSystem = byteArrayOf(11, 12, 13, 14, 15, 16, 17, 18))
|
||||
localeNumberSystem = byteArrayOf(11, 12, 13, 14, 15, 16, 17, 18)
|
||||
)
|
||||
val localeVariant = ResTableConfig(
|
||||
language = ResTableConfig.FILIPINO,
|
||||
country = byteArrayOf(1, 2),
|
||||
localeVariant = byteArrayOf(3, 4, 5, 6, 7, 8, 9, 10))
|
||||
localeVariant = byteArrayOf(3, 4, 5, 6, 7, 8, 9, 10)
|
||||
)
|
||||
val almostTotalMatch = ResTableConfig(
|
||||
language = ResTableConfig.TAGALOG,
|
||||
country = byteArrayOf(1, 2),
|
||||
localeVariant = byteArrayOf(3, 4, 5, 6, 7, 8, 9, 10),
|
||||
localeNumberSystem = byteArrayOf(11, 12, 13, 14, 15, 16, 17, 18))
|
||||
localeNumberSystem = byteArrayOf(11, 12, 13, 14, 15, 16, 17, 18)
|
||||
)
|
||||
|
||||
isBetterLocaleTransitive(
|
||||
requested,
|
||||
@@ -742,13 +782,15 @@ class ResTable_configTest {
|
||||
localeNumberSystem,
|
||||
localeVariant,
|
||||
almostTotalMatch,
|
||||
requested)
|
||||
requested
|
||||
)
|
||||
|
||||
// Test that if the locale variant doesn't match it doesn't count.
|
||||
val localeVariantFail = ResTableConfig(
|
||||
language = ResTableConfig.FILIPINO,
|
||||
country = byteArrayOf(1, 2),
|
||||
localeVariant = byteArrayOf(3, 4, 5, 6, 7, 8, 9, 11))
|
||||
localeVariant = byteArrayOf(3, 4, 5, 6, 7, 8, 9, 11)
|
||||
)
|
||||
|
||||
Truth.assertThat(localeVariantFail.isLocaleBetterThan(localeNumberSystem, requested)).isFalse()
|
||||
Truth.assertThat(localeNumberSystem.isLocaleBetterThan(localeVariantFail, requested)).isTrue()
|
||||
@@ -756,14 +798,15 @@ class ResTable_configTest {
|
||||
}
|
||||
|
||||
private fun isBetterTransitive(
|
||||
requested: ResTableConfig, vararg leastToGreatest: ResTableConfig) {
|
||||
requested: ResTableConfig, vararg leastToGreatest: ResTableConfig
|
||||
) {
|
||||
|
||||
for (config in leastToGreatest) {
|
||||
// no config is better than itself.
|
||||
Truth.assertThat(config.isBetterThan(config, requested)).isFalse()
|
||||
}
|
||||
|
||||
for (i in 0.until(leastToGreatest.size)) {
|
||||
for (i in leastToGreatest.indices) {
|
||||
for (j in (i + 1).until(leastToGreatest.size)) {
|
||||
val worse = leastToGreatest[i]
|
||||
val better = leastToGreatest[j]
|
||||
@@ -772,7 +815,8 @@ class ResTable_configTest {
|
||||
Truth.assertThat(better.isBetterThan(worse, requested)).isTrue()
|
||||
} catch (e: AssertionError) {
|
||||
throw AssertionError(
|
||||
"Failed with worse = \"$worse\" at index $i and better = \"$better\" at index $j.", e)
|
||||
"Failed with worse = \"$worse\" at index $i and better = \"$better\" at index $j.", e
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -807,7 +851,8 @@ class ResTable_configTest {
|
||||
// screenConfig2 block
|
||||
0xffffffff.toInt().hostToDevice(),
|
||||
// localeNumberSystem block
|
||||
byteArrayOf(0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38))
|
||||
byteArrayOf(0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38)
|
||||
)
|
||||
|
||||
val default = ResTableConfig()
|
||||
val minorVersion = ResTableConfig(minorVersion = requested.minorVersion)
|
||||
@@ -816,17 +861,21 @@ class ResTable_configTest {
|
||||
val sdkVersion2 = ResTableConfig(sdkVersion = requested.sdkVersion)
|
||||
val screenSize1 = ResTableConfig(screenWidth = requested.screenWidth)
|
||||
val screenSize2 = ResTableConfig(
|
||||
screenWidth = requested.screenWidth, screenHeight = requested.screenHeight)
|
||||
screenWidth = requested.screenWidth, screenHeight = requested.screenHeight
|
||||
)
|
||||
val navigation = ResTableConfig(navigation = requested.navigation)
|
||||
val keyboard = ResTableConfig(keyboard = requested.keyboard)
|
||||
val navHidden = ResTableConfig(
|
||||
inputFlags = (requested.inputFlags.toInt() and
|
||||
ResTableConfig.INPUT_FLAGS.NAVHIDDEN_MASK).toByte())
|
||||
ResTableConfig.INPUT_FLAGS.NAVHIDDEN_MASK).toByte()
|
||||
)
|
||||
val keysHiddenAlmostMatch = ResTableConfig(
|
||||
inputFlags = ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_NO)
|
||||
inputFlags = ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_NO
|
||||
)
|
||||
val keysHiddenMatch = ResTableConfig(
|
||||
inputFlags = (requested.inputFlags.toInt() and
|
||||
ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_MASK).toByte())
|
||||
ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_MASK).toByte()
|
||||
)
|
||||
val touchscreen = ResTableConfig(touchscreen = requested.touchscreen)
|
||||
// scaling up is worse than scaling down.
|
||||
val densityLow = ResTableConfig(density = requested.density - 20)
|
||||
@@ -834,37 +883,48 @@ class ResTable_configTest {
|
||||
val densityEqual = ResTableConfig(density = requested.density)
|
||||
val nightMode = ResTableConfig(
|
||||
uiMode = (requested.uiMode.toInt() and
|
||||
ResTableConfig.UI_MODE.NIGHT_MASK).toByte())
|
||||
ResTableConfig.UI_MODE.NIGHT_MASK).toByte()
|
||||
)
|
||||
val uiType = ResTableConfig(
|
||||
uiMode = (requested.uiMode.toInt() and
|
||||
ResTableConfig.UI_MODE.TYPE_MASK).toByte())
|
||||
ResTableConfig.UI_MODE.TYPE_MASK).toByte()
|
||||
)
|
||||
val orientation = ResTableConfig(orientation = requested.orientation)
|
||||
val hdr = ResTableConfig(
|
||||
colorMode = (requested.colorMode.toInt() and
|
||||
ResTableConfig.COLOR_MODE.HDR_MASK).toByte())
|
||||
ResTableConfig.COLOR_MODE.HDR_MASK).toByte()
|
||||
)
|
||||
val gamut = ResTableConfig(
|
||||
colorMode = (requested.colorMode.toInt() and
|
||||
ResTableConfig.COLOR_MODE.WIDE_GAMUT_MASK).toByte())
|
||||
ResTableConfig.COLOR_MODE.WIDE_GAMUT_MASK).toByte()
|
||||
)
|
||||
val round = ResTableConfig(
|
||||
screenLayout2 = (requested.screenLayout2.toInt() and
|
||||
ResTableConfig.SCREEN_LAYOUT2.SCREENROUND_MASK).toByte())
|
||||
ResTableConfig.SCREEN_LAYOUT2.SCREENROUND_MASK).toByte()
|
||||
)
|
||||
val long = ResTableConfig(
|
||||
screenLayout = (requested.screenLayout.toInt() and
|
||||
ResTableConfig.SCREEN_LAYOUT.SCREENLONG_MASK).toByte())
|
||||
ResTableConfig.SCREEN_LAYOUT.SCREENLONG_MASK).toByte()
|
||||
)
|
||||
val sizeFlag = ResTableConfig(
|
||||
screenLayout = (requested.screenLayout.toInt() and
|
||||
ResTableConfig.SCREEN_LAYOUT.SIZE_MASK).toByte())
|
||||
ResTableConfig.SCREEN_LAYOUT.SIZE_MASK).toByte()
|
||||
)
|
||||
val screenSizeDp1 = ResTableConfig(screenWidthDp = requested.screenWidthDp)
|
||||
val screenSizeDp2 = ResTableConfig(
|
||||
screenWidthDp = requested.screenWidthDp, screenHeightDp = requested.screenHeightDp)
|
||||
screenWidthDp = requested.screenWidthDp, screenHeightDp = requested.screenHeightDp
|
||||
)
|
||||
val smallestScreenWidth1 = ResTableConfig(
|
||||
smallestScreenWidthDp = requested.smallestScreenWidthDp - 20)
|
||||
smallestScreenWidthDp = requested.smallestScreenWidthDp - 20
|
||||
)
|
||||
// Closer to requested will match better.
|
||||
val smallestScreenWidth2 = ResTableConfig(
|
||||
smallestScreenWidthDp = requested.smallestScreenWidthDp)
|
||||
smallestScreenWidthDp = requested.smallestScreenWidthDp
|
||||
)
|
||||
val screenDir = ResTableConfig(
|
||||
screenLayout = (requested.screenLayout.toInt() and
|
||||
ResTableConfig.SCREEN_LAYOUT.DIR_MASK).toByte())
|
||||
ResTableConfig.SCREEN_LAYOUT.DIR_MASK).toByte()
|
||||
)
|
||||
val mnc = ResTableConfig(mnc = requested.mnc)
|
||||
val mcc = ResTableConfig(mcc = requested.mcc)
|
||||
|
||||
@@ -900,7 +960,8 @@ class ResTable_configTest {
|
||||
screenDir,
|
||||
mnc,
|
||||
mcc,
|
||||
requested)
|
||||
requested
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -924,17 +985,37 @@ class ResTable_configTest {
|
||||
val config5 =
|
||||
ResTableConfig(
|
||||
language = ResTableConfig.ENGLISH,
|
||||
localeScript = byteArrayOf('l'.toByte(), 'a'.toByte(), 't'.toByte(), 'n'.toByte()))
|
||||
localeScript = byteArrayOf(
|
||||
'l'.code.toByte(),
|
||||
'a'.code.toByte(),
|
||||
't'.code.toByte(),
|
||||
'n'.code.toByte()
|
||||
)
|
||||
)
|
||||
Truth.assertThat(config5.toString()).isEqualTo("b+en+latn")
|
||||
|
||||
val config6 =
|
||||
ResTableConfig(
|
||||
language = ResTableConfig.ENGLISH,
|
||||
country = ResTableConfig.UNITED_STATES,
|
||||
localeScript = byteArrayOf('l'.toByte(), 'a'.toByte(), 't'.toByte(), 'n'.toByte()),
|
||||
localeVariant = byteArrayOf('h'.toByte(), 'i'.toByte(), 0, 0, 0, 0, 0, 0),
|
||||
localeScript = byteArrayOf(
|
||||
'l'.code.toByte(),
|
||||
'a'.code.toByte(),
|
||||
't'.code.toByte(),
|
||||
'n'.code.toByte()
|
||||
),
|
||||
localeVariant = byteArrayOf('h'.code.toByte(), 'i'.code.toByte(), 0, 0, 0, 0, 0, 0),
|
||||
localeNumberSystem = byteArrayOf(
|
||||
't'.toByte(), 'h'.toByte(), 'e'.toByte(), 'r'.toByte(), 'e'.toByte(), 0, 0, 0))
|
||||
't'.code.toByte(),
|
||||
'h'.code.toByte(),
|
||||
'e'.code.toByte(),
|
||||
'r'.code.toByte(),
|
||||
'e'.code.toByte(),
|
||||
0,
|
||||
0,
|
||||
0
|
||||
)
|
||||
)
|
||||
Truth.assertThat(config6.toString()).isEqualTo("b+en+latn+US+hi+u+nu+there")
|
||||
|
||||
val config7 = ResTableConfig(screenWidth = 480, screenHeight = 640)
|
||||
@@ -969,16 +1050,27 @@ class ResTable_configTest {
|
||||
480,
|
||||
480,
|
||||
640,
|
||||
byteArrayOf('l'.toByte(), 'a'.toByte(), 't'.toByte(), 'n'.toByte()),
|
||||
byteArrayOf('h'.toByte(), 'i'.toByte(), 0, 0, 0, 0, 0, 0),
|
||||
byteArrayOf('l'.code.toByte(), 'a'.code.toByte(), 't'.code.toByte(), 'n'.code.toByte()),
|
||||
byteArrayOf('h'.code.toByte(), 'i'.code.toByte(), 0, 0, 0, 0, 0, 0),
|
||||
ResTableConfig.SCREEN_LAYOUT2.SCREENROUND_YES,
|
||||
(ResTableConfig.COLOR_MODE.HDR_YES.toInt() or
|
||||
ResTableConfig.COLOR_MODE.WIDE_GAMUT_YES.toInt()).toByte(),
|
||||
false,
|
||||
byteArrayOf('t'.toByte(), 'h'.toByte(), 'e'.toByte(), 'r'.toByte(), 'e'.toByte(), 0, 0, 0))
|
||||
byteArrayOf(
|
||||
't'.code.toByte(),
|
||||
'h'.code.toByte(),
|
||||
'e'.code.toByte(),
|
||||
'r'.code.toByte(),
|
||||
'e'.code.toByte(),
|
||||
0,
|
||||
0,
|
||||
0
|
||||
)
|
||||
)
|
||||
Truth.assertThat(config9.toString()).isEqualTo(
|
||||
"mcc310-mnc100-b+en+latn+US+hi+u+nu+there-feminine-ldltr-sw480dp-w480dp-h640dp-large-" +
|
||||
"long-round-widecg-highdr-land-desk-notnight-xxhdpi-finger-keyssoft-qwerty-navhidden-dpad-" +
|
||||
"v13.2")
|
||||
"v13.2"
|
||||
)
|
||||
}
|
||||
}
|
||||
+25
-11
@@ -1,6 +1,7 @@
|
||||
package com.android.aaptcompiler.proto
|
||||
|
||||
import com.android.aapt.Resources
|
||||
import com.android.aapt.Resources.Attribute.FormatFlags
|
||||
import com.android.aaptcompiler.ArrayResource
|
||||
import com.android.aaptcompiler.AttributeResource
|
||||
import com.android.aaptcompiler.BasicString
|
||||
@@ -25,6 +26,10 @@ import com.android.aaptcompiler.StyledString
|
||||
import com.android.aaptcompiler.Visibility
|
||||
import com.android.aaptcompiler.android.ResStringPool
|
||||
import com.android.aaptcompiler.android.ResValue
|
||||
import com.android.aaptcompiler.android.ResValue.DataType.INT_DEC
|
||||
import com.android.aaptcompiler.android.ResValue.DataType.INT_HEX
|
||||
import com.android.aaptcompiler.android.ResValue.DataType.NULL
|
||||
import com.android.aaptcompiler.android.ResValue.NullFormat
|
||||
import com.android.aaptcompiler.buffer.BigBuffer
|
||||
import com.android.aaptcompiler.getValue
|
||||
import com.android.aaptcompiler.makeEmpty
|
||||
@@ -237,7 +242,8 @@ class ProtoSerializeTest {
|
||||
testSerializeDeserialize(tryParseBool("true")!!)
|
||||
// Null type
|
||||
testSerializeDeserialize(
|
||||
BinaryPrimitive(ResValue(ResValue.DataType.NULL, ResValue.NullFormat.UNDEFINED)))
|
||||
BinaryPrimitive(ResValue(NULL, NullFormat.UNDEFINED))
|
||||
)
|
||||
// Empty type
|
||||
testSerializeDeserialize(tryParseNullOrEmpty("@empty") as BinaryPrimitive)
|
||||
// Int types
|
||||
@@ -372,7 +378,8 @@ class ProtoSerializeTest {
|
||||
originalPool.makeRef(
|
||||
StyleString(
|
||||
"Hello World!",
|
||||
listOf(Span("b", 0, 4), Span("i", 6, 10)))),
|
||||
listOf(Span("b", 0, 4), Span("i", 6, 10)))
|
||||
),
|
||||
listOf()),
|
||||
newPool)
|
||||
|
||||
@@ -396,7 +403,8 @@ class ProtoSerializeTest {
|
||||
overlayable,
|
||||
OverlayableItem.Policy.SYSTEM or OverlayableItem.Policy.PRODUCT,
|
||||
"comment",
|
||||
Source("res/values/overlayable.xml", 19))
|
||||
Source("res/values/overlayable.xml", 19)
|
||||
)
|
||||
|
||||
val overlayableItem2 = OverlayableItem(overlayable)
|
||||
|
||||
@@ -419,10 +427,10 @@ class ProtoSerializeTest {
|
||||
|
||||
@Test
|
||||
fun testAttrSerialization() {
|
||||
val emptyAttribute = AttributeResource(Resources.Attribute.FormatFlags.ENUM_VALUE)
|
||||
val emptyAttribute = AttributeResource(FormatFlags.ENUM_VALUE)
|
||||
testSerializeDeserialize(emptyAttribute)
|
||||
|
||||
val attributeExample = AttributeResource(Resources.Attribute.FormatFlags.FLAGS_VALUE)
|
||||
val attributeExample = AttributeResource(FormatFlags.FLAGS_VALUE)
|
||||
attributeExample.minInt = 0
|
||||
attributeExample.maxInt = 1 shl 16
|
||||
|
||||
@@ -457,14 +465,16 @@ class ProtoSerializeTest {
|
||||
styleExampleNoParent.entries.add(
|
||||
Style.Entry(
|
||||
Reference(parseResourceName("android:string/foo")!!.resourceName),
|
||||
BasicString(oldPool.makeRef("Hello there!"))))
|
||||
BasicString(oldPool.makeRef("Hello there!"))
|
||||
))
|
||||
val keyReference = Reference(parseResourceName("android:bool/bar")!!.resourceName)
|
||||
keyReference.source = Source("res/values/style.xml", 30)
|
||||
keyReference.comment = "Whether or not the bar state can be active."
|
||||
styleExampleNoParent.entries.add(
|
||||
Style.Entry(
|
||||
keyReference,
|
||||
tryParseBool("true")))
|
||||
tryParseBool("true")
|
||||
))
|
||||
|
||||
testSerializeDeserialize(styleExampleNoParent, newPool)
|
||||
Truth.assertThat(newPool.size()).isEqualTo(1)
|
||||
@@ -567,7 +577,8 @@ class ProtoSerializeTest {
|
||||
parseNameOrFail("com.app.a:string/styled"),
|
||||
ConfigDescription(),
|
||||
"",
|
||||
StyledString(table.stringPool.makeRef(styleString), listOf()))).isTrue()
|
||||
StyledString(table.stringPool.makeRef(styleString), listOf())
|
||||
)).isTrue()
|
||||
|
||||
// Make a resource with different products.
|
||||
Truth.assertThat(
|
||||
@@ -575,13 +586,15 @@ class ProtoSerializeTest {
|
||||
parseNameOrFail("com.app.a:integer/one"),
|
||||
parse("land"),
|
||||
"",
|
||||
BinaryPrimitive(ResValue(ResValue.DataType.INT_DEC, 123)))).isTrue()
|
||||
BinaryPrimitive(ResValue(INT_DEC, 123))
|
||||
)).isTrue()
|
||||
Truth.assertThat(
|
||||
table.addResource(
|
||||
parseNameOrFail("com.app.a:integer/one"),
|
||||
parse("land"),
|
||||
"tablet",
|
||||
BinaryPrimitive(ResValue(ResValue.DataType.INT_HEX, 321)))).isTrue()
|
||||
BinaryPrimitive(ResValue(INT_HEX, 321))
|
||||
)).isTrue()
|
||||
|
||||
// Make a reference with both resource name and resource ID.
|
||||
// The reference should point to a resource outside of this table to test that both name and id
|
||||
@@ -595,7 +608,8 @@ class ProtoSerializeTest {
|
||||
// Make an overlayable resource.
|
||||
val overlayableItem = OverlayableItem(
|
||||
Overlayable("OverlayableName", "overlay://theme", Source("res/values/overlayable.xml", 40)),
|
||||
source = Source("res/values/overlayable.xml", 42))
|
||||
source = Source("res/values/overlayable.xml", 42)
|
||||
)
|
||||
Truth.assertThat(
|
||||
table.setOverlayable(
|
||||
parseNameOrFail("com.app.a:integer/overlayable"), overlayableItem)).isTrue()
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.itsaky.androidide.aaptcompiler
|
||||
import com.android.aaptcompiler.BlameLogger
|
||||
import com.android.aaptcompiler.ResourceCompilerOptions
|
||||
import com.android.aaptcompiler.ResourceFile
|
||||
import com.android.aaptcompiler.ResourceFile.Type.ProtoXml
|
||||
import com.android.aaptcompiler.ResourceName
|
||||
import com.android.aaptcompiler.XmlProcessor
|
||||
import com.android.aaptcompiler.compileResource
|
||||
@@ -27,11 +28,11 @@ import com.android.aaptcompiler.extractPathData
|
||||
import com.android.utils.StdLogger
|
||||
import com.android.utils.StdLogger.Level.VERBOSE
|
||||
import com.itsaky.androidide.utils.FileProvider
|
||||
import java.nio.file.Paths
|
||||
import kotlin.io.path.absolute
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import java.nio.file.Paths
|
||||
import kotlin.io.path.absolute
|
||||
|
||||
/** @author Akash Yadav */
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@@ -40,7 +41,8 @@ class CompilerTest {
|
||||
@Test
|
||||
fun `test simple compilatation`() {
|
||||
val input =
|
||||
FileProvider.projectRoot().resolve("core/app/src/main/res/layout/activity_editor.xml").toFile()
|
||||
FileProvider.projectRoot().resolve("core/app/src/main/res/layout/activity_editor.xml")
|
||||
.toFile()
|
||||
val output = Paths.get("./build").absolute().normalize().toFile()
|
||||
println(input)
|
||||
println(output)
|
||||
@@ -53,13 +55,14 @@ class CompilerTest {
|
||||
@Test
|
||||
fun `test xml processor`() {
|
||||
val input =
|
||||
Paths.get(".", "src/test/resources/layout/activity_editor.xml").absolute().normalize().toFile()
|
||||
Paths.get(".", "src/test/resources/layout/activity_editor.xml").absolute().normalize()
|
||||
.toFile()
|
||||
val pathData = extractPathData(input, input.absolutePath)
|
||||
val resFile = ResourceFile(
|
||||
ResourceName("", pathData.type!!, pathData.name),
|
||||
pathData.config,
|
||||
pathData.source,
|
||||
ResourceFile.Type.ProtoXml
|
||||
ProtoXml
|
||||
)
|
||||
val processor = XmlProcessor(pathData.source, BlameLogger(StdLogger(VERBOSE)))
|
||||
processor.process(resFile, input.inputStream().buffered())
|
||||
|
||||
@@ -22,8 +22,6 @@ plugins {
|
||||
id("org.jetbrains.kotlin.jvm")
|
||||
}
|
||||
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation(projects.utilities.shared)
|
||||
implementation(libs.composite.jaxp)
|
||||
|
||||
@@ -27,7 +27,7 @@ plugins {
|
||||
|
||||
|
||||
android {
|
||||
namespace = "${BuildConfig.packageName}.lsp.xml"
|
||||
namespace = "${BuildConfig.packageName}.xml.lsp"
|
||||
}
|
||||
|
||||
kapt {
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.itsaky.androidide.lsp.models.CodeFormatResult;
|
||||
import com.itsaky.androidide.lsp.models.FormatCodeParams;
|
||||
import com.itsaky.androidide.lsp.xml.providers.format.XMLFormatter;
|
||||
import com.itsaky.androidide.utils.StopWatch;
|
||||
|
||||
import org.eclipse.lemminx.dom.DOMParser;
|
||||
import org.eclipse.lemminx.uriresolver.URIResolverExtensionManager;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
+13
-14
@@ -19,10 +19,7 @@ package com.itsaky.androidide.lsp.xml.providers.completion
|
||||
|
||||
import com.android.aaptcompiler.AaptResourceType.STYLEABLE
|
||||
import com.android.aaptcompiler.ConfigDescription
|
||||
import com.android.aaptcompiler.Reference
|
||||
import com.android.aaptcompiler.ResourceGroup
|
||||
import com.android.aaptcompiler.ResourcePathData
|
||||
import com.android.aaptcompiler.ResourceTablePackage
|
||||
import com.android.aaptcompiler.Styleable
|
||||
import com.itsaky.androidide.lookup.Lookup
|
||||
import com.itsaky.androidide.lsp.api.ICompletionProvider
|
||||
@@ -32,6 +29,8 @@ import com.itsaky.androidide.lsp.models.CompletionResult
|
||||
import com.itsaky.androidide.lsp.models.MatchLevel.NO_MATCH
|
||||
import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType
|
||||
import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType.ATTRIBUTE
|
||||
import com.itsaky.androidide.xml.res.IResourceGroup
|
||||
import com.itsaky.androidide.xml.res.IResourceTablePackage
|
||||
import com.itsaky.androidide.xml.widgets.Widget
|
||||
import com.itsaky.androidide.xml.widgets.WidgetTable
|
||||
import org.eclipse.lemminx.dom.DOMDocument
|
||||
@@ -108,7 +107,7 @@ open class AttrCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
|
||||
val pck = namespace.substringAfter(NAMESPACE_PREFIX)
|
||||
val packages = mutableSetOf<ResourceTablePackage>()
|
||||
val packages = mutableSetOf<IResourceTablePackage>()
|
||||
for (table in tables) {
|
||||
if (namespace == NAMESPACE_AUTO) {
|
||||
packages.addAll(table.packages.filter { it.name.isNotBlank() })
|
||||
@@ -124,7 +123,7 @@ open class AttrCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
|
||||
protected open fun addFromPackage(
|
||||
tablePackage: ResourceTablePackage?,
|
||||
tablePackage: IResourceTablePackage?,
|
||||
node: DOMNode,
|
||||
pck: String,
|
||||
nsPrefix: String,
|
||||
@@ -173,11 +172,11 @@ open class AttrCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun hasAttr(prefix: String, ref: Reference): Boolean {
|
||||
protected open fun hasAttr(prefix: String, ref: com.android.aaptcompiler.Reference): Boolean {
|
||||
return this.nodeAtCursor.hasAttribute("${prefix}:${ref.name.entry}")
|
||||
}
|
||||
|
||||
protected open fun findNodeStyleables(node: DOMNode, styleables: ResourceGroup): Set<Styleable> {
|
||||
protected open fun findNodeStyleables(node: DOMNode, styleables: IResourceGroup): Set<Styleable> {
|
||||
val nodeName = node.nodeName
|
||||
val widgets = Lookup.getDefault().lookup(WidgetTable.COMPLETION_LOOKUP_KEY) ?: return emptySet()
|
||||
|
||||
@@ -205,7 +204,7 @@ open class AttrCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
|
||||
protected open fun findStyleablesForName(
|
||||
styleables: ResourceGroup,
|
||||
styleables: IResourceGroup,
|
||||
node: DOMNode,
|
||||
addFromParent: Boolean = false,
|
||||
suffix: String = ""
|
||||
@@ -237,7 +236,7 @@ open class AttrCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
|
||||
protected open fun findLayoutParams(
|
||||
styleables: ResourceGroup,
|
||||
styleables: IResourceGroup,
|
||||
parentNode: DOMNode
|
||||
): Set<Styleable> {
|
||||
val result = mutableSetOf<Styleable>()
|
||||
@@ -257,7 +256,7 @@ open class AttrCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
|
||||
protected open fun findStyleablesForWidget(
|
||||
styleables: ResourceGroup,
|
||||
styleables: IResourceGroup,
|
||||
widgets: WidgetTable,
|
||||
widget: Widget,
|
||||
node: DOMNode,
|
||||
@@ -302,7 +301,7 @@ open class AttrCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
|
||||
protected open fun addWidgetStyleable(
|
||||
styleables: ResourceGroup,
|
||||
styleables: IResourceGroup,
|
||||
widget: Widget,
|
||||
result: MutableSet<Styleable>,
|
||||
suffix: String = ""
|
||||
@@ -311,7 +310,7 @@ open class AttrCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
|
||||
protected open fun addWidgetStyleable(
|
||||
styleables: ResourceGroup,
|
||||
styleables: IResourceGroup,
|
||||
widget: String,
|
||||
result: MutableSet<Styleable>,
|
||||
suffix: String = ""
|
||||
@@ -323,7 +322,7 @@ open class AttrCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
|
||||
protected open fun addSuperclassStyleables(
|
||||
styleables: ResourceGroup,
|
||||
styleables: IResourceGroup,
|
||||
widgets: WidgetTable,
|
||||
widget: Widget,
|
||||
result: MutableSet<Styleable>,
|
||||
@@ -340,7 +339,7 @@ open class AttrCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun findStyleableEntry(styleables: ResourceGroup, name: String): Styleable? {
|
||||
protected open fun findStyleableEntry(styleables: IResourceGroup, name: String): Styleable? {
|
||||
val value = styleables.findEntry(name)?.findValue(ConfigDescription())?.value
|
||||
if (value !is Styleable) {
|
||||
log.warn("Cannot find styleable for {}", name)
|
||||
|
||||
+38
-19
@@ -27,7 +27,6 @@ import com.android.aapt.Resources.Attribute.FormatFlags.FLAGS
|
||||
import com.android.aapt.Resources.Attribute.FormatFlags.INTEGER
|
||||
import com.android.aapt.Resources.Attribute.FormatFlags.REFERENCE
|
||||
import com.android.aapt.Resources.Attribute.FormatFlags.STRING
|
||||
import com.android.aaptcompiler.AaptResourceType
|
||||
import com.android.aaptcompiler.AaptResourceType.ATTR
|
||||
import com.android.aaptcompiler.AaptResourceType.BOOL
|
||||
import com.android.aaptcompiler.AaptResourceType.DIMEN
|
||||
@@ -35,9 +34,6 @@ import com.android.aaptcompiler.AaptResourceType.UNKNOWN
|
||||
import com.android.aaptcompiler.AttributeResource
|
||||
import com.android.aaptcompiler.ConfigDescription
|
||||
import com.android.aaptcompiler.ResourcePathData
|
||||
import com.android.aaptcompiler.ResourceTable
|
||||
import com.android.aaptcompiler.ResourceTablePackage
|
||||
import com.itsaky.androidide.aapt.findEntries
|
||||
import com.itsaky.androidide.lsp.api.ICompletionProvider
|
||||
import com.itsaky.androidide.lsp.models.CompletionItem
|
||||
import com.itsaky.androidide.lsp.models.CompletionParams
|
||||
@@ -49,6 +45,8 @@ import com.itsaky.androidide.lsp.xml.edits.QualifiedValueEditHandler
|
||||
import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType
|
||||
import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType.ATTRIBUTE_VALUE
|
||||
import com.itsaky.androidide.lsp.xml.utils.dimensionUnits
|
||||
import com.itsaky.androidide.xml.res.IResourceTable
|
||||
import com.itsaky.androidide.xml.res.IResourceTablePackage
|
||||
import com.itsaky.androidide.xml.resources.ResourceTableRegistry
|
||||
import com.itsaky.androidide.xml.utils.attrValue_qualifiedRef
|
||||
import com.itsaky.androidide.xml.utils.attrValue_qualifiedRefWithIncompletePckOrType
|
||||
@@ -143,7 +141,9 @@ open class AttrValueCompletionProvider(provider: ICompletionProvider) :
|
||||
if (matcher.matches()) {
|
||||
val valPck = matcher.group(1)
|
||||
val typeStr = matcher.group(3)
|
||||
val valType = AaptResourceType.values().firstOrNull { it.tagName == typeStr } ?: return EMPTY
|
||||
val valType =
|
||||
com.android.aaptcompiler.AaptResourceType.values().firstOrNull { it.tagName == typeStr }
|
||||
?: return EMPTY
|
||||
val newPrefix = matcher.group(4) ?: ""
|
||||
addValues(valType, newPrefix, list) { it == valPck }
|
||||
return CompletionResult(list)
|
||||
@@ -179,7 +179,9 @@ open class AttrValueCompletionProvider(provider: ICompletionProvider) :
|
||||
if (matcher.matches()) {
|
||||
val typeStr = matcher.group(1)
|
||||
val newPrefix = matcher.group(2) ?: ""
|
||||
val valType = AaptResourceType.values().firstOrNull { it.tagName == typeStr } ?: return EMPTY
|
||||
val valType =
|
||||
com.android.aaptcompiler.AaptResourceType.values().firstOrNull { it.tagName == typeStr }
|
||||
?: return EMPTY
|
||||
addValues(valType, newPrefix, list)
|
||||
return CompletionResult(list)
|
||||
}
|
||||
@@ -217,12 +219,13 @@ open class AttrValueCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
}
|
||||
|
||||
private fun listResTypes(): List<String> = AaptResourceType.values().map { it.tagName }
|
||||
private fun listResTypes(): List<String> =
|
||||
com.android.aaptcompiler.AaptResourceType.values().map { it.tagName }
|
||||
|
||||
protected open fun resTableForFindAttr() = platformResourceTable()
|
||||
|
||||
private fun findAttr(
|
||||
tables: Set<ResourceTable>,
|
||||
tables: Set<IResourceTable>,
|
||||
namespace: String,
|
||||
pck: String,
|
||||
attr: String
|
||||
@@ -248,7 +251,7 @@ open class AttrValueCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
|
||||
private fun findAttr(
|
||||
packages: Collection<ResourceTablePackage>,
|
||||
packages: Collection<IResourceTablePackage>,
|
||||
attr: String
|
||||
): AttributeResource? {
|
||||
for (pck in packages) {
|
||||
@@ -272,15 +275,27 @@ open class AttrValueCompletionProvider(provider: ICompletionProvider) :
|
||||
} else {
|
||||
// Check for specific attribute formats
|
||||
if (attr.hasType(STRING)) {
|
||||
addValues(type = AaptResourceType.STRING, prefix = prefix, result = list)
|
||||
addValues(
|
||||
type = com.android.aaptcompiler.AaptResourceType.STRING,
|
||||
prefix = prefix,
|
||||
result = list
|
||||
)
|
||||
}
|
||||
|
||||
if (attr.hasType(INTEGER)) {
|
||||
addValues(type = AaptResourceType.INTEGER, prefix = prefix, result = list)
|
||||
addValues(
|
||||
type = com.android.aaptcompiler.AaptResourceType.INTEGER,
|
||||
prefix = prefix,
|
||||
result = list
|
||||
)
|
||||
}
|
||||
|
||||
if (attr.hasType(COLOR)) {
|
||||
addValues(type = AaptResourceType.COLOR, prefix = prefix, result = list)
|
||||
addValues(
|
||||
type = com.android.aaptcompiler.AaptResourceType.COLOR,
|
||||
prefix = prefix,
|
||||
result = list
|
||||
)
|
||||
}
|
||||
|
||||
if (attr.hasType(BOOLEAN)) {
|
||||
@@ -294,7 +309,11 @@ open class AttrValueCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
|
||||
if (attr.hasType(INTEGER)) {
|
||||
addValues(type = AaptResourceType.INTEGER, prefix = prefix, result = list)
|
||||
addValues(
|
||||
type = com.android.aaptcompiler.AaptResourceType.INTEGER,
|
||||
prefix = prefix,
|
||||
result = list
|
||||
)
|
||||
}
|
||||
|
||||
if (attr.hasType(ENUM) || attr.hasType(FLAGS)) {
|
||||
@@ -333,7 +352,7 @@ open class AttrValueCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
|
||||
private fun completeReferences(prefix: String, list: MutableList<CompletionItem>) {
|
||||
for (value in AaptResourceType.values()) {
|
||||
for (value in com.android.aaptcompiler.AaptResourceType.values()) {
|
||||
if (value == UNKNOWN) {
|
||||
continue
|
||||
}
|
||||
@@ -343,7 +362,7 @@ open class AttrValueCompletionProvider(provider: ICompletionProvider) :
|
||||
}
|
||||
|
||||
private fun addValues(
|
||||
type: AaptResourceType,
|
||||
type: com.android.aaptcompiler.AaptResourceType,
|
||||
prefix: String,
|
||||
result: MutableList<CompletionItem>,
|
||||
checkPck: (String) -> Boolean = { true }
|
||||
@@ -369,20 +388,20 @@ open class AttrValueCompletionProvider(provider: ICompletionProvider) :
|
||||
.toHashSet()
|
||||
|
||||
entries.forEach { pair ->
|
||||
pair.second?.forEach {
|
||||
pair.second?.forEach { entry ->
|
||||
result.add(
|
||||
createAttrValueCompletionItem(
|
||||
pair.first,
|
||||
type.tagName,
|
||||
it.name,
|
||||
matchLevel(it.name, prefix)
|
||||
entry.name,
|
||||
matchLevel(entry.name, prefix)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun findResourceTables(nsUri: String?): Set<ResourceTable> {
|
||||
override fun findResourceTables(nsUri: String?): Set<IResourceTable> {
|
||||
// When completing values, all namespaces must be included
|
||||
val tables = HashSet(findAllModuleResourceTables())
|
||||
|
||||
|
||||
+5
-6
@@ -17,9 +17,7 @@
|
||||
|
||||
package com.itsaky.androidide.lsp.xml.providers.completion
|
||||
|
||||
import com.android.aaptcompiler.Reference
|
||||
import com.android.aaptcompiler.ResourcePathData
|
||||
import com.android.aaptcompiler.ResourceTable
|
||||
import com.itsaky.androidide.lookup.Lookup
|
||||
import com.itsaky.androidide.lsp.api.ICompletionProvider
|
||||
import com.itsaky.androidide.lsp.api.describeSnippet
|
||||
@@ -41,6 +39,7 @@ import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType
|
||||
import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType.ATTRIBUTE
|
||||
import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType.ATTRIBUTE_VALUE
|
||||
import com.itsaky.androidide.utils.DocumentUtils
|
||||
import com.itsaky.androidide.xml.res.IResourceTable
|
||||
import com.itsaky.androidide.xml.resources.ResourceTableRegistry
|
||||
import org.eclipse.lemminx.dom.DOMAttr
|
||||
import org.eclipse.lemminx.dom.DOMDocument
|
||||
@@ -163,7 +162,7 @@ abstract class IXmlCompletionProvider(private val provider: ICompletionProvider)
|
||||
* @param matchLevel The match level.
|
||||
*/
|
||||
protected open fun createAttrCompletionItem(
|
||||
attr: Reference,
|
||||
attr: com.android.aaptcompiler.Reference,
|
||||
partial: String,
|
||||
resPkg: String,
|
||||
nsPrefix: String,
|
||||
@@ -252,7 +251,7 @@ abstract class IXmlCompletionProvider(private val provider: ICompletionProvider)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun findResourceTables(nsUri: String?): Set<ResourceTable> {
|
||||
protected open fun findResourceTables(nsUri: String?): Set<IResourceTable> {
|
||||
if (nsUri.isNullOrBlank()) {
|
||||
return emptySet()
|
||||
}
|
||||
@@ -287,11 +286,11 @@ abstract class IXmlCompletionProvider(private val provider: ICompletionProvider)
|
||||
return setOf(table)
|
||||
}
|
||||
|
||||
protected open fun findAllModuleResourceTables(): Set<ResourceTable> {
|
||||
protected open fun findAllModuleResourceTables(): Set<IResourceTable> {
|
||||
val lookup = Lookup.getDefault()
|
||||
val sourceResTables = lookup.lookup(ResourceTableRegistry.COMPLETION_MODULE_RES) ?: emptySet()
|
||||
val depResTables = lookup.lookup(ResourceTableRegistry.COMPLETION_DEP_RES) ?: emptySet()
|
||||
return mutableSetOf<ResourceTable>().also {
|
||||
return mutableSetOf<IResourceTable>().also {
|
||||
it.addAll(sourceResTables)
|
||||
it.addAll(depResTables)
|
||||
}
|
||||
|
||||
+2
-2
@@ -18,11 +18,11 @@
|
||||
package com.itsaky.androidide.lsp.xml.providers.completion.common
|
||||
|
||||
import com.android.aaptcompiler.ConfigDescription
|
||||
import com.android.aaptcompiler.ResourceGroup
|
||||
import com.android.aaptcompiler.Styleable
|
||||
import com.itsaky.androidide.lsp.api.ICompletionProvider
|
||||
import com.itsaky.androidide.lsp.xml.providers.completion.AttrCompletionProvider
|
||||
import com.itsaky.androidide.lsp.xml.utils.ITagTransformer
|
||||
import com.itsaky.androidide.xml.res.IResourceGroup
|
||||
import org.eclipse.lemminx.dom.DOMNode
|
||||
|
||||
/**
|
||||
@@ -37,7 +37,7 @@ open class CommonAttrCompletionProvider(
|
||||
provider: ICompletionProvider
|
||||
) : AttrCompletionProvider(provider) {
|
||||
|
||||
override fun findNodeStyleables(node: DOMNode, styleables: ResourceGroup): Set<Styleable> {
|
||||
override fun findNodeStyleables(node: DOMNode, styleables: IResourceGroup): Set<Styleable> {
|
||||
val name = node.nodeName
|
||||
val styleable =
|
||||
styleables
|
||||
|
||||
+2
-2
@@ -17,11 +17,11 @@
|
||||
|
||||
package com.itsaky.androidide.lsp.xml.providers.completion.etc
|
||||
|
||||
import com.android.aaptcompiler.ResourceGroup
|
||||
import com.android.aaptcompiler.Styleable
|
||||
import com.itsaky.androidide.lsp.api.ICompletionProvider
|
||||
import com.itsaky.androidide.lsp.xml.providers.completion.AttrCompletionProvider
|
||||
import com.itsaky.androidide.lsp.xml.utils.ITagTransformer
|
||||
import com.itsaky.androidide.xml.res.IResourceGroup
|
||||
import org.eclipse.lemminx.dom.DOMNode
|
||||
|
||||
/**
|
||||
@@ -35,7 +35,7 @@ class InheritingAttrCompletionProvider(
|
||||
provider: ICompletionProvider
|
||||
) : AttrCompletionProvider(provider) {
|
||||
|
||||
override fun findNodeStyleables(node: DOMNode, styleables: ResourceGroup): Set<Styleable> {
|
||||
override fun findNodeStyleables(node: DOMNode, styleables: IResourceGroup): Set<Styleable> {
|
||||
val nodeStyleables = mutableSetOf<Styleable>()
|
||||
val name = node.nodeName
|
||||
val entryName = tagTransform.transform(name, nodeAtCursor.parentNode?.nodeName ?: "")
|
||||
|
||||
+4
-3
@@ -18,7 +18,6 @@
|
||||
package com.itsaky.androidide.lsp.xml.providers.completion.manifest
|
||||
|
||||
import com.android.aaptcompiler.ConfigDescription
|
||||
import com.android.aaptcompiler.ResourceGroup
|
||||
import com.android.aaptcompiler.ResourcePathData
|
||||
import com.android.aaptcompiler.Styleable
|
||||
import com.itsaky.androidide.lsp.api.ICompletionProvider
|
||||
@@ -28,6 +27,7 @@ import com.itsaky.androidide.lsp.xml.providers.completion.canCompleteManifest
|
||||
import com.itsaky.androidide.lsp.xml.providers.completion.manifestResourceTable
|
||||
import com.itsaky.androidide.lsp.xml.providers.completion.transformToEntryName
|
||||
import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType
|
||||
import com.itsaky.androidide.xml.res.IResourceGroup
|
||||
import org.eclipse.lemminx.dom.DOMNode
|
||||
|
||||
/**
|
||||
@@ -44,10 +44,11 @@ class ManifestAttrCompletionProvider(provider: ICompletionProvider) :
|
||||
|
||||
override fun findResourceTables(nsUri: String?) = manifestResourceTable()
|
||||
|
||||
override fun findNodeStyleables(node: DOMNode, styleables: ResourceGroup): Set<Styleable> {
|
||||
override fun findNodeStyleables(node: DOMNode, styleables: IResourceGroup): Set<Styleable> {
|
||||
val name = node.nodeName
|
||||
val styleable =
|
||||
styleables.findEntry(transformToEntryName(name, MANIFEST_TAG_PREFIX))?.findValue(ConfigDescription())?.value
|
||||
styleables.findEntry(transformToEntryName(name, MANIFEST_TAG_PREFIX))
|
||||
?.findValue(ConfigDescription())?.value
|
||||
if (styleable != null && styleable is Styleable) {
|
||||
return setOf(styleable)
|
||||
}
|
||||
|
||||
+4
-4
@@ -25,7 +25,6 @@ import com.android.SdkConstants.TAG_INTENT_FILTER
|
||||
import com.android.SdkConstants.TAG_RECEIVER
|
||||
import com.android.SdkConstants.TAG_SERVICE
|
||||
import com.android.aaptcompiler.ResourcePathData
|
||||
import com.android.aaptcompiler.ResourceTable
|
||||
import com.itsaky.androidide.lookup.Lookup
|
||||
import com.itsaky.androidide.lsp.api.ICompletionProvider
|
||||
import com.itsaky.androidide.lsp.models.ClassCompletionData
|
||||
@@ -41,9 +40,10 @@ import com.itsaky.androidide.lsp.xml.providers.completion.AttrValueCompletionPro
|
||||
import com.itsaky.androidide.lsp.xml.providers.completion.manifestResourceTable
|
||||
import com.itsaky.androidide.lsp.xml.providers.completion.match
|
||||
import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType
|
||||
import com.itsaky.androidide.projects.android.AndroidModule
|
||||
import com.itsaky.androidide.projects.ModuleProject
|
||||
import com.itsaky.androidide.projects.android.AndroidModule
|
||||
import com.itsaky.androidide.xml.permissions.Permission
|
||||
import com.itsaky.androidide.xml.res.IResourceTable
|
||||
import com.itsaky.androidide.xml.resources.ResourceTableRegistry
|
||||
import org.eclipse.lemminx.dom.DOMDocument
|
||||
|
||||
@@ -74,7 +74,7 @@ class ManifestAttrValueCompletionProvider(provider: ICompletionProvider) :
|
||||
return super.doComplete(params, pathData, document, type, prefix)
|
||||
}
|
||||
|
||||
override fun resTableForFindAttr(): ResourceTable? {
|
||||
override fun resTableForFindAttr(): IResourceTable? {
|
||||
return manifestResourceTable().firstOrNull()
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ class ManifestAttrValueCompletionProvider(provider: ICompletionProvider) :
|
||||
?: throw IllegalStateException("No module project provided")
|
||||
}
|
||||
|
||||
override fun findResourceTables(nsUri: String?): Set<ResourceTable> {
|
||||
override fun findResourceTables(nsUri: String?): Set<IResourceTable> {
|
||||
val tables = manifestResourceTable().toMutableSet()
|
||||
if (nsUri.isNullOrBlank()) {
|
||||
return tables
|
||||
|
||||
-1
@@ -19,7 +19,6 @@ package com.itsaky.androidide.lsp.xml.providers.completion.manifest
|
||||
|
||||
import com.android.aaptcompiler.AaptResourceType.STYLEABLE
|
||||
import com.android.aaptcompiler.ResourcePathData
|
||||
import com.itsaky.androidide.aapt.findEntries
|
||||
import com.itsaky.androidide.lookup.Lookup
|
||||
import com.itsaky.androidide.lsp.api.ICompletionProvider
|
||||
import com.itsaky.androidide.lsp.models.CompletionItem
|
||||
|
||||
+4
-3
@@ -19,10 +19,10 @@ package com.itsaky.androidide.lsp.xml.providers.completion
|
||||
|
||||
import com.android.SdkConstants.ANDROID_MANIFEST_XML
|
||||
import com.android.aaptcompiler.ResourcePathData
|
||||
import com.android.aaptcompiler.ResourceTable
|
||||
import com.itsaky.androidide.lookup.Lookup
|
||||
import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType
|
||||
import com.itsaky.androidide.utils.VMUtils
|
||||
import com.itsaky.androidide.xml.res.IResourceTable
|
||||
import com.itsaky.androidide.xml.resources.ResourceTableRegistry
|
||||
|
||||
const val MANIFEST_TAG_PREFIX = "AndroidManifest"
|
||||
@@ -34,8 +34,9 @@ fun canCompleteManifest(pathData: ResourcePathData, type: NodeType): Boolean {
|
||||
pathData.file.name.endsWith("_template.xml"))
|
||||
}
|
||||
|
||||
fun manifestResourceTable(): Set<ResourceTable> {
|
||||
fun manifestResourceTable(): Set<IResourceTable> {
|
||||
return setOf(
|
||||
Lookup.getDefault().lookup(ResourceTableRegistry.COMPLETION_MANIFEST_ATTR_RES) ?: return emptySet()
|
||||
Lookup.getDefault().lookup(ResourceTableRegistry.COMPLETION_MANIFEST_ATTR_RES)
|
||||
?: return emptySet()
|
||||
)
|
||||
}
|
||||
+2
-3
@@ -17,11 +17,11 @@
|
||||
|
||||
package com.itsaky.androidide.lsp.xml.providers.completion
|
||||
|
||||
import com.android.aaptcompiler.ResourceTable
|
||||
import com.itsaky.androidide.lookup.Lookup
|
||||
import com.itsaky.androidide.lsp.models.CompletionItem.Companion.matchLevel
|
||||
import com.itsaky.androidide.lsp.models.MatchLevel
|
||||
import com.itsaky.androidide.lsp.models.MatchLevel.NO_MATCH
|
||||
import com.itsaky.androidide.xml.res.IResourceTable
|
||||
import com.itsaky.androidide.xml.resources.ResourceTableRegistry
|
||||
import org.eclipse.lemminx.dom.DOMNode
|
||||
import kotlin.math.min
|
||||
@@ -36,7 +36,7 @@ fun match(simpleName: String, qualifiedName: String, prefix: String): MatchLevel
|
||||
return MatchLevel.values()[min(simpleNameMatchLevel.ordinal, nameMatchLevel.ordinal)]
|
||||
}
|
||||
|
||||
fun platformResourceTable(): ResourceTable? {
|
||||
fun platformResourceTable(): IResourceTable? {
|
||||
return Lookup.getDefault().lookup(ResourceTableRegistry.COMPLETION_FRAMEWORK_RES)
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ fun findAllNamespaces(node: DOMNode): MutableSet<Pair<String, String>> {
|
||||
|
||||
while (curr != null && !curr.isOwnerDocument) {
|
||||
|
||||
@Suppress("SENSELESS_COMPARISON") // attributes might be null. Ignore warning
|
||||
if (curr.attributes == null) {
|
||||
curr = curr.parentNode
|
||||
continue
|
||||
|
||||
+3
-1
@@ -29,10 +29,12 @@
|
||||
package com.itsaky.androidide.lsp.xml.providers.format;
|
||||
|
||||
import com.itsaky.androidide.lsp.models.TextEdit;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lemminx.dom.DOMAttr;
|
||||
import org.eclipse.lemminx.utils.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DOM attribute formatter.
|
||||
*
|
||||
|
||||
+3
-1
@@ -30,9 +30,11 @@ package com.itsaky.androidide.lsp.xml.providers.format;
|
||||
|
||||
import com.itsaky.androidide.lsp.models.TextEdit;
|
||||
import com.itsaky.androidide.preferences.internal.EditorPreferences;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lemminx.dom.DOMCDATASection;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** DOM CDATA section formatter. */
|
||||
public class DOMCDATAFormatter {
|
||||
private final XMLFormatterDocumentNew formatterDocument;
|
||||
|
||||
+3
-1
@@ -30,9 +30,11 @@ package com.itsaky.androidide.lsp.xml.providers.format;
|
||||
|
||||
import com.itsaky.androidide.lsp.models.TextEdit;
|
||||
import com.itsaky.androidide.preferences.internal.EditorPreferences;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lemminx.dom.DOMComment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** DOM comment formatter. */
|
||||
public class DOMCommentFormatter {
|
||||
|
||||
|
||||
+3
-1
@@ -29,7 +29,7 @@
|
||||
package com.itsaky.androidide.lsp.xml.providers.format;
|
||||
|
||||
import com.itsaky.androidide.lsp.models.TextEdit;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lemminx.dom.DOMDocumentType;
|
||||
import org.eclipse.lemminx.dom.DOMNode;
|
||||
import org.eclipse.lemminx.dom.DTDAttlistDecl;
|
||||
@@ -38,6 +38,8 @@ import org.eclipse.lemminx.dom.DTDDeclParameter;
|
||||
import org.eclipse.lemminx.utils.StringUtils;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DOM docType formatter.
|
||||
*
|
||||
|
||||
+3
-1
@@ -29,13 +29,15 @@
|
||||
package com.itsaky.androidide.lsp.xml.providers.format;
|
||||
|
||||
import com.itsaky.androidide.lsp.models.TextEdit;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lemminx.commons.BadLocationException;
|
||||
import org.eclipse.lemminx.dom.DOMAttr;
|
||||
import org.eclipse.lemminx.dom.DOMElement;
|
||||
import org.eclipse.lemminx.dom.builder.EmptyElements;
|
||||
import org.eclipse.lemminx.utils.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DOM element formatter.
|
||||
*
|
||||
|
||||
+3
-1
@@ -29,10 +29,12 @@
|
||||
package com.itsaky.androidide.lsp.xml.providers.format;
|
||||
|
||||
import com.itsaky.androidide.lsp.models.TextEdit;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lemminx.dom.DOMAttr;
|
||||
import org.eclipse.lemminx.dom.DOMProcessingInstruction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DOM processing instruction formatter.
|
||||
*
|
||||
|
||||
+3
-1
@@ -29,9 +29,11 @@
|
||||
package com.itsaky.androidide.lsp.xml.providers.format;
|
||||
|
||||
import com.itsaky.androidide.lsp.models.TextEdit;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lemminx.dom.DOMText;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DOM text formatter.
|
||||
*
|
||||
|
||||
+4
-2
@@ -31,14 +31,16 @@ package com.itsaky.androidide.lsp.xml.providers.format;
|
||||
import com.itsaky.androidide.lsp.models.TextEdit;
|
||||
import com.itsaky.androidide.models.Position;
|
||||
import com.itsaky.androidide.models.Range;
|
||||
|
||||
import org.eclipse.lemminx.commons.BadLocationException;
|
||||
import org.eclipse.lemminx.commons.TextDocument;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import org.eclipse.lemminx.commons.BadLocationException;
|
||||
import org.eclipse.lemminx.commons.TextDocument;
|
||||
|
||||
/**
|
||||
* Utilities for {@link TextEdit}.
|
||||
|
||||
+3
-1
@@ -19,12 +19,14 @@ package com.itsaky.androidide.lsp.xml.providers.format;
|
||||
|
||||
import com.itsaky.androidide.lsp.models.TextEdit;
|
||||
import com.itsaky.androidide.models.Range;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lemminx.commons.BadLocationException;
|
||||
import org.eclipse.lemminx.dom.DOMDocument;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* XML formatter support.
|
||||
*/
|
||||
|
||||
+4
-2
@@ -33,8 +33,7 @@ import com.itsaky.androidide.lsp.xml.utils.XMLBuilder;
|
||||
import com.itsaky.androidide.models.Position;
|
||||
import com.itsaky.androidide.models.Range;
|
||||
import com.itsaky.androidide.preferences.internal.EditorPreferences;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lemminx.commons.BadLocationException;
|
||||
import org.eclipse.lemminx.commons.TextDocument;
|
||||
import org.eclipse.lemminx.dom.DOMAttr;
|
||||
@@ -52,6 +51,9 @@ import org.eclipse.lemminx.dom.DTDDeclNode;
|
||||
import org.eclipse.lemminx.dom.DTDDeclParameter;
|
||||
import org.eclipse.lemminx.dom.builder.EmptyElements;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Default XML formatter which generates one text edit by rewriting the DOM node which must be
|
||||
* formatted.
|
||||
|
||||
+6
-4
@@ -34,10 +34,7 @@ import com.itsaky.androidide.lsp.xml.models.XMLServerSettings;
|
||||
import com.itsaky.androidide.models.Position;
|
||||
import com.itsaky.androidide.models.Range;
|
||||
import com.itsaky.androidide.preferences.internal.EditorPreferences;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.eclipse.lemminx.commons.BadLocationException;
|
||||
import org.eclipse.lemminx.commons.TextDocument;
|
||||
import org.eclipse.lemminx.dom.DOMAttr;
|
||||
@@ -54,6 +51,11 @@ import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.Text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Experimental XML formatter which generates several text edit to remove, add, update spaces /
|
||||
* indent.
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
package com.itsaky.androidide.lsp.xml.utils;
|
||||
|
||||
import com.itsaky.androidide.lsp.xml.models.XMLServerSettings;
|
||||
|
||||
import org.eclipse.lemminx.dom.builder.BaseXmlFormattingOptions;
|
||||
import org.eclipse.lemminx.dom.builder.XmlBuilder;
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* 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 {
|
||||
namespace = "${BuildConfig.packageName}.xml.resapi"
|
||||
}
|
||||
|
||||
protobuf {
|
||||
protoc {
|
||||
artifact = "com.google.protobuf:protoc:4.27.0"
|
||||
}
|
||||
|
||||
generateProtoTasks {
|
||||
all().forEach {
|
||||
it.builtins {
|
||||
id("java") {
|
||||
option("lite")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(libs.aapt2.annotations)
|
||||
api(libs.aapt2.common)
|
||||
api(libs.google.protobuf)
|
||||
|
||||
api(libs.composite.layoutlibApi)
|
||||
api(libs.composite.jaxp)
|
||||
|
||||
implementation(projects.utilities.shared)
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aaptcompiler.AaptResourceType.ANIM
|
||||
import com.android.aaptcompiler.AaptResourceType.ANIMATOR
|
||||
import com.android.aaptcompiler.AaptResourceType.ARRAY
|
||||
import com.android.aaptcompiler.AaptResourceType.ATTR
|
||||
import com.android.aaptcompiler.AaptResourceType.ATTR_PRIVATE
|
||||
import com.android.aaptcompiler.AaptResourceType.BOOL
|
||||
import com.android.aaptcompiler.AaptResourceType.COLOR
|
||||
import com.android.aaptcompiler.AaptResourceType.CONFIG_VARYING
|
||||
import com.android.aaptcompiler.AaptResourceType.DIMEN
|
||||
import com.android.aaptcompiler.AaptResourceType.DRAWABLE
|
||||
import com.android.aaptcompiler.AaptResourceType.FONT
|
||||
import com.android.aaptcompiler.AaptResourceType.FRACTION
|
||||
import com.android.aaptcompiler.AaptResourceType.ID
|
||||
import com.android.aaptcompiler.AaptResourceType.INTEGER
|
||||
import com.android.aaptcompiler.AaptResourceType.INTERPOLATOR
|
||||
import com.android.aaptcompiler.AaptResourceType.LAYOUT
|
||||
import com.android.aaptcompiler.AaptResourceType.MACRO
|
||||
import com.android.aaptcompiler.AaptResourceType.MENU
|
||||
import com.android.aaptcompiler.AaptResourceType.MIPMAP
|
||||
import com.android.aaptcompiler.AaptResourceType.NAVIGATION
|
||||
import com.android.aaptcompiler.AaptResourceType.PLURALS
|
||||
import com.android.aaptcompiler.AaptResourceType.RAW
|
||||
import com.android.aaptcompiler.AaptResourceType.STRING
|
||||
import com.android.aaptcompiler.AaptResourceType.STYLE
|
||||
import com.android.aaptcompiler.AaptResourceType.STYLEABLE
|
||||
import com.android.aaptcompiler.AaptResourceType.TRANSITION
|
||||
import com.android.aaptcompiler.AaptResourceType.XML
|
||||
|
||||
private const val ANIM_TAG = "anim"
|
||||
private const val ANIMATOR_TAG = "animator"
|
||||
private const val ARRAY_TAG = "array"
|
||||
private const val ATTR_TAG = "attr"
|
||||
private const val ATTR_PRIVATE_TAG = "^attr-private"
|
||||
private const val BOOL_TAG = "bool"
|
||||
private const val COLOR_TAG = "color"
|
||||
private const val CONFIG_VARYING_TAG = "configVarying"
|
||||
private const val DIMEN_TAG = "dimen"
|
||||
private const val DRAWABLE_TAG = "drawable"
|
||||
private const val FONT_TAG = "font"
|
||||
private const val FRACTION_TAG = "fraction"
|
||||
private const val ID_TAG = "id"
|
||||
private const val INTEGER_TAG = "integer"
|
||||
private const val INTERPOLATOR_TAG = "interpolator"
|
||||
private const val LAYOUT_TAG = "layout"
|
||||
private const val MACRO_TAG = "macro"
|
||||
private const val MENU_TAG = "menu"
|
||||
private const val MIPMAP_TAG = "mipmap"
|
||||
private const val NAVIGATION_TAG = "navigation"
|
||||
private const val PLURALS_TAG = "plurals"
|
||||
private const val RAW_TAG = "raw"
|
||||
private const val STRING_TAG = "string"
|
||||
private const val STYLE_TAG = "style"
|
||||
private const val STYLEABLE_TAG = "styleable"
|
||||
private const val TRANSITION_TAG = "transition"
|
||||
private const val XML_TAG = "xml"
|
||||
|
||||
fun resourceTypeFromTag(tag: String) =
|
||||
when(tag) {
|
||||
ANIM_TAG -> ANIM
|
||||
ANIMATOR_TAG -> ANIMATOR
|
||||
ARRAY_TAG -> ARRAY
|
||||
ATTR_TAG -> ATTR
|
||||
ATTR_PRIVATE_TAG -> ATTR_PRIVATE
|
||||
BOOL_TAG -> BOOL
|
||||
COLOR_TAG -> COLOR
|
||||
CONFIG_VARYING_TAG -> CONFIG_VARYING
|
||||
DIMEN_TAG -> DIMEN
|
||||
DRAWABLE_TAG -> DRAWABLE
|
||||
FONT_TAG -> FONT
|
||||
FRACTION_TAG -> FRACTION
|
||||
ID_TAG -> ID
|
||||
INTEGER_TAG -> INTEGER
|
||||
INTERPOLATOR_TAG -> INTERPOLATOR
|
||||
LAYOUT_TAG -> LAYOUT
|
||||
MACRO_TAG -> MACRO
|
||||
MENU_TAG -> MENU
|
||||
MIPMAP_TAG -> MIPMAP
|
||||
NAVIGATION_TAG -> NAVIGATION
|
||||
PLURALS_TAG -> PLURALS
|
||||
RAW_TAG -> RAW
|
||||
STRING_TAG -> STRING
|
||||
STYLE_TAG -> STYLE
|
||||
STYLEABLE_TAG -> STYLEABLE
|
||||
TRANSITION_TAG -> TRANSITION
|
||||
XML_TAG -> XML
|
||||
else -> null
|
||||
}
|
||||
|
||||
enum class AaptResourceType(val tagName: String) {
|
||||
ANIM(ANIM_TAG),
|
||||
ANIMATOR(ANIMATOR_TAG),
|
||||
ARRAY(ARRAY_TAG),
|
||||
ATTR(ATTR_TAG),
|
||||
ATTR_PRIVATE(ATTR_PRIVATE_TAG),
|
||||
BOOL(BOOL_TAG),
|
||||
COLOR(COLOR_TAG),
|
||||
CONFIG_VARYING(CONFIG_VARYING_TAG),
|
||||
DIMEN(DIMEN_TAG),
|
||||
DRAWABLE(DRAWABLE_TAG),
|
||||
FONT(FONT_TAG),
|
||||
FRACTION(FRACTION_TAG),
|
||||
ID(ID_TAG),
|
||||
INTEGER(INTEGER_TAG),
|
||||
INTERPOLATOR(INTERPOLATOR_TAG),
|
||||
LAYOUT(LAYOUT_TAG),
|
||||
MACRO(MACRO_TAG),
|
||||
MENU(MENU_TAG),
|
||||
MIPMAP(MIPMAP_TAG),
|
||||
NAVIGATION(NAVIGATION_TAG),
|
||||
PLURALS(PLURALS_TAG),
|
||||
RAW(RAW_TAG),
|
||||
STRING(STRING_TAG),
|
||||
STYLE(STYLE_TAG),
|
||||
STYLEABLE(STYLEABLE_TAG),
|
||||
TRANSITION(TRANSITION_TAG),
|
||||
UNKNOWN(""),
|
||||
XML(XML_TAG)
|
||||
}
|
||||
+20
-3
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
@@ -22,14 +39,14 @@ import com.android.utils.ILogger
|
||||
import jaxp.xml.stream.Location
|
||||
import java.io.File
|
||||
|
||||
internal fun blameSource(
|
||||
fun blameSource(
|
||||
source: Source,
|
||||
line: Int? = source.line,
|
||||
column: Int? = null
|
||||
): BlameLogger.Source =
|
||||
BlameLogger.Source(source.path, line ?: -1, column ?: -1)
|
||||
|
||||
internal fun blameSource(
|
||||
fun blameSource(
|
||||
source: Source,
|
||||
location: Location
|
||||
): BlameLogger.Source =
|
||||
@@ -126,7 +143,7 @@ class BlameLogger(
|
||||
logger.verbose(message)
|
||||
}
|
||||
|
||||
internal fun getOutputSource(source: Source): Source {
|
||||
fun getOutputSource(source: Source): Source {
|
||||
return getOriginalSource(
|
||||
source.copy(sourcePath = userVisibleSourceTransform(source.sourcePath))
|
||||
)
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aaptcompiler.android.ResTableConfig
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class ConfigDescription(base: ResTableConfig = ResTableConfig()): ResTableConfig(base) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other is ConfigDescription) {
|
||||
return compareTo(other) == 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun compatible(first: Int, second: Int) = first == 0 || second == 0 || first == second
|
||||
}
|
||||
|
||||
const val WILDCARD_NAME: String = "any"
|
||||
|
||||
fun parse(config: String): ConfigDescription {
|
||||
val parts = config.split('-').map { it.lowercase() }
|
||||
var index = 0
|
||||
|
||||
val configDescription = ConfigDescription()
|
||||
val locale = LocaleValue()
|
||||
|
||||
if (parts.isEmpty() || config.isEmpty()) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
|
||||
if (parseMcc(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseMnc(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
// Locale spans a few '-' separators, so we let it control the index
|
||||
index += locale.initFromParts(parts, index)
|
||||
locale.writeTo(configDescription)
|
||||
if (index == parts.size) {
|
||||
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) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseSmallestScreenWidthDp(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseScreenWidthDp(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseScreenHeightDp(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseScreenLayoutSize(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseScreenLayoutLong(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseScreenRound(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseWideColorGamut(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseHdr(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseOrientation(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseUiModeType(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseUiModeNight(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseDensity(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseTouchscreen(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseKeysHidden(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseKeyboard(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseNavHidden(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseNavigation(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseScreenSize(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
if (parseVersion(parts[index], configDescription)) {
|
||||
index++
|
||||
if (index == parts.size) {
|
||||
return applyVersionForCompatibility(configDescription)
|
||||
}
|
||||
}
|
||||
|
||||
throw error("Unrecognized part '${parts[index]}' in configuration $config")
|
||||
}
|
||||
|
||||
private fun applyVersionForCompatibility(config: ConfigDescription): ConfigDescription {
|
||||
val minSdk = when {
|
||||
config.uiModeType() == ResTableConfig.UI_MODE.TYPE_VR_HEADSET ||
|
||||
config.wideColorGamut() != ResTableConfig.COLOR_MODE.WIDE_GAMUT_ANY ||
|
||||
config.hdr() != ResTableConfig.COLOR_MODE.HDR_ANY -> SDKConstants.SDK_O
|
||||
|
||||
config.layoutRound() != 0.toByte() -> SDKConstants.SDK_MARSHMALLOW
|
||||
config.density == ResTableConfig.DENSITY.ANY -> SDKConstants.SDK_LOLLIPOP
|
||||
config.smallestScreenWidthDp != 0 ||
|
||||
config.screenWidthDp != 0 ||
|
||||
config.screenHeightDp != 0 -> SDKConstants.SDK_HONEYCOMB_MR2
|
||||
|
||||
config.uiModeType() != ResTableConfig.UI_MODE.TYPE_ANY ||
|
||||
config.uiModeNight() != ResTableConfig.UI_MODE.NIGHT_ANY -> SDKConstants.SDK_FROYO
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
if (minSdk > config.sdkVersion) {
|
||||
config.sdkVersion = minSdk
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
+32
-10
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
@@ -18,6 +35,11 @@ package com.android.aaptcompiler
|
||||
|
||||
import com.android.aaptcompiler.android.AConfiguration
|
||||
import com.android.aaptcompiler.android.ResTableConfig
|
||||
import com.android.aaptcompiler.android.ResTableConfig.COLOR_MODE
|
||||
import com.android.aaptcompiler.android.ResTableConfig.INPUT_FLAGS
|
||||
import com.android.aaptcompiler.android.ResTableConfig.SCREEN_LAYOUT
|
||||
import com.android.aaptcompiler.android.ResTableConfig.SCREEN_LAYOUT2
|
||||
import com.android.aaptcompiler.android.ResTableConfig.UI_MODE
|
||||
import com.android.aaptcompiler.android.isTruthy
|
||||
|
||||
/** attempt to parse the Mobile Country Code */
|
||||
@@ -65,7 +87,7 @@ fun parseLayoutDirection(part: String, config: ConfigDescription) : Boolean {
|
||||
}
|
||||
// AND existing config with the mask and then OR with the found layout direction.
|
||||
config.screenLayout =
|
||||
maskAndApply(config.screenLayout, ResTableConfig.SCREEN_LAYOUT.DIR_MASK, value)
|
||||
maskAndApply(config.screenLayout, SCREEN_LAYOUT.DIR_MASK, value)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -119,7 +141,7 @@ fun parseScreenLayoutSize(part: String, config: ConfigDescription): Boolean {
|
||||
}
|
||||
// AND existing config with the mask and then OR with the found layout size.
|
||||
config.screenLayout =
|
||||
maskAndApply(config.screenLayout, ResTableConfig.SCREEN_LAYOUT.SIZE_MASK, value)
|
||||
maskAndApply(config.screenLayout, SCREEN_LAYOUT.SIZE_MASK, value)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -132,7 +154,7 @@ fun parseScreenLayoutLong(part: String, config: ConfigDescription): Boolean {
|
||||
}
|
||||
// AND existing config with the mask and then OR with the found layout size.
|
||||
config.screenLayout =
|
||||
maskAndApply(config.screenLayout, ResTableConfig.SCREEN_LAYOUT.SCREENLONG_MASK, value)
|
||||
maskAndApply(config.screenLayout, SCREEN_LAYOUT.SCREENLONG_MASK, value)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -144,7 +166,7 @@ fun parseScreenRound(part: String, config: ConfigDescription): Boolean {
|
||||
else -> return false
|
||||
}
|
||||
config.screenLayout2 =
|
||||
maskAndApply(config.screenLayout2, ResTableConfig.SCREEN_LAYOUT2.SCREENROUND_MASK, value)
|
||||
maskAndApply(config.screenLayout2, SCREEN_LAYOUT2.SCREENROUND_MASK, value)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -156,7 +178,7 @@ fun parseWideColorGamut(part: String, config: ConfigDescription): Boolean {
|
||||
else -> return false
|
||||
}
|
||||
config.colorMode =
|
||||
maskAndApply(config.colorMode, ResTableConfig.COLOR_MODE.WIDE_GAMUT_MASK, value)
|
||||
maskAndApply(config.colorMode, COLOR_MODE.WIDE_GAMUT_MASK, value)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -167,7 +189,7 @@ fun parseHdr(part: String, config: ConfigDescription): Boolean {
|
||||
"lowdr" -> ResTableConfig.COLOR_MODE.HDR_NO
|
||||
else -> return false
|
||||
}
|
||||
config.colorMode = maskAndApply(config.colorMode, ResTableConfig.COLOR_MODE.HDR_MASK, value)
|
||||
config.colorMode = maskAndApply(config.colorMode, COLOR_MODE.HDR_MASK, value)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -193,7 +215,7 @@ fun parseUiModeType(part: String, config: ConfigDescription): Boolean {
|
||||
"vrheadset" -> ResTableConfig.UI_MODE.TYPE_VR_HEADSET
|
||||
else -> return false
|
||||
}
|
||||
config.uiMode = maskAndApply(config.uiMode, ResTableConfig.UI_MODE.TYPE_MASK, value)
|
||||
config.uiMode = maskAndApply(config.uiMode, UI_MODE.TYPE_MASK, value)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -204,7 +226,7 @@ fun parseUiModeNight(part: String, config: ConfigDescription): Boolean {
|
||||
"notnight" -> ResTableConfig.UI_MODE.NIGHT_NO
|
||||
else -> return false
|
||||
}
|
||||
config.uiMode = maskAndApply(config.uiMode, ResTableConfig.UI_MODE.NIGHT_MASK, value)
|
||||
config.uiMode = maskAndApply(config.uiMode, UI_MODE.NIGHT_MASK, value)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -255,7 +277,7 @@ fun parseKeysHidden(part: String, config: ConfigDescription): Boolean {
|
||||
else -> return false
|
||||
}
|
||||
config.inputFlags =
|
||||
maskAndApply(config.inputFlags, ResTableConfig.INPUT_FLAGS.KEYSHIDDEN_MASK, value)
|
||||
maskAndApply(config.inputFlags, INPUT_FLAGS.KEYSHIDDEN_MASK, value)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -278,7 +300,7 @@ fun parseNavHidden(part: String, config: ConfigDescription): Boolean {
|
||||
else -> return false
|
||||
}
|
||||
config.inputFlags =
|
||||
maskAndApply(config.inputFlags, ResTableConfig.INPUT_FLAGS.NAVHIDDEN_MASK, value)
|
||||
maskAndApply(config.inputFlags, INPUT_FLAGS.NAVHIDDEN_MASK, value)
|
||||
return true
|
||||
}
|
||||
|
||||
+17
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
+17
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.android.aaptcompiler
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.android.aaptcompiler
|
||||
|
||||
/**
|
||||
* Represents a single value for an entry for a given Configuration.
|
||||
*
|
||||
* @property config The configuration for which this value is defined.
|
||||
* @property product The product name for which this value is defined.
|
||||
* @property value The actual Value.
|
||||
*/
|
||||
data class ResourceConfigValue(
|
||||
val config: ConfigDescription,
|
||||
val product: String,
|
||||
var value: Value? = null
|
||||
)
|
||||
+21
-2
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
@@ -16,6 +33,8 @@
|
||||
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aaptcompiler.AaptResourceType.RAW
|
||||
|
||||
data class ResourceFile(
|
||||
val name: ResourceName,
|
||||
val configuration: ConfigDescription,
|
||||
@@ -42,7 +61,7 @@ data class ResourceFile(
|
||||
|
||||
data class ResourceName(
|
||||
val pck: String?,
|
||||
val type: AaptResourceType = AaptResourceType.RAW,
|
||||
val type: AaptResourceType = RAW,
|
||||
val entry: String? = null): Comparable<ResourceName> {
|
||||
|
||||
override fun compareTo(other: ResourceName): Int {
|
||||
@@ -75,7 +94,7 @@ data class ResourceName(
|
||||
}
|
||||
|
||||
companion object {
|
||||
val EMPTY = ResourceName("", AaptResourceType.RAW, "")
|
||||
val EMPTY = ResourceName("", RAW, "")
|
||||
}
|
||||
}
|
||||
|
||||
+23
-4
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
@@ -16,8 +33,8 @@
|
||||
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.itsaky.androidide.layoutlib.resources.ResourceType
|
||||
import java.io.File
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Class for keeping track of Resource File of any kind.
|
||||
@@ -60,17 +77,19 @@ 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.toLowerCase(), resName, type, config, file, configDescription)
|
||||
source, extension.lowercase(Locale.getDefault()), resName, type, config, file, configDescription
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
+56
-13
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
@@ -17,7 +34,14 @@
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aapt.Resources
|
||||
import com.android.aaptcompiler.AaptResourceType.ATTR
|
||||
import com.android.aaptcompiler.AaptResourceType.ID
|
||||
import com.android.aaptcompiler.AaptResourceType.STYLE
|
||||
import com.android.aaptcompiler.Reference.Type.ATTRIBUTE
|
||||
import com.android.aaptcompiler.android.ResValue
|
||||
import com.android.aaptcompiler.android.ResValue.DataType.INT_BOOLEAN
|
||||
import com.android.aaptcompiler.android.ResValue.DataType.NULL
|
||||
import com.android.aaptcompiler.android.ResValue.NullFormat
|
||||
import com.android.aaptcompiler.android.parseHex
|
||||
import com.android.aaptcompiler.android.stringToFloat
|
||||
import com.android.aaptcompiler.android.stringToInt
|
||||
@@ -27,7 +51,7 @@ fun tryParseBool(string: String) : BinaryPrimitive? {
|
||||
boolean ?: return null
|
||||
|
||||
val data = if (boolean) -1 else 0
|
||||
return BinaryPrimitive(ResValue(ResValue.DataType.INT_BOOLEAN, data))
|
||||
return BinaryPrimitive(ResValue(INT_BOOLEAN, data))
|
||||
}
|
||||
|
||||
fun parseAsBool(string: String): Boolean? =
|
||||
@@ -51,7 +75,7 @@ fun makeNull() : Reference {
|
||||
}
|
||||
|
||||
fun makeEmpty(): BinaryPrimitive {
|
||||
return BinaryPrimitive(ResValue(ResValue.DataType.NULL, ResValue.NullFormat.EMPTY))
|
||||
return BinaryPrimitive(ResValue(NULL, NullFormat.EMPTY))
|
||||
}
|
||||
|
||||
fun tryParseInt(value: String): BinaryPrimitive? {
|
||||
@@ -64,7 +88,8 @@ fun parseResourceId(value: String): Int? {
|
||||
val resValue = stringToInt(value)
|
||||
if (resValue != null &&
|
||||
resValue.dataType == ResValue.DataType.INT_HEX &&
|
||||
resValue.data.isValidDynamicId()) {
|
||||
resValue.data.isValidDynamicId()
|
||||
) {
|
||||
return resValue.data
|
||||
}
|
||||
return null
|
||||
@@ -100,6 +125,7 @@ fun tryParseColor(value: String): BinaryPrimitive? {
|
||||
}
|
||||
data = data or 0xff000000.toInt()
|
||||
}
|
||||
|
||||
5 -> {
|
||||
dataType = ResValue.DataType.INT_COLOR_ARGB4
|
||||
for (i in 1..4) {
|
||||
@@ -111,6 +137,7 @@ fun tryParseColor(value: String): BinaryPrimitive? {
|
||||
data = (data shl 8) or (hexValue + (hexValue shl 4))
|
||||
}
|
||||
}
|
||||
|
||||
7 -> {
|
||||
dataType = ResValue.DataType.INT_COLOR_RGB8
|
||||
for (i in 1..6) {
|
||||
@@ -123,6 +150,7 @@ fun tryParseColor(value: String): BinaryPrimitive? {
|
||||
}
|
||||
data = data or 0xff000000.toInt()
|
||||
}
|
||||
|
||||
9 -> {
|
||||
dataType = ResValue.DataType.INT_COLOR_ARGB8
|
||||
for (i in 1..8) {
|
||||
@@ -134,6 +162,7 @@ fun tryParseColor(value: String): BinaryPrimitive? {
|
||||
data = (data shl 4) or hexValue
|
||||
}
|
||||
}
|
||||
|
||||
else -> return null
|
||||
}
|
||||
return if (error)
|
||||
@@ -197,8 +226,9 @@ fun parseAttributeReference(value: String) : ReferenceInfo? {
|
||||
val reference = Reference()
|
||||
reference.name =
|
||||
ResourceName(
|
||||
possibleResourceName.packageName, AaptResourceType.ATTR, possibleResourceName.entry)
|
||||
reference.referenceType = Reference.Type.ATTRIBUTE
|
||||
possibleResourceName.packageName, ATTR, possibleResourceName.entry
|
||||
)
|
||||
reference.referenceType = ATTRIBUTE
|
||||
return ReferenceInfo(reference, false)
|
||||
}
|
||||
|
||||
@@ -248,7 +278,7 @@ fun parseReference(value: String) : ReferenceInfo? {
|
||||
return null
|
||||
}
|
||||
|
||||
if (create && referenceNameInfo.resourceName.type != AaptResourceType.ID) {
|
||||
if (create && referenceNameInfo.resourceName.type != ID) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -308,11 +338,13 @@ 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 {
|
||||
@@ -334,6 +366,7 @@ fun extractResourceName(value: String): PossibleResourceName {
|
||||
typeName = value.substring(offsetCurrent, currentChar)
|
||||
offsetCurrent = currentChar + 1
|
||||
}
|
||||
|
||||
packageName.isEmpty() && value[currentChar] == ':' -> {
|
||||
hasPackageSeparator = true
|
||||
packageName = value.substring(offsetCurrent, currentChar)
|
||||
@@ -353,7 +386,8 @@ 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) {
|
||||
@@ -399,7 +433,8 @@ fun tryParseItemForAttribute(
|
||||
if ((resourceTypeMask and floatMask) != 0) {
|
||||
val floatingPoint = tryParseFloat(value)
|
||||
if (floatingPoint != null &&
|
||||
(androidTypeToAttributeTypeMask(floatingPoint.resValue.dataType) and resourceTypeMask) != 0) {
|
||||
(androidTypeToAttributeTypeMask(floatingPoint.resValue.dataType) and resourceTypeMask) != 0
|
||||
) {
|
||||
return floatingPoint
|
||||
}
|
||||
}
|
||||
@@ -413,6 +448,7 @@ fun androidTypeToAttributeTypeMask(type: ResValue.DataType) =
|
||||
ResValue.DataType.REFERENCE,
|
||||
ResValue.DataType.ATTRIBUTE,
|
||||
ResValue.DataType.DYNAMIC_REFERENCE -> Resources.Attribute.FormatFlags.REFERENCE_VALUE
|
||||
|
||||
ResValue.DataType.STRING -> Resources.Attribute.FormatFlags.STRING_VALUE
|
||||
ResValue.DataType.FLOAT -> Resources.Attribute.FormatFlags.FLOAT_VALUE
|
||||
ResValue.DataType.DIMENSION -> Resources.Attribute.FormatFlags.DIMENSION_VALUE
|
||||
@@ -423,11 +459,13 @@ fun androidTypeToAttributeTypeMask(type: ResValue.DataType) =
|
||||
Resources.Attribute.FormatFlags.ENUM_VALUE or
|
||||
Resources.Attribute.FormatFlags.FLAGS_VALUE
|
||||
}
|
||||
|
||||
ResValue.DataType.INT_BOOLEAN -> Resources.Attribute.FormatFlags.BOOLEAN_VALUE
|
||||
ResValue.DataType.INT_COLOR_ARGB8,
|
||||
ResValue.DataType.INT_COLOR_RGB8,
|
||||
ResValue.DataType.INT_COLOR_ARGB4,
|
||||
ResValue.DataType.INT_COLOR_RGB4 -> Resources.Attribute.FormatFlags.COLOR_VALUE
|
||||
|
||||
else -> 0
|
||||
}
|
||||
|
||||
@@ -456,6 +494,7 @@ fun verifyJavaStringFormat(string: String): Boolean {
|
||||
nonpositionalArgs = true
|
||||
}
|
||||
}
|
||||
|
||||
currentIndex < string.length && string.codePointAt(currentIndex) == '<'.code -> {
|
||||
// Reusing last argument, bad idea since positions can be moved around during translation
|
||||
nonpositionalArgs = true
|
||||
@@ -466,6 +505,7 @@ fun verifyJavaStringFormat(string: String): Boolean {
|
||||
++currentIndex
|
||||
}
|
||||
}
|
||||
|
||||
else -> nonpositionalArgs = true
|
||||
}
|
||||
// Ignore size, width, flags, etc.
|
||||
@@ -478,6 +518,7 @@ fun verifyJavaStringFormat(string: String): Boolean {
|
||||
','.code,
|
||||
'('.code,
|
||||
in '0'.code..'9'.code -> ++currentIndex
|
||||
|
||||
else -> break@search
|
||||
}
|
||||
}
|
||||
@@ -571,11 +612,13 @@ fun parseStyleParentReference(str: String): ParsedParentInfo {
|
||||
|
||||
val resourceName =
|
||||
ResourceName(
|
||||
possibleResourceName.packageName, AaptResourceType.STYLE, possibleResourceName.entry)
|
||||
possibleResourceName.packageName, STYLE, possibleResourceName.entry
|
||||
)
|
||||
|
||||
if (!hasLeadingIdentifiers &&
|
||||
resourceName.pck!!.isEmpty() &&
|
||||
possibleResourceName.typeName.isNotEmpty()) {
|
||||
possibleResourceName.typeName.isNotEmpty()
|
||||
) {
|
||||
val errorString = "Invalid parent reference '$str'"
|
||||
return ParsedParentInfo(null, errorString)
|
||||
}
|
||||
@@ -610,7 +653,7 @@ fun parseXmlAttributeName(str: String): Reference {
|
||||
}
|
||||
|
||||
result.name =
|
||||
ResourceName(packageName, AaptResourceType.ATTR, if (entryName.isEmpty()) name else entryName)
|
||||
ResourceName(packageName, ATTR, if (entryName.isEmpty()) name else entryName)
|
||||
return result
|
||||
}
|
||||
|
||||
+37
-12
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
@@ -17,6 +34,8 @@
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aapt.Resources
|
||||
import com.android.aaptcompiler.AaptResourceType.MACRO
|
||||
import com.android.aaptcompiler.Reference.Type.RESOURCE
|
||||
import com.android.aaptcompiler.android.ResValue
|
||||
import com.android.aaptcompiler.android.deviceToHost
|
||||
import com.android.aaptcompiler.android.hostToDevice
|
||||
@@ -74,7 +93,7 @@ class Reference(var name: ResourceName = ResourceName.EMPTY): Item() {
|
||||
}
|
||||
|
||||
var id : Int? = null
|
||||
var referenceType : Reference.Type = Reference.Type.RESOURCE
|
||||
var referenceType : Type = RESOURCE
|
||||
var isPrivate = false
|
||||
var isDynamic = false
|
||||
// Only used for macros, which can contain any format type
|
||||
@@ -83,14 +102,14 @@ class Reference(var name: ResourceName = ResourceName.EMPTY): Item() {
|
||||
var allowRaw = true
|
||||
|
||||
override fun flatten(): ResValue? {
|
||||
if (name?.type == AaptResourceType.MACRO) {
|
||||
if (name?.type == MACRO) {
|
||||
return null
|
||||
}
|
||||
val resId = id ?: 0
|
||||
val dynamic = resId.isValidDynamicId() && isDynamic
|
||||
|
||||
val dataType = when {
|
||||
referenceType == Reference.Type.RESOURCE ->
|
||||
referenceType == RESOURCE ->
|
||||
if (dynamic) ResValue.DataType.DYNAMIC_REFERENCE else ResValue.DataType.REFERENCE
|
||||
else ->
|
||||
if (dynamic) ResValue.DataType.DYNAMIC_ATTRIBUTE else ResValue.DataType.ATTRIBUTE
|
||||
@@ -253,18 +272,23 @@ private fun maskToString(typeMask: Int): String {
|
||||
result.append(maskToString(typeMask, Resources.Attribute.FormatFlags.BOOLEAN_VALUE, "| boolean"))
|
||||
result.append(maskToString(typeMask, Resources.Attribute.FormatFlags.COLOR_VALUE, "| color"))
|
||||
result.append(
|
||||
maskToString(typeMask, Resources.Attribute.FormatFlags.DIMENSION_VALUE, "| dimension"))
|
||||
maskToString(typeMask, Resources.Attribute.FormatFlags.DIMENSION_VALUE, "| dimension")
|
||||
)
|
||||
result.append(maskToString(typeMask, Resources.Attribute.FormatFlags.ENUM_VALUE, "| enum"))
|
||||
result.append(maskToString(typeMask, Resources.Attribute.FormatFlags.FLAGS_VALUE, "| flags"))
|
||||
result.append(maskToString(typeMask, Resources.Attribute.FormatFlags.FLOAT_VALUE, "| float"))
|
||||
result.append(
|
||||
maskToString(typeMask, Resources.Attribute.FormatFlags.FRACTION_VALUE, "| fraction"))
|
||||
maskToString(typeMask, Resources.Attribute.FormatFlags.FRACTION_VALUE, "| fraction")
|
||||
)
|
||||
result.append(
|
||||
maskToString(typeMask, Resources.Attribute.FormatFlags.INTEGER_VALUE, "| integer"))
|
||||
maskToString(typeMask, Resources.Attribute.FormatFlags.INTEGER_VALUE, "| integer")
|
||||
)
|
||||
result.append(
|
||||
maskToString(typeMask, Resources.Attribute.FormatFlags.REFERENCE_VALUE, "| reference"))
|
||||
maskToString(typeMask, Resources.Attribute.FormatFlags.REFERENCE_VALUE, "| reference")
|
||||
)
|
||||
result.append(
|
||||
maskToString(typeMask, Resources.Attribute.FormatFlags.STRING_VALUE, "| string"))
|
||||
maskToString(typeMask, Resources.Attribute.FormatFlags.STRING_VALUE, "| string")
|
||||
)
|
||||
return if (result.isNotEmpty()) result.substring(2) else ""
|
||||
}
|
||||
|
||||
@@ -414,7 +438,8 @@ class Style: Value() {
|
||||
newStyle.source = source
|
||||
for (entry in entries){
|
||||
newStyle.entries.add(
|
||||
Entry(entry.key, entry.value?.clone(pool)))
|
||||
Entry(entry.key, entry.value?.clone(pool))
|
||||
)
|
||||
}
|
||||
return newStyle
|
||||
}
|
||||
@@ -476,14 +501,14 @@ class Style: Value() {
|
||||
|
||||
entries.clear()
|
||||
for (entry in mergedEntries) {
|
||||
entries.add(Style.Entry(entry.key, entry.value?.clone(pool)))
|
||||
entries.add(Entry(entry.key, entry.value?.clone(pool)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val sb = StringBuilder(parent?.name.toString() +"\n")
|
||||
for (entry in entries) {
|
||||
sb.appendln(entry.key.name.toString() + " " + entry.value?.toString())
|
||||
sb.appendLine(entry.key.name.toString() + " " + entry.value?.toString())
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
@@ -506,7 +531,7 @@ class Plural: Value() {
|
||||
|
||||
val values = arrayOfNulls<Item?>(Type.NUM_TYPES)
|
||||
|
||||
fun setValue(type: Plural.Type, item: Item) {
|
||||
fun setValue(type: Type, item: Item) {
|
||||
values[type.ordinal] = item
|
||||
}
|
||||
|
||||
+17
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
+23
-4
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
@@ -16,6 +33,7 @@
|
||||
|
||||
package com.android.aaptcompiler
|
||||
|
||||
import com.android.aaptcompiler.StringPool.Context.Priority.NORMAL
|
||||
import com.android.aaptcompiler.android.ChunkType
|
||||
import com.android.aaptcompiler.android.ResChunkHeader
|
||||
import com.android.aaptcompiler.android.ResStringPoolHeader
|
||||
@@ -36,8 +54,9 @@ class StringPool {
|
||||
private val indexedStrings = mutableMapOf<String, MutableList<Entry>>()
|
||||
|
||||
class Context(
|
||||
var priority: Long = Priority.NORMAL.priority,
|
||||
var config: ConfigDescription = ConfigDescription()) {
|
||||
var priority: Long = NORMAL.priority,
|
||||
var config: ConfigDescription = ConfigDescription()
|
||||
) {
|
||||
enum class Priority(val priority: Long) {
|
||||
HIGH(1),
|
||||
NORMAL(0x7fffffffL),
|
||||
@@ -58,7 +77,7 @@ class StringPool {
|
||||
fun context(): Context = entry.context
|
||||
}
|
||||
|
||||
class Span(internal val name: Ref, var firstChar: Int, var lastChar: Int = firstChar) {
|
||||
class Span(val name: Ref, var firstChar: Int, var lastChar: Int = firstChar) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other is Span) {
|
||||
return name.value() == other.name.value() &&
|
||||
@@ -97,7 +116,7 @@ class StringPool {
|
||||
|
||||
fun size(): Int = styles.size + strings.size
|
||||
|
||||
fun entryAt(index: Int): StringPool.Entry {
|
||||
fun entryAt(index: Int): Entry {
|
||||
return strings[index]
|
||||
}
|
||||
|
||||
+5
-5
@@ -1487,12 +1487,12 @@ open class ResTableConfig(
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal val ENGLISH = byteArrayOf('e'.code.toByte(), 'n'.code.toByte()) // packed version of "en"
|
||||
internal val UNITED_STATES = byteArrayOf('U'.code.toByte(), 'S'.code.toByte()) // packed version of "US"
|
||||
internal val FILIPINO = byteArrayOf(0xAD.toByte(), 0x05.toByte()) // packed version of "fil"
|
||||
internal val TAGALOG = byteArrayOf('t'.code.toByte(), 'l'.code.toByte()) // packed version of "tl"
|
||||
val ENGLISH = byteArrayOf('e'.code.toByte(), 'n'.code.toByte()) // packed version of "en"
|
||||
val UNITED_STATES = byteArrayOf('U'.code.toByte(), 'S'.code.toByte()) // packed version of "US"
|
||||
val FILIPINO = byteArrayOf(0xAD.toByte(), 0x05.toByte()) // packed version of "fil"
|
||||
val TAGALOG = byteArrayOf('t'.code.toByte(), 'l'.code.toByte()) // packed version of "tl"
|
||||
|
||||
internal const val NUMBERING_SYSTEM_PREFIX = "u-nu-"
|
||||
const val NUMBERING_SYSTEM_PREFIX = "u-nu-"
|
||||
|
||||
// Flags indicating a set of config values. These flag constants must
|
||||
// match the corresponding ones in android.content.pm.ActivityInfo and
|
||||
+58
-12
@@ -20,7 +20,6 @@ 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.
|
||||
@@ -36,7 +35,8 @@ class ResChunkHeader(
|
||||
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)
|
||||
|
||||
@@ -54,6 +54,7 @@ enum class ChunkType(val id: Short) {
|
||||
|
||||
// Marker for the beginning of XML types.
|
||||
XML_FIRST_CHUNK_TYPE(0x0100),
|
||||
|
||||
// Child types of XML_TYPE
|
||||
XML_START_NAMESPACE_TYPE(0x0100),
|
||||
XML_END_NAMESPACE_TYPE(0x0101),
|
||||
@@ -61,6 +62,7 @@ enum class ChunkType(val id: Short) {
|
||||
XML_END_ELEMENT_TYPE(0x0103),
|
||||
XML_CDATA_TYPE(0x0104),
|
||||
XML_LAST_CHUNK_TYPE(0x017f),
|
||||
|
||||
// This contains a uint32_t array mapping strings in the string
|
||||
// pool back to resource identifiers. It is optional.
|
||||
XML_RESOURCE_MAP_TYPE(0x0180),
|
||||
@@ -85,36 +87,51 @@ data class ResValue(val dataType: DataType, val data: Int, val size: Short = 0)
|
||||
enum class DataType(val byteValue: Byte) {
|
||||
// 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.
|
||||
REFERENCE(0x01),
|
||||
|
||||
// The 'data' holds an attribute resource identifier.
|
||||
ATTRIBUTE(0x02),
|
||||
|
||||
// The 'data' holds an index into the containing resource table's string pool.
|
||||
STRING(0x03),
|
||||
|
||||
// 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.
|
||||
DIMENSION(0x05),
|
||||
|
||||
// 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.
|
||||
DYNAMIC_REFERENCE(0x07),
|
||||
|
||||
// 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.
|
||||
INT_DEC(0x10),
|
||||
|
||||
// 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.
|
||||
INT_BOOLEAN(0x12),
|
||||
|
||||
// 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.
|
||||
INT_COLOR_RGB8(0x1d),
|
||||
|
||||
// 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
|
||||
INT_COLOR_RGB4(0x1f);
|
||||
|
||||
@@ -135,19 +152,25 @@ data class ResValue(val dataType: DataType, val data: Int, val size: Short = 0)
|
||||
|
||||
// TYPE_DIMENSION: Value is raw pixels.
|
||||
const val UNIT_PX = 0
|
||||
|
||||
// TYPE_DIMENSION: Value is Device Independent Pixels.
|
||||
const val UNIT_DIP = 1
|
||||
|
||||
// TYPE_DIMENSION: Value is a Scaled device independent Pixels.
|
||||
const val UNIT_SP = 2
|
||||
|
||||
// TYPE_DIMENSION: Value is in points.
|
||||
const val UNIT_PT = 3
|
||||
|
||||
// TYPE_DIMENSION: Value is in inches.
|
||||
const val UNIT_IN = 4
|
||||
|
||||
// TYPE_DIMENSION: Value is in millimeters.
|
||||
const val UNIT_MM = 5
|
||||
|
||||
// TYPE_FRACTION: A basic fraction of the overall size.
|
||||
const val UNIT_FRACTION = 0
|
||||
|
||||
// TYPE_FRACTION: A fraction of the parent size.
|
||||
const val UNIT_FRACTION_PARENT = 1
|
||||
|
||||
@@ -159,10 +182,13 @@ data class ResValue(val dataType: DataType, val data: Int, val size: Short = 0)
|
||||
|
||||
// The mantissa is an integral number -- i.e., 0xnnnnnn.0
|
||||
const val RADIX_23p0 = 0
|
||||
|
||||
// The mantissa magnitude is 16 bits -- i.e, 0xnnnn.nn
|
||||
const val RADIX_16p7 = 1
|
||||
|
||||
// The mantissa magnitude is 8 bits -- i.e, 0xnn.nnnn
|
||||
const val RADIX_8p15 = 2
|
||||
|
||||
// The mantissa magnitude is 0 bits -- i.e, 0x0.nnnnnn
|
||||
const val RADIX_0p23 = 3
|
||||
|
||||
@@ -186,7 +212,8 @@ data class ResValue(val dataType: DataType, val data: Int, val size: Short = 0)
|
||||
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.
|
||||
@@ -208,13 +235,16 @@ 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)
|
||||
|
||||
var flags: Int = 0
|
||||
|
||||
// Index from header of the string data.
|
||||
var stringsStart: Int = 0
|
||||
|
||||
// Index from header of the style data.
|
||||
var stylesStart: Int = 0
|
||||
|
||||
@@ -250,7 +280,8 @@ class ResStringPool private constructor(
|
||||
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 {
|
||||
@@ -278,7 +309,8 @@ class ResStringPool 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()
|
||||
@@ -288,7 +320,8 @@ class ResStringPool private constructor(
|
||||
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) {
|
||||
(header.header.headerSize + (header.stringCount * 4)) > resourceSize
|
||||
) {
|
||||
error("Invalid StringPool: Buffer not large enough for string indices.")
|
||||
}
|
||||
|
||||
@@ -367,6 +400,7 @@ class ResStringPool private constructor(
|
||||
|
||||
((firstByteUTF16.toInt() shl 8) + secondByte) and StringPool.UTF8_ENCODE_LENGTH_MAX
|
||||
}
|
||||
|
||||
else -> firstByteUTF16.toInt()
|
||||
}
|
||||
|
||||
@@ -381,6 +415,7 @@ class ResStringPool private constructor(
|
||||
|
||||
((firstByteUTF8.toInt() shl 8) + secondByte) and StringPool.UTF8_ENCODE_LENGTH_MAX
|
||||
}
|
||||
|
||||
else -> firstByteUTF8.toInt()
|
||||
}
|
||||
|
||||
@@ -414,6 +449,7 @@ class ResStringPool private constructor(
|
||||
stringPosition += 2
|
||||
((firstShort.toInt() shl 16) + secondShort) and StringPool.UTF16_ENCODE_LENGTH_MAX
|
||||
}
|
||||
|
||||
else -> firstShort.toInt()
|
||||
}
|
||||
|
||||
@@ -487,7 +523,8 @@ fun stringToInt(string: String): ResValue? {
|
||||
val isHex: Boolean
|
||||
if (codePointCount >= index + 2
|
||||
&& trimmedString.codePointAt(index) == '0'.code
|
||||
&& trimmedString.codePointAt(index+1) == 'x'.code) {
|
||||
&& trimmedString.codePointAt(index + 1) == 'x'.code
|
||||
) {
|
||||
isHex = true
|
||||
index += 2
|
||||
|
||||
@@ -541,11 +578,13 @@ fun stringToInt(string: String): ResValue? {
|
||||
|
||||
return ResValue(
|
||||
if (isHex) ResValue.DataType.INT_HEX else ResValue.DataType.INT_DEC,
|
||||
value.toInt())
|
||||
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(
|
||||
UnitEntry("px", ResValue.DataType.DIMENSION, ResValue.ComplexFormat.UNIT_PX),
|
||||
@@ -557,7 +596,9 @@ private val unitSuffixes = listOf(
|
||||
UnitEntry("mm", ResValue.DataType.DIMENSION, ResValue.ComplexFormat.UNIT_MM),
|
||||
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? {
|
||||
for (entry in unitSuffixes) {
|
||||
@@ -592,7 +633,8 @@ fun stringToFloat(string: String): ResValue? {
|
||||
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')) {
|
||||
!stringToParse.contains('p')
|
||||
) {
|
||||
// ambiguous value string, resulting in a parse failure.
|
||||
return null
|
||||
}
|
||||
@@ -630,15 +672,19 @@ fun stringToFloat(string: String): ResValue? {
|
||||
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 ->
|
||||
// Magnitude can fit in 8 leading bits of precision.
|
||||
Pair(ResValue.ComplexFormat.RADIX_8p15, 8)
|
||||
|
||||
bits and ((1L shl 39) - 1).inv() == 0L ->
|
||||
// Magnitude can fit in 16 leading bits of precision.
|
||||
Pair(ResValue.ComplexFormat.RADIX_16p7, 16)
|
||||
|
||||
else ->
|
||||
// Need whole range, so no fractional part.
|
||||
Pair(ResValue.ComplexFormat.RADIX_23p0, 23)
|
||||
-1
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.aaptcompiler.android
|
||||
|
||||
import androidx.collection.mutableIntIntMapOf
|
||||
import java.nio.ByteOrder
|
||||
|
||||
private val littleEndian = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN
|
||||
+3
-3
@@ -37,13 +37,13 @@ class BigBuffer(val blockSize: Int = 1024) {
|
||||
var size: Int = 0
|
||||
private set
|
||||
|
||||
internal val blocks = mutableListOf<Block>()
|
||||
val blocks = mutableListOf<Block>()
|
||||
|
||||
internal class Block(
|
||||
class Block(
|
||||
internal var size: Int, internal val blockSize: Int, internal val data: ByteBuffer)
|
||||
|
||||
data class BlockRef internal constructor(
|
||||
internal val start: Int, val size: Int, internal val block: Block) {
|
||||
val start: Int, val size: Int, val block: Block) {
|
||||
|
||||
fun writeByte(value: Byte, location: Int) {
|
||||
if (location + 1 > size) {
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.xml.res
|
||||
|
||||
import com.android.aaptcompiler.ConfigDescription
|
||||
import com.android.aaptcompiler.ResourceConfigValue
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
interface IResourceEntry {
|
||||
val name: String
|
||||
fun findValue(config: ConfigDescription, product: String = ""): ResourceConfigValue?
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.xml.res
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
interface IResourceGroup {
|
||||
|
||||
fun findEntry(name: String, entryId: Short? = null): IResourceEntry?
|
||||
|
||||
fun findEntries(
|
||||
entryId: Short? = null,
|
||||
predicate: (String) -> Boolean
|
||||
): List<IResourceEntry>
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.xml.res
|
||||
|
||||
import com.android.aaptcompiler.ResourceName
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
interface IResourceTable {
|
||||
|
||||
val packages: Collection<IResourceTablePackage>
|
||||
|
||||
fun findResource(name: ResourceName): ISearchResult?
|
||||
|
||||
/**
|
||||
* 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 [IResourceTablePackage] with the requested name or {@code null} if that package
|
||||
* does not exist in the table.
|
||||
*/
|
||||
fun findPackage(name: String): IResourceTablePackage?
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.xml.res
|
||||
|
||||
import com.android.aaptcompiler.AaptResourceType
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
interface IResourceTablePackage {
|
||||
val name: String
|
||||
fun findGroup(type: AaptResourceType, groupId: Byte? = null): IResourceGroup?
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.xml.res
|
||||
|
||||
import com.android.aaptcompiler.Source
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
interface IResourceValue {
|
||||
var source: Source
|
||||
var comment: String
|
||||
var weak: Boolean
|
||||
var translatable: Boolean
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.xml.res
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
interface ISearchResult {
|
||||
|
||||
val tablePackage: IResourceTablePackage
|
||||
|
||||
val group: IResourceGroup
|
||||
|
||||
val entry: IResourceEntry
|
||||
}
|
||||
@@ -24,17 +24,15 @@ plugins {
|
||||
id("kotlin-kapt")
|
||||
}
|
||||
|
||||
|
||||
|
||||
android {
|
||||
namespace = "${BuildConfig.packageName}.xml"
|
||||
namespace = "${BuildConfig.packageName}.xml.utils"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
kapt(libs.google.auto.service)
|
||||
|
||||
api(projects.utilities.lookup)
|
||||
api(projects.xml.aaptcompiler)
|
||||
api(projects.xml.resourcesApi)
|
||||
|
||||
implementation(libs.common.kotlin)
|
||||
implementation(libs.composite.jdt)
|
||||
@@ -43,6 +41,7 @@ dependencies {
|
||||
|
||||
implementation(projects.core.common)
|
||||
implementation(projects.logging.logger)
|
||||
implementation(projects.xml.aaptcompiler)
|
||||
|
||||
testImplementation(libs.tests.junit)
|
||||
testImplementation(libs.tests.robolectric)
|
||||
|
||||
+10
-4
@@ -40,6 +40,7 @@ import com.itsaky.androidide.xml.internal.resources.DefaultResourceTableRegistry
|
||||
import com.itsaky.androidide.xml.internal.resources.DefaultResourceTableRegistry.SingleLineValueEntryType.CATEGORIES
|
||||
import com.itsaky.androidide.xml.internal.resources.DefaultResourceTableRegistry.SingleLineValueEntryType.FEATURES
|
||||
import com.itsaky.androidide.xml.internal.resources.DefaultResourceTableRegistry.SingleLineValueEntryType.SERVICE_ACTIONS
|
||||
import com.itsaky.androidide.xml.res.IResourceTable
|
||||
import com.itsaky.androidide.xml.resources.ResourceTableRegistry
|
||||
import com.itsaky.androidide.xml.resources.ResourceTableRegistry.Companion.PCK_ANDROID
|
||||
import org.slf4j.LoggerFactory
|
||||
@@ -98,7 +99,7 @@ class DefaultResourceTableRegistry : ResourceTableRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
override fun forPlatformDir(platform: File): ResourceTable? {
|
||||
override fun forPlatformDir(platform: File): IResourceTable? {
|
||||
getManifestAttrTable(platform)
|
||||
getActivityActions(platform)
|
||||
getBroadcastActions(platform)
|
||||
@@ -249,14 +250,19 @@ class DefaultResourceTableRegistry : ResourceTableRegistry {
|
||||
AaptResourceType.UNKNOWN
|
||||
}
|
||||
val resName = ResourceName(pck, type, file.nameWithoutExtension)
|
||||
table.addFileReference(resName, ConfigDescription(), Source(file.path), file.path)
|
||||
table.addFileReference(
|
||||
resName, ConfigDescription(),
|
||||
Source(file.path), file.path
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDefaultOptions(): TableExtractorOptions {
|
||||
return TableExtractorOptions(translatable = true, errorOnPositionalArgs = false,
|
||||
visibility = PUBLIC)
|
||||
return TableExtractorOptions(
|
||||
translatable = true, errorOnPositionalArgs = false,
|
||||
visibility = PUBLIC
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateFromDirectory(
|
||||
|
||||
+15
-10
@@ -18,10 +18,10 @@
|
||||
package com.itsaky.androidide.xml.resources
|
||||
|
||||
import com.android.aaptcompiler.ResourceGroup
|
||||
import com.android.aaptcompiler.ResourceTable
|
||||
import com.itsaky.androidide.lookup.Lookup
|
||||
import com.itsaky.androidide.utils.ServiceLoader
|
||||
import com.itsaky.androidide.xml.registry.XmlRegistry
|
||||
import com.itsaky.androidide.xml.res.IResourceTable
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
@@ -29,26 +29,31 @@ import java.io.File
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
interface ResourceTableRegistry : XmlRegistry<ResourceTable> {
|
||||
interface ResourceTableRegistry : XmlRegistry<IResourceTable> {
|
||||
|
||||
companion object {
|
||||
|
||||
const val PCK_ANDROID = "android"
|
||||
|
||||
@JvmStatic
|
||||
val COMPLETION_MODULE_RES = Lookup.Key<Set<ResourceTable>>()
|
||||
val COMPLETION_MODULE_RES = Lookup.Key<Set<IResourceTable>>()
|
||||
|
||||
@JvmStatic
|
||||
val COMPLETION_DEP_RES = Lookup.Key<Set<ResourceTable>>()
|
||||
val COMPLETION_DEP_RES = Lookup.Key<Set<IResourceTable>>()
|
||||
|
||||
@JvmStatic
|
||||
val COMPLETION_FRAMEWORK_RES = Lookup.Key<ResourceTable>()
|
||||
val COMPLETION_FRAMEWORK_RES = Lookup.Key<IResourceTable>()
|
||||
|
||||
@JvmStatic
|
||||
val COMPLETION_MANIFEST_ATTR_RES = Lookup.Key<ResourceTable>()
|
||||
val COMPLETION_MANIFEST_ATTR_RES = Lookup.Key<IResourceTable>()
|
||||
|
||||
private var sInstance: ResourceTableRegistry? = null
|
||||
|
||||
@JvmStatic
|
||||
fun getInstance(): ResourceTableRegistry {
|
||||
val klass = ResourceTableRegistry::class.java
|
||||
return sInstance ?: ServiceLoader.load(klass, klass.classLoader).findFirstOrThrow().also { sInstance = it }
|
||||
return sInstance ?: ServiceLoader.load(klass, klass.classLoader).findFirstOrThrow()
|
||||
.also { sInstance = it }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +62,7 @@ interface ResourceTableRegistry : XmlRegistry<ResourceTable> {
|
||||
*
|
||||
* @param name The package name for the resource table.
|
||||
*/
|
||||
fun forPackage(name: String, vararg resDirs: File): ResourceTable?
|
||||
fun forPackage(name: String, vararg resDirs: File): IResourceTable?
|
||||
|
||||
/**
|
||||
* Remove the resource table entry for the given package name.
|
||||
@@ -71,7 +76,7 @@ interface ResourceTableRegistry : XmlRegistry<ResourceTable> {
|
||||
*
|
||||
* @return The [ResourceGroup] or null if not found or not available.
|
||||
*/
|
||||
fun getManifestAttrTable(platform: File): ResourceTable?
|
||||
fun getManifestAttrTable(platform: File): IResourceTable?
|
||||
|
||||
/** Get the list of all activity actions for the given [platform] directory. */
|
||||
fun getActivityActions(platform: File): List<String>
|
||||
@@ -88,7 +93,7 @@ interface ResourceTableRegistry : XmlRegistry<ResourceTable> {
|
||||
/** Get the list of all features for the given [platform] directory. */
|
||||
fun getFeatures(platform: File): List<String>
|
||||
|
||||
override fun forPlatformDir(platform: File): ResourceTable? {
|
||||
override fun forPlatformDir(platform: File): IResourceTable? {
|
||||
return forPackage(PCK_ANDROID, File(platform, "data/res"))
|
||||
}
|
||||
}
|
||||
|
||||
+25
-7
@@ -155,7 +155,13 @@ class ResourceTableRegistryTest {
|
||||
this.packages.first().apply { assertThat(this.name).isEqualTo("android") }
|
||||
}
|
||||
|
||||
resourceTable!!.findResource(ResourceName(pck = "android", type = STRING, entry = "ok")).apply {
|
||||
resourceTable!!.findResource(
|
||||
com.android.aaptcompiler.ResourceName(
|
||||
pck = "android",
|
||||
type = STRING,
|
||||
entry = "ok"
|
||||
)
|
||||
).apply {
|
||||
assertThat(this).isNotNull()
|
||||
assertThat(this!!.entry).isNotNull()
|
||||
assertThat(this.entry.values).isNotEmpty()
|
||||
@@ -163,14 +169,20 @@ class ResourceTableRegistryTest {
|
||||
assertThat(this).isNotNull()
|
||||
assertThat(this!!.value).isNotNull()
|
||||
this.value.apply {
|
||||
assertThat(this).isInstanceOf(BasicString::class.java)
|
||||
assertThat(this).isInstanceOf(com.android.aaptcompiler.BasicString::class.java)
|
||||
assertThat(this.toString()).isEqualTo("OK")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceTable
|
||||
.findResource(ResourceName(pck = "android", type = STRING, entry = "cancel"))
|
||||
.findResource(
|
||||
com.android.aaptcompiler.ResourceName(
|
||||
pck = "android",
|
||||
type = STRING,
|
||||
entry = "cancel"
|
||||
)
|
||||
)
|
||||
.apply {
|
||||
assertThat(this).isNotNull()
|
||||
assertThat(this!!.entry).isNotNull()
|
||||
@@ -179,14 +191,20 @@ class ResourceTableRegistryTest {
|
||||
assertThat(this).isNotNull()
|
||||
assertThat(this!!.value).isNotNull()
|
||||
this.value.apply {
|
||||
assertThat(this).isInstanceOf(BasicString::class.java)
|
||||
assertThat(this).isInstanceOf(com.android.aaptcompiler.BasicString::class.java)
|
||||
assertThat(this.toString()).isEqualTo("Cancel")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceTable
|
||||
.findResource(ResourceName(pck = "android", type = COLOR, entry = "holo_red_dark"))
|
||||
.findResource(
|
||||
com.android.aaptcompiler.ResourceName(
|
||||
pck = "android",
|
||||
type = COLOR,
|
||||
entry = "holo_red_dark"
|
||||
)
|
||||
)
|
||||
.apply {
|
||||
assertThat(this).isNotNull()
|
||||
assertThat(this!!.entry).isNotNull()
|
||||
@@ -196,8 +214,8 @@ class ResourceTableRegistryTest {
|
||||
assertThat(this!!.value).isNotNull()
|
||||
this.value.apply {
|
||||
assertThat(this).isNotNull()
|
||||
assertThat(this!!).isInstanceOf(BinaryPrimitive::class.java)
|
||||
(this as BinaryPrimitive).resValue.apply {
|
||||
assertThat(this!!).isInstanceOf(com.android.aaptcompiler.BinaryPrimitive::class.java)
|
||||
(this as com.android.aaptcompiler.BinaryPrimitive).resValue.apply {
|
||||
assertThat(this).isNotNull()
|
||||
assertThat(this.dataType).isEqualTo(DataType.INT_COLOR_ARGB8)
|
||||
assertThat(this.data)
|
||||
|
||||
Reference in New Issue
Block a user