Status Update
Comments
to...@gmail.com <to...@gmail.com> #2
We are currently using AGP internal task types to flag memory-intensive tasks to enforce a reduced parallelism at execution time. I've raised this separately (with a lot more detail) as a feature request (
to...@gmail.com <to...@gmail.com> #4
Another use case that we have is to reactively respond to the creation of APKs and AABs. The new AGP APIs allow us to connect out tasks into the artifact pipeline via wiredWith
but the best we can come up with to receive the completed artifact is to wire in toTransform
. This A) does not guarantee that we will receive the final artifact as more transforms may be applied after our task is called, and B) requires us to copy the input property file/dir to our tasks output property file/dir in order to not break the build cache.
The reactive behavior of the above is the complicating factor.
A non-reactive approach could simply depend upon the task name and then look for a hardcoded path in the build directory (which is still sort of gross, since the build output paths are not documented as public API and change from time to time).
Another approach would be to wire a custom task to consume the output of the build via the built artifacts loader feeding an input property. However, this approach cannot be applied reactively. Either the custom task is included in the build and causes the creation of the binary artifact, or it is not included in the build and never gets invoked.
ss...@google.com <ss...@google.com> #6
We didn't provide a task wiring helper for that case as there's only one thing to wire, but I can see how the inconsistency can be misleading
ch...@google.com <ch...@google.com> #7
WRT variant.artifacts.get(SingleArtifact.APK))
, if the task is included in the build it will cause the creation of the artifact. Our build is currently defined to reactively perform some actions (predominantly some fancy reporting) only if work is actually performed.
We had previously been pushing our build to wire in to task outputs by locating tasks by type and referencing output properties as inputs to tasks registered via task finalizes
or dependsOn
relationships. This started getting more and more fragile as the AGP APIs migration proceeded/matured. I'm to the point now where I think the notion of reactive execution is hostile to the direction/expectations of both Gradle and AGP and want to start moving away from it, yet our build as it currently stands does rely on this behavior.
I bring up this up as a gap only because I don't know if I'll be able to completely refactor our CI pipeline's expectations in time for Gradle 8+.
to...@gmail.com <to...@gmail.com> #8
ch...@google.com <ch...@google.com> #9
Another minor functionality gap: We have a build that has test coverage enabled during test execution but then we manually disable the coverage report generation for all project modules as we have a custom coverage report task that creates an aggregate test coverage report for the entire project. This saves us the execution time, I/O, and protects us from Jacoco implementation instabilities.
We're currently using the following to accomplish this:
project.tasks.withType(JacocoReportTask::class.java) {
enabled = false
}
to...@gmail.com <to...@gmail.com> #10
Another gap, though my perhaps there's a better way to express this? Some of our builds leverage Flank to run instrumentation tests on Firebase Test Lab. These builds run as a single CI stage so as to afford Gradle the best opportunity to parallelize work. In this context, we have found that prioritizing instrumentation test assembly work early in the build allows the tests to dispatch to FTL earlier, minimizing overall build times. To implement this, we have chosen to be explicit on the inverse side by pushing lint and local unit test execution to be shouldRunAfter
the flank tasks which in turn depend on the instrumentation test assembly, etc.
Specifically:
private fun bumpFlankTask(project: Project, flankTasks: TaskCollection<FlankExecutionTask>) {
listOf(AndroidLintTask::class.java, AndroidLintAnalysisTask::class.java, AndroidUnitTest::class.java)
.forEach {
project.tasks.withType(it).configureEach {
shouldRunAfter(flankTasks)
}
}
}
This seems fairly specific to our project's desires and not necessarily transferable to other projects. I think our best option for the future Gradle 9+ might be to fallback to leveraging task names rather than leveraging task types in a generic fashion. Mentioning it here in case there is a better approach/option once the types are no longer available.
ch...@google.com <ch...@google.com>
al...@android.com <al...@android.com> #11
Another gap we've found but no longer directly depend upon: when invoking BundleToStandaloneApkTask
the resulting universal APK does not appear to be accessible via the Artifacts API / ArtifactType.APK
- at least as of AGP 7.0.
We are able to no longer directly depend upon it because we are using the task name and a hardcoded build output directory path to locate the APK if/when it gets built. This is another symptom of our reactively defined build implementation. However, if we were to relay on
(phew! I think that's it for now? sorry for the dump, we're just starting to get caught up!)
to...@gmail.com <to...@gmail.com> #12
That last one (
ch...@google.com <ch...@google.com> #13
Ran into another use case that the API does not yet seem to support: AndroidUnitTest configuration for offline Jacoco instrumentation. Given that we've had to tweak task outputs to get this to work reliably with the build cache it is probably best corrected on the AGP side. Probably easiest just to paste the relevant code here:
/*
* -Djacoco-agent.destfile arg is used to configure the offline mode behavior of jacoco. The offline
* behavior is what is used when dependency module code is executed as it has already been
* instrumented by the jacoco-agent in previous executions. We redirect this to record the offline
* results under the build directory and give it a more explicit/identifiable name (it defaults
* to the project dir as jacoco.exec).
*
* NOTE: Attempts at using JacocoTaskExtension.setDestinationFile were unsuccessful in capturing coverage
*/
project.tasks.withType(AndroidUnitTest::class.java).configureEach {
val execFile = project.layout.buildDirectory.file("jacoco/offlineDependencies.exec").get()
jvmArgs("-Dfile.encoding=UTF-8", "-Djacoco-agent.destfile=${execFile}")
// Register our file as a task output to ensure it is restored via the build cache when execution is avoided
outputs.file(execFile)
doFirst {
// Make sure the coverage file is removed if it exists from a previous run
execFile.asFile.deleteRecursively()
}
}
to...@gmail.com <to...@gmail.com> #14
And one question:
We have some convention plugin code which is applied to many project module. It uses the components extension's onVariants
callback to reactively trigger some data capture but needs to know whether or not minification has been enabled for the build type, configured by a separate convention plugin. We have code similar to the following:
project.plugins.withId("com.android.application") { plugin ->
val extension = project.extensions.getByType(ApplicationAndroidComponentsExtension::class.java)
val android = project.extensions.getByType(ApplicationExtension::class.java)
extension.onVariants { variant ->
...
if (android.buildTypes.getByName(variant.buildType!!).isMinifyEnabled) {
...
}
ApplicationExtension
feels like more of an input API for AGP and not something we should be programmatically querying within the onVariants
callback. Given the exposure of other configuration values (e.g. variant.pseudoLocalesEnabled
as Property<Boolean>
), should isMinifyEnabled
also be exposed?
ch...@google.com <ch...@google.com> #15
Alex, can you look at #11 first, then at #13.
al...@android.com <al...@android.com> #16
#14, yes, it should probably be offered in ApplicationVariantBuilder.
Description
Version used: 23.4.0
Theme used: Non relevant
Devices/Android versions reproduced on: Android 5+
Since #205369 is still present I'm trying to manually manage CollapsingToolbarLayout with transparent / translucent status bar.
To achieve the effect there's the need to disable onApplyWindowInsets of the CTL. Then I add a top margin to the Toolbar.
See code below. (The Toolbar top margin is set by code but it's the same via XML)
All works except that the CTL does not seems to take in account the margins for the animations, leading to a problem with the title animation (see video).
The strange thing is that the little change weight at the correct position so I can't explain why the title continue to move up.
Xml :
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
xmlns:android="
xmlns:app="
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/main_collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/header_height"
android:minHeight="?attr/actionBarSize"
app:contentScrim="@color/blue_grey_950"
app:expandedTitleGravity="bottom|left"
app:expandedTitleMargin="16dp"
app:expandedTitleMarginBottom="@dimen/header_title_spacing"
app:expandedTitleTextAppearance="@style/TextAppearance.AppCompat.Headline"
app:layout_scrollFlags="scroll|enterAlwaysCollapsed|enterAlways">
<android.support.v7.widget.ViewStubCompat
android:id="@+id/viewstub_header"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<android.support.v7.widget.Toolbar
android:id="@+id/main_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>