diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 1694d3138..aaa7ffdad 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -271,6 +271,7 @@ + diff --git a/core/projects/src/main/java/com/itsaky/androidide/projects/android/AndroidModule.kt b/core/projects/src/main/java/com/itsaky/androidide/projects/android/AndroidModule.kt index fcee7fdb1..93e064843 100644 --- a/core/projects/src/main/java/com/itsaky/androidide/projects/android/AndroidModule.kt +++ b/core/projects/src/main/java/com/itsaky/androidide/projects/android/AndroidModule.kt @@ -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 { + fun getSourceResourceTables(): Set { val set = mutableSetOf(getResourceTable() ?: return emptySet()) getCompileModuleProjects().filterIsInstance().forEach { it.getResourceTable()?.also { table -> set.add(table) } @@ -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 { - return mutableSetOf().also { + fun getDependencyResourceTables(): Set { + return mutableSetOf().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) } @@ -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 { + ): List { if (pck == SdkConstants.ANDROID_PKG) { return getFrameworkResourceTable()?.let { listOf(it) } ?: emptyList() } - val tables: List = mutableListOf().apply { + val tables: List = mutableListOf().apply { getResourceTable()?.let { add(it) } addAll(getSourceResourceTables()) addAll(getDependencyResourceTables()) } - val result = mutableListOf() + val result = mutableListOf() 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 { - return mutableSetOf().apply { + fun getAllResourceTables(): Set { + return mutableSetOf().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) } diff --git a/settings.gradle.kts b/settings.gradle.kts index cb0bcab4d..798ed9681 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -177,6 +177,7 @@ include( ":xml:aaptcompiler", ":xml:dom", ":xml:lsp", + ":xml:resources-api", ":xml:utils", ) diff --git a/utilities/shared/build.gradle.kts b/utilities/shared/build.gradle.kts index 3d6ff349f..78c21729a 100644 --- a/utilities/shared/build.gradle.kts +++ b/utilities/shared/build.gradle.kts @@ -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) diff --git a/utilities/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/utils/basicParseUtils.kt b/utilities/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/utils/basicParseUtils.kt index 3feeba09b..9fcdbadbf 100644 --- a/utilities/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/utils/basicParseUtils.kt +++ b/utilities/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/utils/basicParseUtils.kt @@ -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 ((Value?) -> T?).arrayResolver(value: Value?): Array? { - 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 resolveQualifiedResourceReference( } fun resolveResourceReference( - table: ResourceTable, + table: IResourceTable, type: AaptResourceType, pck: String, name: String, @@ -449,7 +452,7 @@ fun 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 resolveResourceReference( } fun resolveResourceReference( - table: ResourceTable, - pck: ResourceTablePackage, - entry: ResourceEntry, + table: IResourceTable, + pck: IResourceTablePackage, + entry: IResourceEntry, type: AaptResourceType, name: String, def: T, diff --git a/utilities/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/utils/lookup.kt b/utilities/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/utils/lookup.kt index 8805cd475..9b8fc4998 100644 --- a/utilities/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/utils/lookup.kt +++ b/utilities/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/utils/lookup.kt @@ -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)) diff --git a/utilities/xml-inflater/src/main/java/com/itsaky/androidide/inflater/utils/inflaterUtils.kt b/utilities/xml-inflater/src/main/java/com/itsaky/androidide/inflater/utils/inflaterUtils.kt index db9d753f0..469f31567 100644 --- a/utilities/xml-inflater/src/main/java/com/itsaky/androidide/inflater/utils/inflaterUtils.kt +++ b/utilities/xml-inflater/src/main/java/com/itsaky/androidide/inflater/utils/inflaterUtils.kt @@ -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 { +fun processXmlFile(file: File, expectedType: com.android.aaptcompiler.AaptResourceType): Pair { 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 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) -} diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ConfigDescription.kt b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ConfigDescription.kt deleted file mode 100644 index def299ea0..000000000 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ConfigDescription.kt +++ /dev/null @@ -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 -} diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/PseudolocaleGenerator.kt b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/PseudolocaleGenerator.kt index d5450e4b3..23008eebf 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/PseudolocaleGenerator.kt +++ b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/PseudolocaleGenerator.kt @@ -46,7 +46,8 @@ internal fun mergeSpans(string: StyledString): List { } 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() diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/Pseudolocalizer.kt b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/Pseudolocalizer.kt index ad9675ec5..fcbf3b0eb 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/Pseudolocalizer.kt +++ b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/Pseudolocalizer.kt @@ -272,6 +272,7 @@ class PseudoMethodAccent: PseudoMethodImpl() { var currentChar = source[currentIndex] val htmlPartial = StringBuilder() + @Suppress("KotlinConstantConditions") htmlTag@ while (currentIndex < size) { if (currentChar == '&') { diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceCompiler.kt b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceCompiler.kt index 4ff819b19..209dae94d 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceCompiler.kt +++ b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceCompiler.kt @@ -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) { @@ -167,12 +170,13 @@ private fun getCompileMethod(pathData: ResourcePathData, logger: BlameLogger): * @throws IllegalStateException A failure occurred in processing this resource. */ private fun compileTable( - pathData: ResourcePathData, - outputDirectory: File, - options: ResourceCompilerOptions, - logger: BlameLogger) { + pathData: ResourcePathData, + outputDirectory: File, + options: ResourceCompilerOptions, + 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) @@ -220,17 +224,17 @@ private fun compileTable( if (group.type != AaptResourceType.MACRO) { 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}") - 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}") - } + val visibility = getVisibility(entry.value.values, group.type) + 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.appendLine("public int styleable ${entry.key}${childPackage}_${it.name.entry}") } + } } } } @@ -264,10 +268,10 @@ private fun getVisibility(values: Collection, type: AaptResourceT * @param outputDirectory the directory to which the compiled file is to be placed. */ private fun compileFile( - pathData: ResourcePathData, - outputDirectory: File, - options: ResourceCompilerOptions, - logger: BlameLogger?) { + pathData: ResourcePathData, + outputDirectory: File, + options: ResourceCompilerOptions, + logger: BlameLogger?) { val outputFile = File(outputDirectory, pathData.getIntermediateContainerFilename()) logger?.info("Compiling file ${pathData.file.absolutePath} to $outputFile") pathData.file.inputStream().use { @@ -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) @@ -306,10 +310,10 @@ private fun compileFile( * @throws IllegalStateException A failure occurred in processing this resource. */ private fun compileXml( - pathData: ResourcePathData, - outputDirectory: File, - options: ResourceCompilerOptions, - logger: BlameLogger?) { + pathData: ResourcePathData, + outputDirectory: File, + options: ResourceCompilerOptions, + logger: BlameLogger?) { val outputFile = File(outputDirectory, pathData.getIntermediateContainerFilename()) logger?.info("Compiling xml file ${pathData.file.absolutePath} to $outputFile") @@ -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()) } @@ -367,10 +371,10 @@ private fun compileXml( * @param outputDirectory the directory in which the processed file will be placed. */ private fun compilePng( - pathData: ResourcePathData, - outputDirectory: File, - options: ResourceCompilerOptions, - logger: BlameLogger?) { + pathData: ResourcePathData, + outputDirectory: File, + options: ResourceCompilerOptions, + logger: BlameLogger?) { logger?.info("Compiling image file ${pathData.file.absolutePath}") if (pathData.extension == PATCH_9_EXTENSION) { error("Patch 9 PNG processing is not supported with the JVM Android resource compiler.") diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceTable.kt b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceTable.kt index bfb707e45..238d8284f 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceTable.kt +++ b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceTable.kt @@ -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() + override val packages = mutableListOf() /** * 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,14 +284,15 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog packages.add(newPackage) newPackage } + else -> tablePackage } } fun sort() { - packages.sortWith(compareBy({it.name}, {it.id})) + packages.sortWith(compareBy({ it.name }, { it.id })) for (pkg in packages) { - pkg.groups.sortWith(compareBy({it.type.ordinal}, {it.id})) + pkg.groups.sortWith(compareBy({ it.type.ordinal }, { it.id })) for (group in pkg.groups) { for (entryByName in group.entries.values) { for (entry in entryByName.values) { @@ -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 } @@ -416,13 +450,14 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog val useId = !validateResources && id.isValidDynamicId() val resourceGroup = - tablePackage.findOrCreateGroup(name.type, if(useId) id.getTypeId() else null) + tablePackage.findOrCreateGroup(name.type, if (useId) id.getTypeId() else null) val groupId = resourceGroup.id if (checkId && groupId != null && groupId != id.getTypeId()) { logError( blameSource(source), "Failed to add resource '$name' with ID ${id.toString(16)} because type " + - "'${resourceGroup.type.tagName}' already has ID ${groupId.toString(16)}.") + "'${resourceGroup.type.tagName}' already has ID ${groupId.toString(16)}." + ) return false } @@ -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.") + blameSource(source), + "Failed to add resource '$name' as private (java-symbol) because it was " + + "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).") + blameSource(source), + "Failed to add resource '$name' as public because it was previously defined as " + + "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 @@ -516,7 +560,7 @@ class ResourceTable(val validateResources: Boolean = false, val logger: BlameLog } companion object { - fun resolveValueCollision(existing: Value, incoming: Value):CollisionResult { + fun resolveValueCollision(existing: Value, incoming: Value): CollisionResult { val existingAttr = existing as? AttributeResource val incomingAttr = incoming as? AttributeResource @@ -565,19 +609,22 @@ 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 in an overlay */ -class AllowNew ( +class AllowNew( val source: Source, - val comment: String) + val comment: String +) -class Overlayable ( +class Overlayable( val name: String, val actor: String, - val source: Source) { + val source: Source +) { - constructor(): this("","", Source("")) + constructor() : this("", "", Source("")) companion object { const val ACTOR_SCHEME = "overlay" @@ -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,45 +656,54 @@ 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() - 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} + groups.find { type == it.type } } fun findOrCreateGroup(type: AaptResourceType, groupId: Byte? = null): ResourceGroup { val group = findGroup(type, groupId) - return when(group) { + return when (group) { null -> { val newGroup = ResourceGroup(type) newGroup.id = groupId 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 @@ -664,18 +721,18 @@ class ResourceGroup(val type : AaptResourceType) { // To get Styleable's children we need to reach the ResourceEntry's value first internal fun getStyleable(entry: Map.Entry>): Styleable { - // To get the actual value we need to find the correct Item that's nested deep in the map - // TODO: Keep children at map value level. - val mapEntry = entry.value - val styleableContainer = mapEntry.values.first().values - // Only one Item should be held in the container - if (styleableContainer.size != 1) - error("Too many resources in one entry: ${styleableContainer.size}") - // The children will be present under the Styleable Item. - return styleableContainer[0].value!! as Styleable + // To get the actual value we need to find the correct Item that's nested deep in the map + // TODO: Keep children at map value level. + val mapEntry = entry.value + val styleableContainer = mapEntry.values.first().values + // Only one Item should be held in the container + if (styleableContainer.size != 1) + error("Too many resources in one entry: ${styleableContainer.size}") + // The children will be present under the Styleable Item. + 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,22 +741,34 @@ class ResourceGroup(val type : AaptResourceType) { } } + override fun findEntries(entryId: Short?, predicate: (String) -> Boolean): List { + 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) { + return when (entry) { null -> { val newEntry = ResourceEntry(name) newEntry.id = entryId entries.getOrPut(name) { TreeMap(nullsFirst()) }[entryId] = newEntry newEntry } + else -> entry } } } /** Represents a resource entry, which may have varying values for each defined configuration. */ -class ResourceEntry(val name : String) { +class ResourceEntry(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() - 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) diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/TableExtractor.kt b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/TableExtractor.kt index 089938485..dd73d1102 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/TableExtractor.kt +++ b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/TableExtractor.kt @@ -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: // 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( - "Ignoring configuration '${parsedResource.config}' for <${element.name}> tag.", - blameSource(source, element.location)) + logger.warning( + "Ignoring configuration '${parsedResource.config}' for <${element.name}> tag.", + 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")) @@ -1774,7 +1787,7 @@ class TableExtractor( */ private fun parsePlural( element: StartElement, eventReader: XMLEventReader, parsedResource: ParsedResource): Boolean { - parsedResource.name = parsedResource.name.copy(type=AaptResourceType.PLURALS) + parsedResource.name = parsedResource.name.copy(type= AaptResourceType.PLURALS) val plural = Plural() @@ -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( - "Ignoring configuration '${parsedResource.config}' for <${element.name}> tag.", - blameSource(source, element.location)) + logger.warning( + "Ignoring configuration '${parsedResource.config}' for <${element.name}> tag.", + blameSource(source, element.location) + ) } val typeAttribute = element.getAttributeByName(QName("type")) diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/XmlProcessor.kt b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/XmlProcessor.kt index b5cb7544f..5968f3af1 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/XmlProcessor.kt +++ b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/XmlProcessor.kt @@ -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 ) } } diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/XmlUtil.kt b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/XmlUtil.kt index e2fac5248..20443567a 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/XmlUtil.kt +++ b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/XmlUtil.kt @@ -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() diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/proto/ProtoDeserialize.kt b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/proto/ProtoDeserialize.kt index dc7de2d48..e313dc962 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/proto/ProtoDeserialize.kt +++ b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/proto/ProtoDeserialize.kt @@ -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() - 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() 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() - 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 } diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/proto/ProtoSerialize.kt b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/proto/ProtoSerialize.kt index d4b5f19dd..117c389bb 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/proto/ProtoSerialize.kt +++ b/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/proto/ProtoSerialize.kt @@ -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() diff --git a/xml/aaptcompiler/src/main/java/com/itsaky/androidide/aapt/Resources.kt b/xml/aaptcompiler/src/main/java/com/itsaky/androidide/aapt/Resources.kt deleted file mode 100644 index e7d599967..000000000 --- a/xml/aaptcompiler/src/main/java/com/itsaky/androidide/aapt/Resources.kt +++ /dev/null @@ -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 { - val result = mutableListOf() - 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 -} diff --git a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/BlameLoggerTest.kt b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/BlameLoggerTest.kt index 443a0c8a6..d6c2936f1 100644 --- a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/BlameLoggerTest.kt +++ b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/BlameLoggerTest.kt @@ -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) } diff --git a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/PseudolocaleGeneratorTest.kt b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/PseudolocaleGeneratorTest.kt index 9092527a4..5b3d2bb9d 100644 --- a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/PseudolocaleGeneratorTest.kt +++ b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/PseudolocaleGeneratorTest.kt @@ -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()) diff --git a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/ResourceCompilerTest.kt b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/ResourceCompilerTest.kt index 41ef66e72..4812b7a5f 100644 --- a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/ResourceCompilerTest.kt +++ b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/ResourceCompilerTest.kt @@ -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 @@ -57,10 +56,10 @@ class ResourceCompilerTest { } private fun testXmlFile( - type: AaptResourceType, - input: String, - config: String = "", - options: ResourceCompilerOptions = ResourceCompilerOptions() + type: AaptResourceType, + input: String, + config: String = "", + options: ResourceCompilerOptions = ResourceCompilerOptions() ): File { val resourceFolder = tempFolder.newFolder(type.tagName) val configSuffix = if (config.isEmpty()) "" else "-$config" @@ -85,11 +84,11 @@ class ResourceCompilerTest { } private fun testPngFile( - type: AaptResourceType, - input: String, - config: String = "", - isPatch9: Boolean = false, - options: ResourceCompilerOptions = ResourceCompilerOptions() + type: AaptResourceType, + input: String, + config: String = "", + isPatch9: Boolean = false, + options: ResourceCompilerOptions = ResourceCompilerOptions() ): File { val resourceFolder = tempFolder.newFolder(type.tagName) val configSuffix = if (config.isEmpty()) "" else "-$config" diff --git a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/ResourceTableTest.kt b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/ResourceTableTest.kt index e4d8ccc94..c4c9d41ea 100644 --- a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/ResourceTableTest.kt +++ b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/ResourceTableTest.kt @@ -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( diff --git a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/ResourceUtilsTest.kt b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/ResourceUtilsTest.kt index a503389bf..186579f8c 100644 --- a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/ResourceUtilsTest.kt +++ b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/ResourceUtilsTest.kt @@ -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()))) } } \ No newline at end of file diff --git a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/TableExtractorTest.kt b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/TableExtractorTest.kt index c7e6feabc..63fb0d0b9 100644 --- a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/TableExtractorTest.kt +++ b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/TableExtractorTest.kt @@ -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) } diff --git a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/XmlProcessorTest.kt b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/XmlProcessorTest.kt index bc57d695f..3395b5777 100644 --- a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/XmlProcessorTest.kt +++ b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/XmlProcessorTest.kt @@ -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) { diff --git a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/XmlResourceBuilderTest.kt b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/XmlResourceBuilderTest.kt index 8ef57ad78..6a7373df0 100644 --- a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/XmlResourceBuilderTest.kt +++ b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/XmlResourceBuilderTest.kt @@ -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() { diff --git a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/android/ResTable_configTest.kt b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/android/ResTableConfigTest.kt similarity index 90% rename from xml/aaptcompiler/src/test/java/com/android/aaptcompiler/android/ResTable_configTest.kt rename to xml/aaptcompiler/src/test/java/com/android/aaptcompiler/android/ResTableConfigTest.kt index 0fafa94ae..d09637469 100644 --- a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/android/ResTable_configTest.kt +++ b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/android/ResTableConfigTest.kt @@ -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,8 +406,8 @@ class ResTable_configTest { Truth.assertThat(config.isMoreSpecificThan(config)).isFalse() } - for (i in 0.until(greatestToLeast.size)) { - for (j in (i+1).until(greatestToLeast.size)) { + for (i in greatestToLeast.indices) { + for (j in (i + 1).until(greatestToLeast.size)) { val greater = greatestToLeast[i] val lesser = greatestToLeast[j] try { @@ -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,8 +484,8 @@ class ResTable_configTest { Truth.assertThat(config.compareLocales(config)).isEqualTo(0) } - for (i in 0.until(firstToLast.size)) { - for (j in (i+1).until(firstToLast.size)) { + for (i in firstToLast.indices) { + for (j in (i + 1).until(firstToLast.size)) { val less = firstToLast[i] val more = firstToLast[j] try { @@ -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,8 +590,8 @@ class ResTable_configTest { Truth.assertThat(config.compareTo(config)).isEqualTo(0) } - for (i in 0.until(firstToLast.size)) { - for (j in (i+1).until(firstToLast.size)) { + for (i in firstToLast.indices) { + for (j in (i + 1).until(firstToLast.size)) { val less = firstToLast[i] val more = firstToLast[j] try { @@ -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,15 +716,16 @@ 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 (j in (i+1).until(leastToGreatest.size)) { + for (i in leastToGreatest.indices) { + for (j in (i + 1).until(leastToGreatest.size)) { val worse = leastToGreatest[i] val better = leastToGreatest[j] try { @@ -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,15 +798,16 @@ 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 (j in (i+1).until(leastToGreatest.size)) { + for (i in leastToGreatest.indices) { + for (j in (i + 1).until(leastToGreatest.size)) { val worse = leastToGreatest[i] val better = leastToGreatest[j] try { @@ -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 @@ -918,23 +979,43 @@ class ResTable_configTest { Truth.assertThat(config3.toString()).isEqualTo("en") val config4 = - ResTableConfig(language = ResTableConfig.ENGLISH, country = ResTableConfig.UNITED_STATES) + ResTableConfig(language = ResTableConfig.ENGLISH, country = ResTableConfig.UNITED_STATES) Truth.assertThat(config4.toString()).isEqualTo("en-rUS") 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" + ) } } diff --git a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/proto/ProtoSerializeTest.kt b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/proto/ProtoSerializeTest.kt index 19c477113..d02e3b767 100644 --- a/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/proto/ProtoSerializeTest.kt +++ b/xml/aaptcompiler/src/test/java/com/android/aaptcompiler/proto/ProtoSerializeTest.kt @@ -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() diff --git a/xml/aaptcompiler/src/test/java/com/itsaky/androidide/aaptcompiler/CompilerTest.kt b/xml/aaptcompiler/src/test/java/com/itsaky/androidide/aaptcompiler/CompilerTest.kt index 33718c6a4..8e507adbb 100644 --- a/xml/aaptcompiler/src/test/java/com/itsaky/androidide/aaptcompiler/CompilerTest.kt +++ b/xml/aaptcompiler/src/test/java/com/itsaky/androidide/aaptcompiler/CompilerTest.kt @@ -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) @@ -49,17 +51,18 @@ class CompilerTest { compileResource(input, output, ResourceCompilerOptions(), BlameLogger(StdLogger(VERBOSE))) println("Compiled in ${System.nanoTime() - start} nano seconds") } - + @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()) diff --git a/xml/dom/build.gradle.kts b/xml/dom/build.gradle.kts index 9158b6773..1dfc909c7 100644 --- a/xml/dom/build.gradle.kts +++ b/xml/dom/build.gradle.kts @@ -22,8 +22,6 @@ plugins { id("org.jetbrains.kotlin.jvm") } - - dependencies { implementation(projects.utilities.shared) implementation(libs.composite.jaxp) diff --git a/xml/lsp/build.gradle.kts b/xml/lsp/build.gradle.kts index 6e9c6df62..9f52a7585 100644 --- a/xml/lsp/build.gradle.kts +++ b/xml/lsp/build.gradle.kts @@ -27,7 +27,7 @@ plugins { android { - namespace = "${BuildConfig.packageName}.lsp.xml" + namespace = "${BuildConfig.packageName}.xml.lsp" } kapt { diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/CodeFormatProvider.java b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/CodeFormatProvider.java index 1fd4fe39d..d22d840c8 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/CodeFormatProvider.java +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/CodeFormatProvider.java @@ -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; diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/AttrCompletionProvider.kt b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/AttrCompletionProvider.kt index 329f8b3c4..80e48eb5a 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/AttrCompletionProvider.kt +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/AttrCompletionProvider.kt @@ -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() + val packages = mutableSetOf() 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 { + protected open fun findNodeStyleables(node: DOMNode, styleables: IResourceGroup): Set { 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 { val result = mutableSetOf() @@ -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, suffix: String = "" @@ -311,7 +310,7 @@ open class AttrCompletionProvider(provider: ICompletionProvider) : } protected open fun addWidgetStyleable( - styleables: ResourceGroup, + styleables: IResourceGroup, widget: String, result: MutableSet, 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, @@ -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) diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/AttrValueCompletionProvider.kt b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/AttrValueCompletionProvider.kt index c69ea2f96..92fd55be0 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/AttrValueCompletionProvider.kt +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/AttrValueCompletionProvider.kt @@ -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 = AaptResourceType.values().map { it.tagName } + private fun listResTypes(): List = + com.android.aaptcompiler.AaptResourceType.values().map { it.tagName } protected open fun resTableForFindAttr() = platformResourceTable() private fun findAttr( - tables: Set, + tables: Set, namespace: String, pck: String, attr: String @@ -248,7 +251,7 @@ open class AttrValueCompletionProvider(provider: ICompletionProvider) : } private fun findAttr( - packages: Collection, + packages: Collection, 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) { - 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, checkPck: (String) -> Boolean = { true } @@ -361,28 +380,28 @@ open class AttrValueCompletionProvider(provider: ICompletionProvider) : return@mapNotNull null } pck.name to - pck.findGroup(type)?.findEntries { entryName -> - matchLevel(entryName, prefix) != NO_MATCH - } + pck.findGroup(type)?.findEntries { entryName -> + matchLevel(entryName, prefix) != NO_MATCH + } } } .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 { + override fun findResourceTables(nsUri: String?): Set { // When completing values, all namespaces must be included val tables = HashSet(findAllModuleResourceTables()) diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/IXmlCompletionProvider.kt b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/IXmlCompletionProvider.kt index 31a36f130..319a76e3e 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/IXmlCompletionProvider.kt +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/IXmlCompletionProvider.kt @@ -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 @@ -54,7 +53,7 @@ import org.slf4j.LoggerFactory * @author Akash Yadav */ abstract class IXmlCompletionProvider(private val provider: ICompletionProvider) { - + protected lateinit var nodeAtCursor: DOMNode protected lateinit var attrAtCursor: DOMAttr protected lateinit var allNamespaces: Set> @@ -62,7 +61,7 @@ abstract class IXmlCompletionProvider(private val provider: ICompletionProvider) companion object { @JvmStatic protected val log: Logger = LoggerFactory.getLogger(IXmlCompletionProvider::class.java) - + const val NAMESPACE_PREFIX = "http://schemas.android.com/apk/res/" const val NAMESPACE_AUTO = "http://schemas.android.com/apk/res-auto" } @@ -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 { + protected open fun findResourceTables(nsUri: String?): Set { if (nsUri.isNullOrBlank()) { return emptySet() } @@ -287,11 +286,11 @@ abstract class IXmlCompletionProvider(private val provider: ICompletionProvider) return setOf(table) } - protected open fun findAllModuleResourceTables(): Set { + protected open fun findAllModuleResourceTables(): Set { val lookup = Lookup.getDefault() val sourceResTables = lookup.lookup(ResourceTableRegistry.COMPLETION_MODULE_RES) ?: emptySet() val depResTables = lookup.lookup(ResourceTableRegistry.COMPLETION_DEP_RES) ?: emptySet() - return mutableSetOf().also { + return mutableSetOf().also { it.addAll(sourceResTables) it.addAll(depResTables) } diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/common/CommonAttrCompletionProvider.kt b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/common/CommonAttrCompletionProvider.kt index 0a8b2d810..252ec11d6 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/common/CommonAttrCompletionProvider.kt +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/common/CommonAttrCompletionProvider.kt @@ -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 { + override fun findNodeStyleables(node: DOMNode, styleables: IResourceGroup): Set { val name = node.nodeName val styleable = styleables diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/etc/InheritingAttrCompletionProvider.kt b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/etc/InheritingAttrCompletionProvider.kt index 0a5f2a262..b80f9cbef 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/etc/InheritingAttrCompletionProvider.kt +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/etc/InheritingAttrCompletionProvider.kt @@ -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 { + override fun findNodeStyleables(node: DOMNode, styleables: IResourceGroup): Set { val nodeStyleables = mutableSetOf() val name = node.nodeName val entryName = tagTransform.transform(name, nodeAtCursor.parentNode?.nodeName ?: "") diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestAttrCompletionProvider.kt b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestAttrCompletionProvider.kt index 31cad9a7a..617c031cf 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestAttrCompletionProvider.kt +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestAttrCompletionProvider.kt @@ -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 { + override fun findNodeStyleables(node: DOMNode, styleables: IResourceGroup): Set { 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) } diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestAttrValueCompletionProvider.kt b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestAttrValueCompletionProvider.kt index 84b57b543..295716a4b 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestAttrValueCompletionProvider.kt +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestAttrValueCompletionProvider.kt @@ -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 { + override fun findResourceTables(nsUri: String?): Set { val tables = manifestResourceTable().toMutableSet() if (nsUri.isNullOrBlank()) { return tables diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestTagCompletionProvider.kt b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestTagCompletionProvider.kt index ae3e05482..aa5e5ea2a 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestTagCompletionProvider.kt +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestTagCompletionProvider.kt @@ -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 diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifestFileCompletions.kt b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifestFileCompletions.kt index d6569eb5d..faf3c87dc 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifestFileCompletions.kt +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifestFileCompletions.kt @@ -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 { +fun manifestResourceTable(): Set { return setOf( - Lookup.getDefault().lookup(ResourceTableRegistry.COMPLETION_MANIFEST_ATTR_RES) ?: return emptySet() + Lookup.getDefault().lookup(ResourceTableRegistry.COMPLETION_MANIFEST_ATTR_RES) + ?: return emptySet() ) } \ No newline at end of file diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/xmlCompletions.kt b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/xmlCompletions.kt index 0dc735727..b85a354de 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/xmlCompletions.kt +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/xmlCompletions.kt @@ -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,22 +36,21 @@ 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) } fun findAllNamespaces(node: DOMNode): MutableSet> { val namespaces = mutableSetOf>() var curr: DOMNode? = node - + while (curr != null && !curr.isOwnerDocument) { - - @Suppress("SENSELESS_COMPARISON") // attributes might be null. Ignore warning + if (curr.attributes == null) { curr = curr.parentNode continue } - + for (i in 0 until curr.attributes.length) { val currAttr = curr.getAttributeAtIndex(i) if (currAttr.isXmlns) { diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMAttributeFormatter.java b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMAttributeFormatter.java index b34ebe717..e6e552ea4 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMAttributeFormatter.java +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMAttributeFormatter.java @@ -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. * diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMCDATAFormatter.java b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMCDATAFormatter.java index de7944ea9..fc067a80d 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMCDATAFormatter.java +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMCDATAFormatter.java @@ -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; diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMCommentFormatter.java b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMCommentFormatter.java index cff03062d..04afc8287 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMCommentFormatter.java +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMCommentFormatter.java @@ -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 { diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMDocTypeFormatter.java b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMDocTypeFormatter.java index f50d1de5f..7fb004dab 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMDocTypeFormatter.java +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMDocTypeFormatter.java @@ -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. * diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMElementFormatter.java b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMElementFormatter.java index a1a68fe1a..d36c8e437 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMElementFormatter.java +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMElementFormatter.java @@ -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. * diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMProcessingInstructionFormatter.java b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMProcessingInstructionFormatter.java index 9f364f5d0..099bf33ea 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMProcessingInstructionFormatter.java +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMProcessingInstructionFormatter.java @@ -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. * diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMTextFormatter.java b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMTextFormatter.java index 30ff4365f..de6c227dc 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMTextFormatter.java +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/DOMTextFormatter.java @@ -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. * diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/TextEditUtils.java b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/TextEditUtils.java index 9d387eaaa..b91483344 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/TextEditUtils.java +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/TextEditUtils.java @@ -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}. diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/XMLFormatter.java b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/XMLFormatter.java index a0148d944..b88a54cfe 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/XMLFormatter.java +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/XMLFormatter.java @@ -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. */ diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/XMLFormatterDocument.java b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/XMLFormatterDocument.java index 5d2bdc049..f997e388c 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/XMLFormatterDocument.java +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/XMLFormatterDocument.java @@ -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. diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/XMLFormatterDocumentNew.java b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/XMLFormatterDocumentNew.java index 538f6dd82..9c94a1620 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/XMLFormatterDocumentNew.java +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/providers/format/XMLFormatterDocumentNew.java @@ -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. diff --git a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/utils/XMLBuilder.java b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/utils/XMLBuilder.java index 8f6e33548..809ede854 100644 --- a/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/utils/XMLBuilder.java +++ b/xml/lsp/src/main/java/com/itsaky/androidide/lsp/xml/utils/XMLBuilder.java @@ -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; diff --git a/xml/resources-api/.gitignore b/xml/resources-api/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/xml/resources-api/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/xml/resources-api/build.gradle.kts b/xml/resources-api/build.gradle.kts new file mode 100644 index 000000000..d08d40ab1 --- /dev/null +++ b/xml/resources-api/build.gradle.kts @@ -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 . + */ + +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) +} \ No newline at end of file diff --git a/xml/resources-api/src/main/java/com/android/aaptcompiler/AaptResourceType.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/AaptResourceType.kt new file mode 100644 index 000000000..c58650763 --- /dev/null +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/AaptResourceType.kt @@ -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 . + */ + +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) +} diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/BlameLogger.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/BlameLogger.kt similarity index 82% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/BlameLogger.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/BlameLogger.kt index c9fd37b95..8581ac9a6 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/BlameLogger.kt +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/BlameLogger.kt @@ -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 . + */ + /* * 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)) ) diff --git a/xml/resources-api/src/main/java/com/android/aaptcompiler/ConfigDescription.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/ConfigDescription.kt new file mode 100644 index 000000000..05b41b40b --- /dev/null +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/ConfigDescription.kt @@ -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 . + */ + +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 +} \ No newline at end of file diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ConfigDescriptionParsers.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/ConfigDescriptionParsers.kt similarity index 86% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ConfigDescriptionParsers.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/ConfigDescriptionParsers.kt index 8996c877b..36ef01af7 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ConfigDescriptionParsers.kt +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/ConfigDescriptionParsers.kt @@ -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 . + */ + /* * 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 } diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/FloatConstants.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/FloatConstants.kt similarity index 91% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/FloatConstants.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/FloatConstants.kt index 1df58ba7e..8fbfd3ca4 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/FloatConstants.kt +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/FloatConstants.kt @@ -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 . + */ + /* * Copyright (C) 2020 The Android Open Source Project * diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/FloatParsing.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/FloatParsing.kt similarity index 96% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/FloatParsing.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/FloatParsing.kt index 5bf5f109e..9c493c86a 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/FloatParsing.kt +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/FloatParsing.kt @@ -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 . + */ + package com.android.aaptcompiler /** @@ -362,7 +379,7 @@ fun parseFloatDec(lowerCaseText: String): Float? { } } - var currentValue = getValue(currentExponent)*scalarValue + var currentValue = getValue(currentExponent) *scalarValue var relativeDownShift = baseBinaryShift - getShift(currentExponent) // make sure to re-normalize the significand before shifting. diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/LocaleValue.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/LocaleValue.kt similarity index 100% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/LocaleValue.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/LocaleValue.kt diff --git a/xml/resources-api/src/main/java/com/android/aaptcompiler/ResourceConfigValue.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/ResourceConfigValue.kt new file mode 100644 index 000000000..06f7fb3da --- /dev/null +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/ResourceConfigValue.kt @@ -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 . + */ + +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 +) \ No newline at end of file diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceFile.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/ResourceFile.kt similarity index 75% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceFile.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/ResourceFile.kt index 8dfd1065b..16719174d 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceFile.kt +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/ResourceFile.kt @@ -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 . + */ + /* * 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 { override fun compareTo(other: ResourceName): Int { @@ -75,7 +94,7 @@ data class ResourceName( } companion object { - val EMPTY = ResourceName("", AaptResourceType.RAW, "") + val EMPTY = ResourceName("", RAW, "") } } diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourcePathData.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/ResourcePathData.kt similarity index 79% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourcePathData.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/ResourcePathData.kt index 1b0079aca..72f08ca1a 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourcePathData.kt +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/ResourcePathData.kt @@ -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 . + */ + /* * 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 + ) } /** diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceUtils.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/ResourceUtils.kt similarity index 86% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceUtils.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/ResourceUtils.kt index ca8c98d19..892ecc287 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceUtils.kt +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/ResourceUtils.kt @@ -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 . + */ + /* * Copyright (C) 2019 The Android Open Source Project * @@ -17,20 +34,27 @@ 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 -fun tryParseBool(string: String) : BinaryPrimitive? { +fun tryParseBool(string: String): BinaryPrimitive? { val boolean = parseAsBool(string) 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? = +fun parseAsBool(string: String): Boolean? = when (string.trim()) { "true", "True", "TRUE" -> true "false", "False", "FALSE" -> false @@ -46,15 +70,15 @@ fun tryParseNullOrEmpty(value: String): Item? { } } -fun makeNull() : Reference { +fun makeNull(): Reference { return Reference() } -fun makeEmpty() : BinaryPrimitive { - return BinaryPrimitive(ResValue(ResValue.DataType.NULL, ResValue.NullFormat.EMPTY)) +fun makeEmpty(): BinaryPrimitive { + return BinaryPrimitive(ResValue(NULL, NullFormat.EMPTY)) } -fun tryParseInt(value: String) : BinaryPrimitive? { +fun tryParseInt(value: String): BinaryPrimitive? { val trimmedValue = value.trim() val resValue = stringToInt(trimmedValue) return if (resValue != null) BinaryPrimitive(resValue) else null @@ -64,13 +88,14 @@ 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 } -fun tryParseFloat(value: String) : BinaryPrimitive? { +fun tryParseFloat(value: String): BinaryPrimitive? { val floatResource = stringToFloat(value) floatResource ?: 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,17 +162,18 @@ fun tryParseColor(value: String): BinaryPrimitive? { data = (data shl 4) or hexValue } } + else -> return null } return if (error) - throw Exception("Unable to parse hex color '$value'.") + throw Exception("Unable to parse hex color '$value'.") else - BinaryPrimitive(ResValue(dataType, data)) + BinaryPrimitive(ResValue(dataType, data)) } data class ReferenceInfo(val reference: Reference, val createNew: Boolean = false) -fun tryParseReference(value: String) : ReferenceInfo? { +fun tryParseReference(value: String): ReferenceInfo? { val parsedReference = parseReference(value) if (parsedReference != null) { @@ -171,7 +200,7 @@ fun tryParseReference(value: String) : ReferenceInfo? { * * [ReferenceInfo.createNew] will be false, as Attributes cannot be created. */ -fun parseAttributeReference(value: String) : ReferenceInfo? { +fun parseAttributeReference(value: String): ReferenceInfo? { val trimmedValue = value.trim() if (trimmedValue.isEmpty()) { return null @@ -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) } @@ -226,7 +256,7 @@ fun parseAttributeReference(value: String) : ReferenceInfo? { * + [ReferenceInfo.reference] will be set as private if and only if a '*' followed the '@' in the * input. */ -fun parseReference(value: String) : ReferenceInfo? { +fun parseReference(value: String): ReferenceInfo? { val trimmedValue = value.trim() if (trimmedValue.isEmpty()) { return null @@ -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 } @@ -281,7 +311,7 @@ data class ResourceNameInfo(val resourceName: ResourceName, val isPrivate: Boole * valid [ResourceName] and whether the parsed name identifies a private resource. If the value * failed to parsed {@code null} is returned instead. */ -fun parseResourceName(value: String) : ResourceNameInfo? { +fun parseResourceName(value: String): ResourceNameInfo? { if (value.isEmpty()) { return null @@ -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) { @@ -365,8 +399,8 @@ fun tryParseItemForAttribute( reference.reference.typeFlags = resourceTypeMask if (reference.createNew) { val result = onCreateReference?.invoke(reference.reference.name) - if (result != null && !result) { - return null + if (result != null && !result) { + return null } } return reference.reference @@ -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) } @@ -605,12 +648,12 @@ fun parseXmlAttributeName(str: String): Reference { for (i in startOffset..(name.length - 1)) { if (name.codePointAt(i) == ':'.code) { packageName = name.substring(startOffset, i) - entryName = name.substring(i+1) + entryName = name.substring(i + 1) } } result.name = - ResourceName(packageName, AaptResourceType.ATTR, if (entryName.isEmpty()) name else entryName) + ResourceName(packageName, ATTR, if (entryName.isEmpty()) name else entryName) return result } @@ -632,7 +675,7 @@ fun tryParseFlagSymbol(attribute: AttributeResource, value: String): BinaryPrimi // so we need to match against the 'entry' part of the identifier val flagResourceName = symbol.symbol.name if (trimmedPart == flagResourceName.entry) { - flagsData = flagsData or symbol.value + flagsData = flagsData or symbol.value flagSet = true break } diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceValues.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/ResourceValues.kt similarity index 91% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceValues.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/ResourceValues.kt index 213f267fb..7a182dbbe 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceValues.kt +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/ResourceValues.kt @@ -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 . + */ + /* * 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(Type.NUM_TYPES) - fun setValue(type: Plural.Type, item: Item) { + fun setValue(type: Type, item: Item) { values[type.ordinal] = item } @@ -540,10 +565,10 @@ class Styleable: Value() { } class Macro( - var rawValue: String? = null, - var styleString: StyleString? = null, - var untranslatables: List = listOf(), - var aliasNamespaces: List = listOf()): Value() { + var rawValue: String? = null, + var styleString: StyleString? = null, + var untranslatables: List = listOf(), + var aliasNamespaces: List = listOf()): Value() { class Namespace( var alias: String? = null, diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/SDKConstants.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/SDKConstants.kt similarity index 100% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/SDKConstants.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/SDKConstants.kt diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/Source.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/Source.kt similarity index 61% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/Source.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/Source.kt index fe6751005..57473594e 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/Source.kt +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/Source.kt @@ -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 . + */ + /* * Copyright (C) 2019 The Android Open Source Project * diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/StringPool.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/StringPool.kt similarity index 92% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/StringPool.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/StringPool.kt index d37dc392f..7d0660333 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/StringPool.kt +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/StringPool.kt @@ -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 . + */ + /* * 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>() 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] } @@ -105,7 +124,7 @@ class StringPool { return makeRefImpl(str, context, true) } - fun makeRef(ref: Ref): Ref{ + fun makeRef(ref: Ref): Ref { if (ref.entry.pool == this) { return ref } diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/AConfiguration.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/android/AConfiguration.kt similarity index 100% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/AConfiguration.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/android/AConfiguration.kt diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/LocaleData.java b/xml/resources-api/src/main/java/com/android/aaptcompiler/android/LocaleData.java similarity index 100% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/LocaleData.java rename to xml/resources-api/src/main/java/com/android/aaptcompiler/android/LocaleData.java diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/LocaleDataTables.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/android/LocaleDataTables.kt similarity index 100% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/LocaleDataTables.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/android/LocaleDataTables.kt diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/Ref.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/android/Ref.kt similarity index 100% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/Ref.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/android/Ref.kt diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/ResTableConfig.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/android/ResTableConfig.kt similarity index 99% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/ResTableConfig.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/android/ResTableConfig.kt index 1f8403c8d..e1b7478e3 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/ResTableConfig.kt +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/android/ResTableConfig.kt @@ -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 diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/ResourceTypes.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/android/ResourceTypes.kt similarity index 94% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/ResourceTypes.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/android/ResourceTypes.kt index 3a60afb5f..4555bd2bd 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/ResourceTypes.kt +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/android/ResourceTypes.kt @@ -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,9 +35,10 @@ 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) + constructor() : this(0, 0) // Total size of this chunk (in bytes). This is the chunkSize plus the size of any data // associated with this chunk. Adding the this to the address of this chunk will completely skip @@ -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) + 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, val stylesPoolSize: Int, - val styles: List>) { + val styles: List> +) { 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() @@ -287,8 +319,9 @@ class ResStringPool private constructor( val strings = mutableListOf() if (header.stringCount != 0) { // we need to check overflow and ensure the string indexes can fit. - if (header.stringCount*4 < header.stringCount || - (header.header.headerSize + (header.stringCount*4)) > resourceSize) { + if (header.stringCount * 4 < header.stringCount || + (header.header.headerSize + (header.stringCount * 4)) > resourceSize + ) { error("Invalid StringPool: Buffer not large enough for string indices.") } @@ -296,7 +329,7 @@ class ResStringPool private constructor( // There should at least be enough space for the smallest string. // (2 bytes length, null terminator) - if (header.stringsStart+2 >= resourceSize) { + if (header.stringsStart + 2 >= resourceSize) { error("Invalid StringPool: Buffer not large enough for strings.") } @@ -314,7 +347,7 @@ class ResStringPool private constructor( stringPoolSize = (header.stylesStart - header.stringsStart) / charSize } - if (stringPoolSize ==0) { + if (stringPoolSize == 0) { error("Invalid StringPool: Space for strings in header is too small.") } @@ -333,13 +366,13 @@ class ResStringPool private constructor( val styles = mutableListOf>() if (header.styleCount != 0) { - var currentStyleIndex = headerSize.toInt() + header.stringCount*4 + var currentStyleIndex = headerSize.toInt() + header.stringCount * 4 // invariant: integer overflow in calculating styles if (currentStyleIndex < headerSize.toInt()) { error("Invalid StringPool: Integer overflow encountered while decoding styles.") } - stylePoolSize = (resourceSize - header.stylesStart)/4 + stylePoolSize = (resourceSize - header.stylesStart) / 4 for (i in 0.until(header.styleCount)) { val styleLocation = buffer.getInt(currentStyleIndex).deviceToHost() + header.stylesStart @@ -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() } @@ -453,7 +489,7 @@ class ResStringPool private constructor( } fun parseHex(codePoint: Int) = - when(codePoint) { + when (codePoint) { in '0'.code..'9'.code -> codePoint - '0'.code in 'A'.code..'F'.code -> codePoint - 'A'.code + 10 in 'a'.code..'f'.code -> codePoint - 'a'.code + 10 @@ -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 @@ -525,7 +562,7 @@ fun stringToInt(string: String): ResValue? { ++index val decValue = codePoint - '0'.code - value = (value*10) + decValue + value = (value * 10) + decValue val outOfBounds = if (isNegative) -value < Int.MIN_VALUE.toLong() else value > Int.MAX_VALUE.toLong() @@ -540,12 +577,14 @@ fun stringToInt(string: String): ResValue? { } return ResValue( - if(isHex) ResValue.DataType.INT_HEX else ResValue.DataType.INT_DEC, - value.toInt()) + if (isHex) ResValue.DataType.INT_HEX else ResValue.DataType.INT_DEC, + value.toInt() + ) } private data class UnitEntry( - val name: String, val dataType: ResValue.DataType, val unitValue: Int, val scale: Float = 1.0f) + val name: String, val dataType: ResValue.DataType, val unitValue: Int, val scale: Float = 1.0f +) private val unitSuffixes = listOf( UnitEntry("px", ResValue.DataType.DIMENSION, ResValue.ComplexFormat.UNIT_PX), @@ -555,11 +594,13 @@ private val unitSuffixes = listOf( UnitEntry("pt", ResValue.DataType.DIMENSION, ResValue.ComplexFormat.UNIT_PT), UnitEntry("in", ResValue.DataType.DIMENSION, ResValue.ComplexFormat.UNIT_IN), UnitEntry("mm", ResValue.DataType.DIMENSION, ResValue.ComplexFormat.UNIT_MM), - UnitEntry("%", ResValue.DataType.FRACTION, ResValue.ComplexFormat.UNIT_FRACTION, 1.0f/100), + UnitEntry("%", ResValue.DataType.FRACTION, ResValue.ComplexFormat.UNIT_FRACTION, 1.0f / 100), UnitEntry( - "%p", ResValue.DataType.FRACTION, ResValue.ComplexFormat.UNIT_FRACTION_PARENT, 1.0f/100)) + "%p", ResValue.DataType.FRACTION, ResValue.ComplexFormat.UNIT_FRACTION_PARENT, 1.0f / 100 + ) +) -private fun parseUnitType(string: String) : UnitEntry? { +private fun parseUnitType(string: String): UnitEntry? { for (entry in unitSuffixes) { if (string.endsWith(entry.name)) { return entry @@ -581,7 +622,7 @@ fun stringToFloat(string: String): ResValue? { if (entry != null) trimmedString.lastIndexOf(entry.name) else trimmedString.length // no spaces allowed between suffix and floating point value - if (suffixIndex == 0 || Character.isWhitespace(trimmedString.codePointAt(suffixIndex-1))) { + if (suffixIndex == 0 || Character.isWhitespace(trimmedString.codePointAt(suffixIndex - 1))) { return null } @@ -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 } @@ -624,21 +666,25 @@ fun stringToFloat(string: String): ResValue? { // Transform the float to (rounded) integer with the lower 23 bits representing the fraction // and bits 45 to 23 representing the whole number part. - val bits = (parsedValue*(1 shl 23) + .5f).toLong() + val bits = (parsedValue * (1 shl 23) + .5f).toLong() val (radix, shift) = when { bits and ((1L shl 23) - 1) == 0L -> // Always use 23p0 if there is no fraction, as it is easier to read. Pair(ResValue.ComplexFormat.RADIX_23p0, 23) + bits and ((1L shl 23) - 1).inv() == 0L -> // Whole number part is zero -- can fit into 0 leading bits of precision. Pair(ResValue.ComplexFormat.RADIX_0p23, 0) - bits and ((1L shl 31) -1).inv() == 0L -> + + bits and ((1L shl 31) - 1).inv() == 0L -> // Magnitude can fit in 8 leading bits of precision. Pair(ResValue.ComplexFormat.RADIX_8p15, 8) - bits and ((1L shl 39) -1).inv() == 0L -> + + bits and ((1L shl 39) - 1).inv() == 0L -> // Magnitude can fit in 16 leading bits of precision. Pair(ResValue.ComplexFormat.RADIX_16p7, 16) + else -> // Need whole range, so no fractional part. Pair(ResValue.ComplexFormat.RADIX_23p0, 23) diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/Util.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/android/Util.kt similarity index 98% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/Util.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/android/Util.kt index 02a08e239..109a21014 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/android/Util.kt +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/android/Util.kt @@ -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 diff --git a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/buffer/BigBuffer.kt b/xml/resources-api/src/main/java/com/android/aaptcompiler/buffer/BigBuffer.kt similarity index 97% rename from xml/aaptcompiler/src/main/java/com/android/aaptcompiler/buffer/BigBuffer.kt rename to xml/resources-api/src/main/java/com/android/aaptcompiler/buffer/BigBuffer.kt index 8d88e8c76..a6061ba4c 100644 --- a/xml/aaptcompiler/src/main/java/com/android/aaptcompiler/buffer/BigBuffer.kt +++ b/xml/resources-api/src/main/java/com/android/aaptcompiler/buffer/BigBuffer.kt @@ -37,13 +37,13 @@ class BigBuffer(val blockSize: Int = 1024) { var size: Int = 0 private set - internal val blocks = mutableListOf() + val blocks = mutableListOf() - 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) { diff --git a/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceEntry.kt b/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceEntry.kt new file mode 100644 index 000000000..50ee5c946 --- /dev/null +++ b/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceEntry.kt @@ -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 . + */ + +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? +} \ No newline at end of file diff --git a/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceGroup.kt b/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceGroup.kt new file mode 100644 index 000000000..45ca58c34 --- /dev/null +++ b/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceGroup.kt @@ -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 . + */ + +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 +} \ No newline at end of file diff --git a/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceTable.kt b/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceTable.kt new file mode 100644 index 000000000..c9e7b4b88 --- /dev/null +++ b/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceTable.kt @@ -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 . + */ + +package com.itsaky.androidide.xml.res + +import com.android.aaptcompiler.ResourceName + +/** + * @author Akash Yadav + */ +interface IResourceTable { + + val packages: Collection + + 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? +} \ No newline at end of file diff --git a/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceTablePackage.kt b/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceTablePackage.kt new file mode 100644 index 000000000..6e714aabe --- /dev/null +++ b/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceTablePackage.kt @@ -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 . + */ + +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? +} \ No newline at end of file diff --git a/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceValue.kt b/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceValue.kt new file mode 100644 index 000000000..ccb454632 --- /dev/null +++ b/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/IResourceValue.kt @@ -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 . + */ + +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 +} \ No newline at end of file diff --git a/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/ISearchResult.kt b/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/ISearchResult.kt new file mode 100644 index 000000000..877b9f6bc --- /dev/null +++ b/xml/resources-api/src/main/java/com/itsaky/androidide/xml/res/ISearchResult.kt @@ -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 . + */ + +package com.itsaky.androidide.xml.res + +/** + * @author Akash Yadav + */ +interface ISearchResult { + + val tablePackage: IResourceTablePackage + + val group: IResourceGroup + + val entry: IResourceEntry +} \ No newline at end of file diff --git a/xml/aaptcompiler/src/main/proto/com/android/aapt/Configuration.proto b/xml/resources-api/src/main/proto/com/android/aapt/Configuration.proto similarity index 100% rename from xml/aaptcompiler/src/main/proto/com/android/aapt/Configuration.proto rename to xml/resources-api/src/main/proto/com/android/aapt/Configuration.proto diff --git a/xml/aaptcompiler/src/main/proto/com/android/aapt/README.md b/xml/resources-api/src/main/proto/com/android/aapt/README.md similarity index 100% rename from xml/aaptcompiler/src/main/proto/com/android/aapt/README.md rename to xml/resources-api/src/main/proto/com/android/aapt/README.md diff --git a/xml/aaptcompiler/src/main/proto/com/android/aapt/Resources.proto b/xml/resources-api/src/main/proto/com/android/aapt/Resources.proto similarity index 100% rename from xml/aaptcompiler/src/main/proto/com/android/aapt/Resources.proto rename to xml/resources-api/src/main/proto/com/android/aapt/Resources.proto diff --git a/xml/aaptcompiler/src/main/proto/com/android/aapt/ResourcesInternal.proto b/xml/resources-api/src/main/proto/com/android/aapt/ResourcesInternal.proto similarity index 100% rename from xml/aaptcompiler/src/main/proto/com/android/aapt/ResourcesInternal.proto rename to xml/resources-api/src/main/proto/com/android/aapt/ResourcesInternal.proto diff --git a/xml/utils/build.gradle.kts b/xml/utils/build.gradle.kts index 8803b8eaf..c52c265ff 100644 --- a/xml/utils/build.gradle.kts +++ b/xml/utils/build.gradle.kts @@ -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) diff --git a/xml/utils/src/main/java/com/itsaky/androidide/xml/internal/resources/DefaultResourceTableRegistry.kt b/xml/utils/src/main/java/com/itsaky/androidide/xml/internal/resources/DefaultResourceTableRegistry.kt index b1c2ae56a..c226067ce 100644 --- a/xml/utils/src/main/java/com/itsaky/androidide/xml/internal/resources/DefaultResourceTableRegistry.kt +++ b/xml/utils/src/main/java/com/itsaky/androidide/xml/internal/resources/DefaultResourceTableRegistry.kt @@ -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( diff --git a/xml/utils/src/main/java/com/itsaky/androidide/xml/resources/ResourceTableRegistry.kt b/xml/utils/src/main/java/com/itsaky/androidide/xml/resources/ResourceTableRegistry.kt index 27265ed16..fcd019823 100644 --- a/xml/utils/src/main/java/com/itsaky/androidide/xml/resources/ResourceTableRegistry.kt +++ b/xml/utils/src/main/java/com/itsaky/androidide/xml/resources/ResourceTableRegistry.kt @@ -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 { +interface ResourceTableRegistry : XmlRegistry { companion object { const val PCK_ANDROID = "android" + @JvmStatic - val COMPLETION_MODULE_RES = Lookup.Key>() + val COMPLETION_MODULE_RES = Lookup.Key>() + @JvmStatic - val COMPLETION_DEP_RES = Lookup.Key>() + val COMPLETION_DEP_RES = Lookup.Key>() + @JvmStatic - val COMPLETION_FRAMEWORK_RES = Lookup.Key() + val COMPLETION_FRAMEWORK_RES = Lookup.Key() + @JvmStatic - val COMPLETION_MANIFEST_ATTR_RES = Lookup.Key() + val COMPLETION_MANIFEST_ATTR_RES = Lookup.Key() 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 { * * @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 { * * @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 @@ -88,7 +93,7 @@ interface ResourceTableRegistry : XmlRegistry { /** Get the list of all features for the given [platform] directory. */ fun getFeatures(platform: File): List - override fun forPlatformDir(platform: File): ResourceTable? { + override fun forPlatformDir(platform: File): IResourceTable? { return forPackage(PCK_ANDROID, File(platform, "data/res")) } } diff --git a/xml/utils/src/test/java/com/itsaky/androidide/xml/resources/ResourceTableRegistryTest.kt b/xml/utils/src/test/java/com/itsaky/androidide/xml/resources/ResourceTableRegistryTest.kt index c5af924d3..6fb87e3f2 100644 --- a/xml/utils/src/test/java/com/itsaky/androidide/xml/resources/ResourceTableRegistryTest.kt +++ b/xml/utils/src/test/java/com/itsaky/androidide/xml/resources/ResourceTableRegistryTest.kt @@ -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)