Merge "Marking SystemAlarmDispatcherTest#testDelayMet_withUnMetConstraint() a @LargeTest." into pi-preview1-androidx-dev
diff --git a/buildSrc/init.gradle b/buildSrc/init.gradle
index eddb3a6..ce416f9 100644
--- a/buildSrc/init.gradle
+++ b/buildSrc/init.gradle
@@ -167,7 +167,11 @@
             buildOnServerTask.dependsOn task
         }
     }
+    def docsProject = rootProject.findProject(":docs-fake")
     subprojects {
+        if (docsProject == project) {
+            return
+        }
         project.tasks.whenTaskAdded { task ->
             if ("assembleErrorProne".equals(task.name)
                     || "assembleAndroidTest".equals(task.name)
diff --git a/buildSrc/repos.gradle b/buildSrc/repos.gradle
index f3d71e6..d6f69af 100644
--- a/buildSrc/repos.gradle
+++ b/buildSrc/repos.gradle
@@ -47,7 +47,9 @@
                  // Full checkout prebuilts updated by update_current.py
                  "${repos.prebuiltsRoot}/sdk/current/support/m2repository",
                  // Unbundled checkout prebuilts updated by fullsdk drop
-                 "${getFullSdkPath(repos.prebuiltsRoot)}/extras/android/m2repository"]
+                 "${getFullSdkPath(repos.prebuiltsRoot)}/extras/android/m2repository",
+                 // temporary: com.android.support.constraint:constraint-layout:1.0.2 is there
+                 "${getFullSdkPath(repos.prebuiltsRoot)}/extras/m2repository/"]
 
 /**
  * Adds maven repositories to the given repository handler.
diff --git a/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
index 40d3802..c167769 100644
--- a/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
@@ -16,43 +16,152 @@
 
 package androidx.build
 
+import androidx.build.PublishDocsRules.Strategy.Prebuilts
+import androidx.build.PublishDocsRules.Strategy.TipOfTree
 import androidx.build.checkapi.ApiXmlConversionTask
 import androidx.build.checkapi.CheckApiTask
 import androidx.build.checkapi.UpdateApiTask
 import androidx.build.doclava.DoclavaTask
 import androidx.build.docs.GenerateDocsTask
 import androidx.build.jdiff.JDiffTask
+import com.android.build.gradle.AppExtension
 import com.android.build.gradle.LibraryExtension
+import com.android.build.gradle.api.BaseVariant
 import com.android.build.gradle.api.LibraryVariant
 import org.gradle.api.GradleException
 import org.gradle.api.Project
 import org.gradle.api.Task
 import org.gradle.api.artifacts.Configuration
 import org.gradle.api.file.FileCollection
+import org.gradle.api.file.FileTree
 import org.gradle.api.plugins.JavaBasePlugin
 import org.gradle.api.tasks.TaskContainer
 import org.gradle.api.tasks.bundling.Zip
 import org.gradle.api.tasks.compile.JavaCompile
 import org.gradle.api.tasks.javadoc.Javadoc
 import java.io.File
+import kotlin.collections.Collection
+import kotlin.collections.List
+import kotlin.collections.MutableMap
+import kotlin.collections.emptyList
+import kotlin.collections.emptySet
+import kotlin.collections.filter
+import kotlin.collections.find
+import kotlin.collections.forEach
+import kotlin.collections.listOf
+import kotlin.collections.mapNotNull
+import kotlin.collections.minus
+import kotlin.collections.mutableMapOf
+import kotlin.collections.plus
+import kotlin.collections.set
+import kotlin.collections.toList
+import kotlin.collections.toSet
 
 data class DacOptions(val libraryroot: String, val dataname: String)
 
 object DiffAndDocs {
     private lateinit var allChecksTask: Task
     private lateinit var generateDocsTask: GenerateDocsTask
+    private var docsProject: Project? = null
+
+    private val rules: List<PublishDocsRules> = listOf(RELEASE_RULE)
+    private val docsTasks: MutableMap<String, DoclavaTask> = mutableMapOf()
 
     @JvmStatic
     fun configureDiffAndDocs(root: Project, supportRootFolder: File, dacOptions: DacOptions): Task {
+        docsProject = root.findProject(":docs-fake")
         allChecksTask = root.tasks.create("anchorCheckApis")
         val doclavaConfiguration = root.configurations.getByName("doclava")
         val generateSdkApiTask = createGenerateSdkApiTask(root, doclavaConfiguration)
-        generateDocsTask = createGenerateDocsTask(root, generateSdkApiTask,
-                doclavaConfiguration, supportRootFolder, dacOptions)
+        generateDocsTask = createGenerateDocsTask(
+                project = root, generateSdkApiTask = generateSdkApiTask,
+                doclavaConfig = doclavaConfiguration, supportRootFolder = supportRootFolder,
+                dacOptions = dacOptions, destDir = root.docsDir())
+
+        rules.forEach {
+            val task = createGenerateDocsTask(
+                    project = root, generateSdkApiTask = generateSdkApiTask,
+                    doclavaConfig = doclavaConfiguration,
+                    supportRootFolder = supportRootFolder, dacOptions = dacOptions,
+                    destDir = File(root.docsDir(), it.name),
+                    taskName = "${it.name}DocsTask")
+            docsTasks[it.name] = task
+        }
+
+        setupDocsProject()
         createDistDocsTask(root, generateDocsTask)
         return allChecksTask
     }
 
+    private fun prebuiltSources(root: Project, mavenId: String): FileTree {
+        val configName = "docs-temp_$mavenId"
+        val configuration = root.configurations.create(configName)
+        root.dependencies.add(configName, mavenId)
+
+        val artifacts = configuration.resolvedConfiguration.resolvedArtifacts
+        val artifact = artifacts.find { it.moduleVersion.id.toString() == mavenId }
+                ?: throw GradleException("Failed to resolve $mavenId")
+
+        val folder = artifact.file.parentFile
+        val tree = root.zipTree(File(folder, "${artifact.file.nameWithoutExtension}-sources.jar"))
+                    .matching {
+                        it.exclude("**/*.MF")
+                        it.exclude("**/*.aidl")
+                        it.exclude("**/*.html")
+                        it.exclude("**/*.kt")
+                    }
+        root.configurations.remove(configuration)
+        return tree
+    }
+
+    private fun setupDocsProject() {
+        docsProject?.afterEvaluate { docs ->
+            val appExtension = docs.extensions.findByType(AppExtension::class.java)
+                    ?: throw GradleException("Android app plugin is missing on docsProject")
+
+            rules.forEach { rule ->
+                appExtension.productFlavors.create(rule.name) {
+                    it.dimension = "library-group"
+                }
+            }
+            appExtension.applicationVariants.all { v ->
+                val task = docsTasks[v.flavorName]
+                if (v.buildType.name == "release" && task != null) {
+                    registerAndroidProjectForDocsTask(task, v)
+                    task.exclude { fileTreeElement ->
+                        fileTreeElement.path.endsWith(v.rFile())
+                    }
+                }
+            }
+        }
+
+        docsProject?.rootProject?.subprojects
+                ?.filter { docsProject != it }
+                ?.forEach { docsProject?.evaluationDependsOn(it.path) }
+    }
+
+    private fun registerPrebuilts(extension: SupportLibraryExtension)
+            = docsProject?.afterEvaluate { docs ->
+        val depHandler = docs.dependencies
+        val root = docs.rootProject
+        rules.mapNotNull { rule ->
+            (rule.resolve(extension) as? Prebuilts)?.let { rule.name to it } }
+                .forEach { (name, prebuilt) ->
+                    val dependency = prebuilt.dependency(extension)
+                    depHandler.add("${name}Implementation", dependency)
+                    prebuilt.stubs?.forEach { path ->
+                        depHandler.add("${name}CompileOnly", root.files(path))
+                    }
+                    docsTasks[name]!!.source(prebuiltSources(root, dependency))
+                }
+    }
+
+    private fun tipOfTreeTasks(extension: SupportLibraryExtension, setup: (DoclavaTask) -> Unit) {
+        rules.filter { rule -> rule.resolve(extension) == TipOfTree }
+                .mapNotNull { rule -> docsTasks[rule.name] }
+                .forEach(setup)
+    }
+
     /**
      * Registers a Java project for global docs generation, local API file generation, and
      * local API diff generation tasks.
@@ -63,7 +172,14 @@
         }
         val compileJava = project.properties["compileJava"] as JavaCompile
         registerJavaProjectForDocsTask(generateDocsTask, compileJava)
-        if (!hasApiFolder(project)) {
+
+        registerPrebuilts(extension)
+
+        tipOfTreeTasks(extension) { task ->
+            registerJavaProjectForDocsTask(task, compileJava)
+        }
+
+        if (!project.hasApiFolder()) {
             project.logger.info("Project ${project.name} doesn't have an api folder, " +
                     "ignoring API tasks.")
             return
@@ -86,13 +202,28 @@
         if (!hasApiTasks(project, extension)) {
             return
         }
+
+        registerPrebuilts(extension)
+
         library.libraryVariants.all { variant ->
             if (variant.name == "release") {
                 registerAndroidProjectForDocsTask(generateDocsTask, variant)
-                if (!hasJavaSources(variant)) {
+
+                // include R.file generated for prebuilts
+                rules.filter { it.resolve(extension) is Prebuilts }.forEach { rule ->
+                    docsTasks[rule.name]?.include { fileTreeElement ->
+                        fileTreeElement.path.endsWith(variant.rFile())
+                    }
+                }
+
+                tipOfTreeTasks(extension) { task ->
+                    registerAndroidProjectForDocsTask(task, variant)
+                }
+
+                if (!variant.hasJavaSources()) {
                     return@all
                 }
-                if (!hasApiFolder(project)) {
+                if (!project.hasApiFolder()) {
                     project.logger.info("Project ${project.name} doesn't have " +
                             "an api folder, ignoring API tasks.")
                     return@all
@@ -119,7 +250,7 @@
                 "annotation paired with the @RestrictTo(LIBRARY_GROUP) code annotation."
 
 @Suppress("DEPRECATION")
-private fun hasJavaSources(variant: LibraryVariant) = !variant.javaCompile.source
+private fun LibraryVariant.hasJavaSources() = !javaCompile.source
         .filter { file -> file.name != "R.java" && file.name != "BuildConfig.java" }
         .isEmpty
 
@@ -155,7 +286,7 @@
         onFailMessage = "Public API definition may not change in finalized or patch releases.\n" +
                 "\n" + MSG_HIDE_API)
 
-private fun hasApiFolder(project: Project) = File(project.projectDir, "api").exists()
+fun Project.hasApiFolder() = File(projectDir, "api").exists()
 
 private fun stripExtension(fileName: String) = fileName.substringBeforeLast('.')
 
@@ -273,17 +404,15 @@
  * <p>
  * @see #registerJavaProjectForDocsTask
  */
-private fun registerAndroidProjectForDocsTask(task: Javadoc, releaseVariant: LibraryVariant) {
+private fun registerAndroidProjectForDocsTask(task: Javadoc, releaseVariant: BaseVariant) {
     // This code makes a number of unsafe assumptions about Android Gradle Plugin,
     // and there's a good chance that this will break in the near future.
     @Suppress("DEPRECATION")
     task.dependsOn(releaseVariant.javaCompile)
-    val packageDir = releaseVariant.applicationId.replace('.', '/')
+    task.include { fileTreeElement ->
+        fileTreeElement.name != "R.java" || fileTreeElement.path.endsWith(releaseVariant.rFile()) }
     @Suppress("DEPRECATION")
-    val sources = releaseVariant.javaCompile.source.filter { file ->
-        file.name != "R.java" || file.parent.endsWith(packageDir)
-    }
-    task.source(sources)
+    task.source(releaseVariant.javaCompile.source)
     @Suppress("DEPRECATION")
     task.classpath += releaseVariant.getCompileClasspath(null) +
             task.project.files(releaseVariant.javaCompile.destinationDir)
@@ -467,8 +596,10 @@
         generateSdkApiTask: DoclavaTask,
         doclavaConfig: Configuration,
         supportRootFolder: File,
-        dacOptions: DacOptions): GenerateDocsTask =
-        project.tasks.createWithConfig("generateDocs", GenerateDocsTask::class.java) {
+        dacOptions: DacOptions,
+        destDir: File,
+        taskName: String = "generateDocs"): GenerateDocsTask =
+        project.tasks.createWithConfig(taskName, GenerateDocsTask::class.java) {
             dependsOn(generateSdkApiTask, doclavaConfig)
             group = JavaBasePlugin.DOCUMENTATION_GROUP
             description = "Generates d.android.com-style documentation. To generate offline docs " +
@@ -476,9 +607,9 @@
 
             setDocletpath(doclavaConfig.resolve())
             val offline = project.processProperty("offlineDocs") != null
-            destinationDir = File(project.docsDir(), if (offline) "offline" else "online")
+            destinationDir = File(destDir, if (offline) "offline" else "online")
             classpath = androidJarFile(project)
-            val hidden = listOf<Int>(105, 106, 107, 111, 112, 113, 115, 116, 121)
+            val hidden = listOf(105, 106, 107, 111, 112, 113, 115, 116, 121)
             doclavaErrors = ((101..122) - hidden).toSet()
             doclavaWarnings = emptySet()
             doclavaHidden += hidden
@@ -619,6 +750,14 @@
 private fun androidSrcJarFile(project: Project): File = File(project.fullSdkPath(),
         "platforms/android-${SupportConfig.CURRENT_SDK_VERSION}/android-stubs-src.jar")
 
+private fun PublishDocsRules.resolve(extension: SupportLibraryExtension) =
+        resolve(extension.mavenGroup!!, extension.project.name)
+
+private fun Prebuilts.dependency(extension: SupportLibraryExtension) =
+        "${extension.mavenGroup}:${extension.project.name}:$version"
+
+private fun BaseVariant.rFile() = "${applicationId.replace('.', '/')}/R.java"
+
 // Nasty part. Get rid of that eventually!
 private fun Project.docsDir(): File = properties["docsDir"] as File
 
diff --git a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
new file mode 100644
index 0000000..511d961
--- /dev/null
+++ b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2018 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 androidx.build
+
+import androidx.build.PublishDocsRules.Strategy.TipOfTree
+import androidx.build.PublishDocsRules.Strategy.Prebuilts
+import androidx.build.PublishDocsRules.Strategy.Ignore
+
+val RELEASE_RULE = docsRules("public") {
+    val defaultVersion = "1.0.0-alpha1"
+    prebuilts(LibraryGroups.ANNOTATION, defaultVersion)
+    prebuilts(LibraryGroups.APPCOMPAT, defaultVersion)
+    prebuilts(LibraryGroups.ASYNCLAYOUTINFLATER, defaultVersion)
+    prebuilts(LibraryGroups.BROWSER, defaultVersion)
+    prebuilts(LibraryGroups.CAR, defaultVersion)
+            .addStubs("car/car-stubs/android.car.jar")
+    prebuilts(LibraryGroups.CARDVIEW, defaultVersion)
+    prebuilts(LibraryGroups.COLLECTION, defaultVersion)
+    // misses prebuilts, because it was released under different name in alpha1
+    tipOfTree(LibraryGroups.CONTENTPAGER)
+
+    prebuilts(LibraryGroups.COORDINATORLAYOUT, defaultVersion)
+    prebuilts(LibraryGroups.CORE, defaultVersion)
+    prebuilts(LibraryGroups.CURSORADAPTER, defaultVersion)
+    prebuilts(LibraryGroups.CUSTOMVIEW, defaultVersion)
+    prebuilts(LibraryGroups.DOCUMENTFILE, defaultVersion)
+    prebuilts(LibraryGroups.DRAWERLAYOUT, defaultVersion)
+    prebuilts(LibraryGroups.DYNAMICANIMATION, defaultVersion)
+    prebuilts(LibraryGroups.EMOJI, defaultVersion)
+    prebuilts(LibraryGroups.EXIFINTERFACE, defaultVersion)
+    prebuilts(LibraryGroups.FRAGMENT, defaultVersion)
+    prebuilts(LibraryGroups.GRIDLAYOUT, defaultVersion)
+    prebuilts(LibraryGroups.HEIFWRITER, defaultVersion)
+    prebuilts(LibraryGroups.INTERPOLATOR, defaultVersion)
+    prebuilts(LibraryGroups.LEANBACK, defaultVersion)
+    prebuilts(LibraryGroups.LEGACY, defaultVersion)
+    prebuilts(LibraryGroups.LOADER, defaultVersion)
+    prebuilts(LibraryGroups.LOCALBROADCASTMANAGER, defaultVersion)
+    prebuilts(LibraryGroups.MEDIA, defaultVersion)
+    prebuilts(LibraryGroups.MEDIAROUTER, defaultVersion)
+    prebuilts(LibraryGroups.PALETTE, defaultVersion)
+    prebuilts(LibraryGroups.PERCENTLAYOUT, defaultVersion)
+    prebuilts(LibraryGroups.PREFERENCE, defaultVersion)
+    prebuilts(LibraryGroups.PRINT, defaultVersion)
+    prebuilts(LibraryGroups.RECOMMENDATION, defaultVersion)
+    prebuilts(LibraryGroups.RECYCLERVIEW, defaultVersion)
+    prebuilts(LibraryGroups.SLICE, defaultVersion)
+    prebuilts(LibraryGroups.SLIDINGPANELAYOUT, defaultVersion)
+    prebuilts(LibraryGroups.SWIPEREFRESHLAYOUT, defaultVersion)
+    prebuilts(LibraryGroups.TEXTCLASSIFIER, defaultVersion)
+    prebuilts(LibraryGroups.TRANSITION, defaultVersion)
+    prebuilts(LibraryGroups.TVPROVIDER, defaultVersion)
+    prebuilts(LibraryGroups.VECTORDRAWABLE, defaultVersion)
+    prebuilts(LibraryGroups.VIEWPAGER, defaultVersion)
+    prebuilts(LibraryGroups.VIEWPAGER2, defaultVersion)
+    prebuilts(LibraryGroups.WEAR, defaultVersion)
+            .addStubs("wear/wear_stubs/com.google.android.wearable-stubs.jar")
+    prebuilts(LibraryGroups.WEBKIT, defaultVersion)
+    val flatfootVersion = "2.0.0-alpha1"
+    prebuilts(LibraryGroups.ROOM, flatfootVersion)
+    prebuilts(LibraryGroups.PERSISTENCE, flatfootVersion)
+    // lifecycle-viewmodel-ktx / lifecycle-process / lifecycle-service miss their prebuilts
+    tipOfTree(LibraryGroups.LIFECYCLE, "lifecycle-viewmodel-ktx")
+    tipOfTree(LibraryGroups.LIFECYCLE, "lifecycle-process")
+    tipOfTree(LibraryGroups.LIFECYCLE, "lifecycle-service")
+    prebuilts(LibraryGroups.LIFECYCLE, flatfootVersion)
+    prebuilts(LibraryGroups.ARCH_CORE, flatfootVersion)
+    prebuilts(LibraryGroups.PAGING, "paging-rxjava2", "1.0.0-alpha1")
+    prebuilts(LibraryGroups.PAGING, "2.0.0-alpha1")
+    // navigation & workmanager don't have prebuilts currently
+    tipOfTree(LibraryGroups.NAVIGATION)
+    tipOfTree(LibraryGroups.WORKMANAGER)
+    default(Ignore)
+}
+
+typealias ArtifactsPredicate = (String, String) -> Boolean
+
+/**
+ * Rules are resolved in addition order. So if you have two rules that specify how docs should be
+ * built for a module, first defined rule wins.
+ */
+fun docsRules(name: String, init: PublishDocsRulesBuilder.() -> Unit): PublishDocsRules {
+    val f = PublishDocsRulesBuilder(name)
+    f.init()
+    return f.build()
+}
+
+class PublishDocsRulesBuilder(private val name: String) {
+
+    private val rules: MutableList<Pair<ArtifactsPredicate, PublishDocsRules.Strategy>>
+            = mutableListOf()
+
+    private fun groupPredicate(name: String) = { group: String, _: String -> name == group }
+
+    private fun artifactPredicate(group: String, name: String) = {
+        inGroup: String, inName: String -> group == inGroup && name == inName }
+
+    private val allPredicate = { _: String, _: String -> true }
+
+    /**
+     * docs for projects within [groupName] will be built from sources.
+     */
+    fun tipOfTree(groupName: String) {
+        rules.add(groupPredicate(groupName) to TipOfTree)
+    }
+
+    /**
+     * docs for a project with the given [groupName] and [name] will be built from sources.
+     */
+    fun tipOfTree(groupName: String, name: String) {
+        rules.add(artifactPredicate(groupName, name) to TipOfTree)
+    }
+
+    /**
+     * docs for a project with the given [groupName] and [name] will be built from a prebuilt with
+     * the given [version].
+     */
+    fun prebuilts(groupName: String, moduleName: String , version: String) {
+        rules.add(artifactPredicate(groupName, moduleName) to Prebuilts(Version(version)))
+    }
+
+    /**
+     * docs for projects within [groupName] will be built from prebuilts with the given [version]
+     */
+    fun prebuilts(groupName: String, version: String) = prebuilts(groupName, Version(version))
+
+    /**
+     * docs for projects within [groupName] will be built from prebuilts with the given [version]
+     */
+    fun prebuilts(groupName: String, version: Version): Prebuilts {
+        val strategy = Prebuilts(version)
+        rules.add(groupPredicate(groupName) to strategy)
+        return strategy
+    }
+
+    /**
+     * defines a default strategy for building docs
+     */
+    fun default(strategy: PublishDocsRules.Strategy) {
+        rules.add(allPredicate to strategy)
+    }
+
+    /**
+     * docs for projects within [groupName] won't be built
+     */
+    fun ignore(groupName: String) {
+        rules.add(groupPredicate(groupName) to Ignore)
+    }
+
+    /**
+     * docs for a specified project won't be built
+     */
+    fun ignore(groupName: String, name: String) {
+        rules.add(artifactPredicate(groupName, name) to Ignore)
+    }
+
+    fun build() = PublishDocsRules(name, rules)
+}
+
+class PublishDocsRules(
+        val name: String,
+        private val rules: List<Pair<ArtifactsPredicate, Strategy>>
+) {
+    sealed class Strategy {
+        object TipOfTree : Strategy()
+        object Ignore : Strategy()
+        class Prebuilts(val version: Version) : Strategy() {
+            var stubs: MutableList<String>? = null
+            constructor(version: String) : this(Version(version))
+            fun addStubs(path: String) {
+                if (stubs == null) {
+                    stubs = mutableListOf()
+                }
+                stubs!!.add(path)
+            }
+        }
+    }
+
+    fun resolve(groupName: String, moduleName: String): Strategy {
+        return rules.find { it.first(groupName, moduleName) }?.second ?: throw Error()
+    }
+}
\ No newline at end of file
diff --git a/compat/res/values/attrs.xml b/compat/res/values/attrs.xml
index 8fd6915..e171e9f 100644
--- a/compat/res/values/attrs.xml
+++ b/compat/res/values/attrs.xml
@@ -34,9 +34,9 @@
         <!-- The strategy to be used when fetching font data from a font provider in XML layouts.
         This attribute is ignored when the resource is loaded from code, as it is equivalent to the
         choice of API between {@link
-    androidx.core.contenttent.res.ResourcesCompat#getFont(Context, int)} (blocking) and
+    androidx.core.content.res.ResourcesCompat#getFont(Context, int)} (blocking) and
         {@link
-    androidx.core.contenttent.res.ResourcesCompat#getFont(Context, int, FontCallback, Handler)}
+    androidx.core.content.res.ResourcesCompat#getFont(Context, int, FontCallback, Handler)}
         (async). -->
         <attr name="fontProviderFetchStrategy">
             <!-- The blocking font fetch works as follows.
diff --git a/core/ktx/src/androidTest/java/androidx/core/content/ContextTest.kt b/core/ktx/src/androidTest/java/androidx/core/content/ContextTest.kt
index 09d2355..102899c 100644
--- a/core/ktx/src/androidTest/java/androidx/core/content/ContextTest.kt
+++ b/core/ktx/src/androidTest/java/androidx/core/content/ContextTest.kt
@@ -42,7 +42,7 @@
                 return if (name == "unit") Unit else null
             }
         }
-        val actual = context.systemService<Unit>()
+        val actual = context.getSystemService<Unit>()
         assertEquals(Unit::class.java, lookup)
         assertSame(Unit, actual)
     }
diff --git a/core/ktx/src/main/java/androidx/core/content/Context.kt b/core/ktx/src/main/java/androidx/core/content/Context.kt
index 2ffb17b..fec1165 100644
--- a/core/ktx/src/main/java/androidx/core/content/Context.kt
+++ b/core/ktx/src/main/java/androidx/core/content/Context.kt
@@ -20,7 +20,6 @@
 import android.content.res.TypedArray
 import android.util.AttributeSet
 import androidx.annotation.AttrRes
-import androidx.annotation.RequiresApi
 import androidx.annotation.StyleRes
 
 /**
@@ -32,9 +31,12 @@
  *
  * @see Context.getSystemService(Class)
  */
-@RequiresApi(23)
-@Suppress("HasPlatformType") // Intentionally propagating platform type with unknown nullability.
-inline fun <reified T> Context.systemService() = getSystemService(T::class.java)
+inline fun <reified T> Context.getSystemService(): T? =
+        ContextCompat.getSystemService(this, T::class.java)
+
+@Deprecated("Use getSystemService", ReplaceWith("this.getSystemService<T>()"))
+inline fun <reified T> Context.systemService(): T? =
+        ContextCompat.getSystemService(this, T::class.java)
 
 /**
  * Executes [block] on a [TypedArray] receiver. The [TypedArray] holds the attribute
@@ -62,12 +64,7 @@
     @StyleRes defStyleRes: Int = 0,
     block: TypedArray.() -> Unit
 ) {
-    val typedArray = obtainStyledAttributes(set, attrs, defStyleAttr, defStyleRes)
-    try {
-        typedArray.block()
-    } finally {
-        typedArray.recycle()
-    }
+    obtainStyledAttributes(set, attrs, defStyleAttr, defStyleRes).apply(block).recycle()
 }
 
 /**
@@ -84,10 +81,5 @@
     attrs: IntArray,
     block: TypedArray.() -> Unit
 ) {
-    val typedArray = obtainStyledAttributes(resourceId, attrs)
-    try {
-        typedArray.block()
-    } finally {
-        typedArray.recycle()
-    }
+    obtainStyledAttributes(resourceId, attrs).apply(block).recycle()
 }
diff --git a/core/ktx/src/main/java/androidx/core/preference/PreferenceGroup.kt b/core/ktx/src/main/java/androidx/core/preference/PreferenceGroup.kt
index 2efab64..5df18a6 100644
--- a/core/ktx/src/main/java/androidx/core/preference/PreferenceGroup.kt
+++ b/core/ktx/src/main/java/androidx/core/preference/PreferenceGroup.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-@file:Suppress("NOTHING_TO_INLINE")
+@file:Suppress("NOTHING_TO_INLINE", "DeprecatedCallableAddReplaceWith", "DEPRECATION")
 
 package androidx.core.preference
 
@@ -26,6 +26,7 @@
  *
  * @throws NullPointerException if no preference is found with that key.
  */
+@Deprecated("Use Jetpack preference library")
 inline operator fun PreferenceGroup.get(key: CharSequence): Preference = findPreference(key)
 
 /**
@@ -33,10 +34,12 @@
  *
  * @throws IndexOutOfBoundsException if index is less than 0 or greater than or equal to the count.
  */
+@Deprecated("Use Jetpack preference library")
 operator fun PreferenceGroup.get(index: Int): Preference = getPreference(index)
         ?: throw IndexOutOfBoundsException("Index: $index, Size: $preferenceCount")
 
 /** Returns `true` if `preference` is found in this preference group. */
+@Deprecated("Use Jetpack preference library")
 operator fun PreferenceGroup.contains(preference: Preference): Boolean {
     for (index in 0 until preferenceCount) {
         if (getPreference(index) == preference) {
@@ -47,25 +50,31 @@
 }
 
 /** Adds `preference` to this preference group. */
+@Deprecated("Use Jetpack preference library")
 inline operator fun PreferenceGroup.plusAssign(preference: Preference) {
     addPreference(preference)
 }
 
 /** Removes `preference` from this preference group. */
+@Deprecated("Use Jetpack preference library")
 inline operator fun PreferenceGroup.minusAssign(preference: Preference) {
     removePreference(preference)
 }
 
 /** Returns the number of preferences in this preference group. */
+@Deprecated("Use Jetpack preference library")
 inline val PreferenceGroup.size: Int get() = preferenceCount
 
 /** Returns true if this preference group contains no preferences. */
+@Deprecated("Use Jetpack preference library")
 inline fun PreferenceGroup.isEmpty(): Boolean = size == 0
 
 /** Returns true if this preference group contains one or more preferences. */
+@Deprecated("Use Jetpack preference library")
 inline fun PreferenceGroup.isNotEmpty(): Boolean = size != 0
 
 /** Performs the given action on each preference in this preference group. */
+@Deprecated("Use Jetpack preference library")
 inline fun PreferenceGroup.forEach(action: (preference: Preference) -> Unit) {
     for (index in 0 until preferenceCount) {
         action(get(index))
@@ -73,6 +82,7 @@
 }
 
 /** Performs the given action on each preference in this preference group, providing its sequential index. */
+@Deprecated("Use Jetpack preference library")
 inline fun PreferenceGroup.forEachIndexed(action: (index: Int, preference: Preference) -> Unit) {
     for (index in 0 until preferenceCount) {
         action(index, get(index))
@@ -80,6 +90,7 @@
 }
 
 /** Returns a [MutableIterator] over the preferences in this preference group. */
+@Deprecated("Use Jetpack preference library")
 operator fun PreferenceGroup.iterator() = object : MutableIterator<Preference> {
     private var index = 0
     override fun hasNext() = index < size
@@ -90,6 +101,7 @@
 }
 
 /** Returns a [Sequence] over the preferences in this preference group. */
+@Deprecated("Use Jetpack preference library")
 val PreferenceGroup.children: Sequence<Preference>
     get() = object : Sequence<Preference> {
         override fun iterator() = this@children.iterator()
diff --git a/docs-fake/AndroidManifest.xml b/docs-fake/AndroidManifest.xml
new file mode 100644
index 0000000..b094662
--- /dev/null
+++ b/docs-fake/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright 2018 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.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools" package="total.fake.sad">
+
+    <application tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon"/>
+</manifest>
diff --git a/docs-fake/build.gradle b/docs-fake/build.gradle
new file mode 100644
index 0000000..cb5b1c1
--- /dev/null
+++ b/docs-fake/build.gradle
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 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.
+ */
+
+plugins {
+    id("SupportAndroidTestAppPlugin")
+}
+
+// replace all tests etc with empty task, so we don't run anything
+// it is more effective then task.enabled = false, because we avoid executing deps as well
+def reentrance = false
+project.tasks.whenTaskAdded { task ->
+    if (task instanceof org.gradle.api.tasks.testing.Test || task.name.startsWith("assemble")) {
+        if (!reentrance) {
+            reentrance = true
+            project.tasks.replace(task.name)
+            reentrance = false
+        }
+    }
+}
+
+android {
+    sourceSets {
+        main {
+            manifest.srcFile "AndroidManifest.xml"
+        }
+    }
+    flavorDimensions("library-group")
+}
+
+
+supportTestApp {
+    minSdkVersion = 'P'
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index e73df47..059a289 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -222,3 +222,10 @@
 ///// FLATFOOT START
 
 ///// FLATFOOT END
+
+// fake project which is used for docs generation from prebuilts
+// we need real android project to generate R.java, aidl etc files that mentioned in sources
+if (!startParameter.projectProperties.containsKey('android.injected.invoked.from.ide')) {
+    // we don't need it in ide, so we don't configure it there
+    includeProject(":docs-fake", "docs-fake")
+}