import com.android.build.api.variant.AndroidComponentsExtension import com.android.build.api.variant.ComponentIdentity import com.android.build.gradle.tasks.MergeResources import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.artifacts.component.ProjectComponentIdentifier import org.gradle.configurationcache.extensions.capitalized /** * Plugin that verifies that correct order is used for Google and AOSP SystemUI resources. When * there are multiple modules with the same resource, AGP will use the order of the dependencies * declaration. * * See https://developer.android.com/build/dependencies#dependency-order for more details */ abstract class VerifySystemUiResourceOrderPlugin : Plugin<Project> { override fun apply(project: Project) { project.extensions.configure(AndroidComponentsExtension::class.java) { onVariants { variant -> project.afterEvaluate { val capitalizedVariantName = variant.name.capitalized() val mergeTask = project.tasks.named( "merge${capitalizedVariantName}Resources", MergeResources::class.java ) mergeTask.configure { doLast { verifyOrder(variant) } } } } } } private fun MergeResources.verifyOrder(variant: ComponentIdentity) { val projectPaths = librariesProjectPaths // The lower the index, the higher is the priority val googleResourcesPriority = projectPaths.indexOf(GOOGLE_RESOURCES_PROJECT) val aospResourcesPriority = projectPaths.indexOf(AOSP_RESOURCES_PROJECT) if (variant.isGoogleSpecific()) { if (googleResourcesPriority == INDEX_NOT_FOUND) { throw IllegalArgumentException( "Project ${projectPath.get()} doesn't have $GOOGLE_RESOURCES_PROJECT dependency" ) } if (aospResourcesPriority == INDEX_NOT_FOUND) { throw IllegalArgumentException( "Project ${projectPath.get()} doesn't have $AOSP_RESOURCES_PROJECT dependency" ) } if (googleResourcesPriority > aospResourcesPriority) { val prioritiesDescription = "'$GOOGLE_RESOURCES_PROJECT' index: $googleResourcesPriority, " + "'$AOSP_RESOURCES_PROJECT' index: $aospResourcesPriority" throw IllegalArgumentException( "Invalid resource dependencies order, expected Google resources " + "($GOOGLE_RESOURCES_PROJECT) to have higher priority " + "(earlier in the list) than AOSP resources " + "($AOSP_RESOURCES_PROJECT) for task ${this.name}.\n\n" + prioritiesDescription ) } } } private val MergeResources.librariesProjectPaths: List<String> get() = resourcesComputer.libraries .get() .map { it.id.componentIdentifier } .filterIsInstance<ProjectComponentIdentifier>() .map { it.projectPath } private fun ComponentIdentity.isGoogleSpecific(): Boolean = name.contains("google", ignoreCase = true) || name.contains("titan", ignoreCase = true) private companion object { private const val GOOGLE_RESOURCES_PROJECT = ":sysuig-resources" private const val AOSP_RESOURCES_PROJECT = ":SystemUI-res" private const val INDEX_NOT_FOUND = -1 } }