Skip to content
This repository has been archived by the owner on Oct 18, 2024. It is now read-only.

Commit

Permalink
fix(xml): extract API classes from aaptcompiler to :xml:resources-api
Browse files Browse the repository at this point in the history
  • Loading branch information
itsaky committed Jul 20, 2024
1 parent 6fcb177 commit 1d68499
Show file tree
Hide file tree
Showing 96 changed files with 1,900 additions and 1,061 deletions.
1 change: 1 addition & 0 deletions .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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) }
Expand All @@ -363,22 +363,22 @@ 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
}.also { libs -> deps = libs.size }.mapNotNull { library ->
ResourceTableRegistry.getInstance().let { registry ->
registry.isLoggingEnabled = false
registry.forPackage(
library.packageName,
library.androidLibraryData!!.resFolder,
).also {
registry.isLoggingEnabled = true
}
}
})
library.type == ANDROID_LIBRARY && library.androidLibraryData!!.resFolder.exists() && library.findPackageName() != UNKNOWN_PACKAGE
}.also { libs -> deps = libs.size }.mapNotNull { library ->
ResourceTableRegistry.getInstance().let { registry ->
registry.isLoggingEnabled = false
registry.forPackage(
library.packageName,
library.androidLibraryData!!.resFolder,
).also {
registry.isLoggingEnabled = true
}
}
})

log.info("Created {} resource tables for {} dependencies of module '{}'", it.size, deps, path)
}
Expand All @@ -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()
Expand All @@ -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) {
Expand All @@ -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())
Expand All @@ -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)
}
Expand Down
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ include(
":xml:aaptcompiler",
":xml:dom",
":xml:lsp",
":xml:resources-api",
":xml:utils",
)

Expand Down
5 changes: 3 additions & 2 deletions utilities/shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -72,31 +75,31 @@ 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
}

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()
}
Expand Down Expand Up @@ -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
}
}
Expand All @@ -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
}
Expand All @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -441,15 +444,15 @@ fun <T> resolveQualifiedResourceReference(
}

fun <T> resolveResourceReference(
table: ResourceTable,
table: IResourceTable,
type: AaptResourceType,
pck: String,
name: String,
def: T,
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,
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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 {
Expand Down Expand Up @@ -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))
Expand Down
Loading

0 comments on commit 1d68499

Please sign in to comment.