Merge "Support Kotlin concrete functions in DAO interfaces." into androidx-master-dev
diff --git a/animation/animation/src/main/java/androidx/animation/AnimationHandler.java b/animation/animation/src/main/java/androidx/animation/AnimationHandler.java
index 2e4241b..c6f1dc6 100644
--- a/animation/animation/src/main/java/androidx/animation/AnimationHandler.java
+++ b/animation/animation/src/main/java/androidx/animation/AnimationHandler.java
@@ -73,7 +73,8 @@
public static AnimationHandler sAnimationHandler = null;
private static AnimationHandler sTestHandler = null;
- private ThreadLocal<AnimationCallbackData> mAnimationCallbackData = new ThreadLocal<>();
+ private static final ThreadLocal<AnimationCallbackData> mAnimationCallbackData =
+ new ThreadLocal<>();
private final AnimationFrameCallbackProvider mProvider;
AnimationHandler(AnimationFrameCallbackProvider provider) {
@@ -81,7 +82,7 @@
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mProvider = new FrameCallbackProvider16();
} else {
- mProvider = new FrameCallbackProvider14();
+ mProvider = new FrameCallbackProvider14(this);
}
} else {
mProvider = provider;
@@ -291,13 +292,16 @@
* Frame provider for ICS and ICS-MR1 releases. The frame callback is achieved via posting
* a Runnable to the main thread Handler with a delay.
*/
- private class FrameCallbackProvider14 implements AnimationFrameCallbackProvider, Runnable {
+ private static class FrameCallbackProvider14 implements AnimationFrameCallbackProvider,
+ Runnable {
- private final ThreadLocal<Handler> mHandler = new ThreadLocal<>();
+ private static final ThreadLocal<Handler> mHandler = new ThreadLocal<>();
private long mLastFrameTime = -1;
private long mFrameDelay = 16;
+ AnimationHandler mAnimationHandler;
- FrameCallbackProvider14() {
+ FrameCallbackProvider14(AnimationHandler animationHandler) {
+ mAnimationHandler = animationHandler;
}
Handler getHandler() {
@@ -310,7 +314,7 @@
@Override
public void run() {
mLastFrameTime = SystemClock.uptimeMillis();
- AnimationHandler.this.onAnimationFrame(mLastFrameTime);
+ mAnimationHandler.onAnimationFrame(mLastFrameTime);
}
@Override
diff --git a/appcompat/appcompat-lint/build.gradle b/appcompat/appcompat-lint/build.gradle
index d67f346..8159beb 100644
--- a/appcompat/appcompat-lint/build.gradle
+++ b/appcompat/appcompat-lint/build.gradle
@@ -14,15 +14,11 @@
* limitations under the License.
*/
-import androidx.build.AndroidXExtension
-import androidx.build.CompilationTarget
import androidx.build.LibraryGroups
import androidx.build.LibraryVersions
import androidx.build.Publish
-import static androidx.build.dependencies.DependenciesKt.LINT_API_MIN
-import static androidx.build.dependencies.DependenciesKt.getKOTLIN_STDLIB
-import static androidx.build.dependencies.DependenciesKt.getLINT_API_LATEST
+import static androidx.build.dependencies.DependenciesKt.*
plugins {
id("AndroidXPlugin")
diff --git a/benchmark/gradle-plugin/build.gradle b/benchmark/gradle-plugin/build.gradle
index c794a45..43ebd26 100644
--- a/benchmark/gradle-plugin/build.gradle
+++ b/benchmark/gradle-plugin/build.gradle
@@ -38,6 +38,7 @@
implementation(KOTLIN_STDLIB)
testImplementation gradleTestKit()
+ testImplementation(project(":internal-testutils-gradle-plugin"))
testImplementation(ANDROIDX_TEST_RUNNER)
testImplementation(JUNIT)
testImplementation(KOTLIN_TEST)
diff --git a/benchmark/gradle-plugin/src/test/kotlin/androidx/benchmark/gradle/BenchmarkPluginTest.kt b/benchmark/gradle-plugin/src/test/kotlin/androidx/benchmark/gradle/BenchmarkPluginTest.kt
index 7844207..5d04073 100644
--- a/benchmark/gradle-plugin/src/test/kotlin/androidx/benchmark/gradle/BenchmarkPluginTest.kt
+++ b/benchmark/gradle-plugin/src/test/kotlin/androidx/benchmark/gradle/BenchmarkPluginTest.kt
@@ -16,95 +16,56 @@
package androidx.benchmark.gradle
+import androidx.testutils.gradle.ProjectSetupRule
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.UnexpectedBuildFailure
import org.junit.Before
import org.junit.Rule
import org.junit.Test
-import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import java.io.File
-import java.util.Properties
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertTrue
+private val PLUGINS_HEADER = """
+ plugins {
+ id('androidx.benchmark')
+ id('com.android.library')
+ }
+""".trimIndent()
+
@RunWith(JUnit4::class)
class BenchmarkPluginTest {
-
@get:Rule
- val testProjectDir = TemporaryFolder()
+ val projectSetup = ProjectSetupRule()
- private lateinit var buildToolsVersion: String
- private lateinit var compileSdkVersion: String
- private lateinit var prebuiltsRoot: String
- private lateinit var minSdkVersion: String
-
- private lateinit var buildFile: File
- private lateinit var propertiesFile: File
private lateinit var versionPropertiesFile: File
private lateinit var gradleRunner: GradleRunner
@Before
fun setUp() {
- val stream = BenchmarkPluginTest::class.java.classLoader.getResourceAsStream("sdk.prop")
- val properties = Properties()
- properties.load(stream)
- prebuiltsRoot = properties.getProperty("prebuiltsRoot")
- compileSdkVersion = properties.getProperty("compileSdkVersion")
- buildToolsVersion = properties.getProperty("buildToolsVersion")
- minSdkVersion = properties.getProperty("minSdkVersion")
-
- testProjectDir.root.mkdirs()
-
- val localPropFile = File("../../local.properties")
- localPropFile.copyTo(File(testProjectDir.root, "local.properties"), overwrite = true)
-
- buildFile = File(testProjectDir.root, "build.gradle")
- buildFile.createNewFile()
-
- propertiesFile = File(testProjectDir.root, "gradle.properties")
- propertiesFile.writer().use {
- val props = Properties()
- props.setProperty("android.useAndroidX", "true")
- props.setProperty("android.enableJetpack", "true")
- props.store(it, null)
- }
-
- versionPropertiesFile = File(testProjectDir.root, "version.properties")
+ versionPropertiesFile = File(projectSetup.rootDir, "version.properties")
versionPropertiesFile.createNewFile()
- File("src/test/test-data", "app-project").copyRecursively(testProjectDir.root)
+ File("src/test/test-data", "app-project").copyRecursively(projectSetup.rootDir)
gradleRunner = GradleRunner.create()
- .withProjectDir(testProjectDir.root)
+ .withProjectDir(projectSetup.rootDir)
.withPluginClasspath()
}
@Test
fun applyPluginAppProject() {
- buildFile.writeText(
- """
- plugins {
- id('com.android.application')
- id('androidx.benchmark')
- }
-
- repositories {
- maven { url "$prebuiltsRoot/androidx/external" }
- maven { url "$prebuiltsRoot/androidx/internal" }
- }
-
- android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
-
- defaultConfig {
- minSdkVersion $minSdkVersion
+ projectSetup.writeDefaultBuildGradle(
+ prefix = """
+ plugins {
+ id('com.android.application')
+ id('androidx.benchmark')
}
- }
-
+ """.trimIndent(),
+ suffix = """
dependencies {
androidTestImplementation "androidx.benchmark:benchmark:1.0.0-alpha01"
}
@@ -118,27 +79,14 @@
@Test
fun applyPluginAndroidLibProject() {
- buildFile.writeText(
- """
- plugins {
- id('com.android.library')
- id('androidx.benchmark')
- }
-
- repositories {
- maven { url "$prebuiltsRoot/androidx/external" }
- maven { url "$prebuiltsRoot/androidx/internal" }
- }
-
- android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
-
- defaultConfig {
- minSdkVersion $minSdkVersion
+ projectSetup.writeDefaultBuildGradle(
+ prefix = """
+ plugins {
+ id('com.android.library')
+ id('androidx.benchmark')
}
- }
-
+ """.trimIndent(),
+ suffix = """
dependencies {
androidTestImplementation "androidx.benchmark:benchmark:1.0.0-alpha01"
}
@@ -152,9 +100,11 @@
@Test
fun applyPluginNonAndroidProject() {
- buildFile.writeText(
+ val prebuiltsRoot = projectSetup.props.prebuiltsRoot
+ projectSetup.buildFile.writeText(
"""
plugins {
+ id('java')
id('androidx.benchmark')
}
@@ -163,49 +113,22 @@
maven { url "$prebuiltsRoot/androidx/internal" }
}
- android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
-
- defaultConfig {
- minSdkVersion $minSdkVersion
- }
- }
-
dependencies {
- androidTestImplementation "androidx.benchmark:benchmark:1.0.0-alpha01"
+ testImplementation "androidx.benchmark:benchmark:1.0.0-alpha01"
}
""".trimIndent()
)
assertFailsWith(UnexpectedBuildFailure::class) {
- gradleRunner.withArguments("assemble").build()
+ gradleRunner.withArguments("jar").build()
}
}
@Test
fun applyPluginNonBenchmarkProject() {
- buildFile.writeText(
- """
- plugins {
- id('com.android.library')
- id('androidx.benchmark')
- }
-
- repositories {
- maven { url "$prebuiltsRoot/androidx/external" }
- maven { url "$prebuiltsRoot/androidx/internal" }
- }
-
- android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
-
- defaultConfig {
- minSdkVersion $minSdkVersion
- }
- }
- """.trimIndent()
+ projectSetup.writeDefaultBuildGradle(
+ prefix = PLUGINS_HEADER,
+ suffix = ""
)
val output = gradleRunner.withArguments("tasks").build()
@@ -215,27 +138,9 @@
@Test
fun applyPluginBeforeAndroid() {
- buildFile.writeText(
- """
- plugins {
- id('androidx.benchmark')
- id('com.android.library')
- }
-
- repositories {
- maven { url "$prebuiltsRoot/androidx/external" }
- maven { url "$prebuiltsRoot/androidx/internal" }
- }
-
- android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
-
- defaultConfig {
- minSdkVersion $minSdkVersion
- }
- }
-
+ projectSetup.writeDefaultBuildGradle(
+ prefix = PLUGINS_HEADER,
+ suffix = """
dependencies {
androidTestImplementation "androidx.benchmark:benchmark:1.0.0-alpha01"
}
@@ -249,24 +154,11 @@
@Test
fun applyPluginOnAgp36() {
- buildFile.writeText(
- """
- plugins {
- id('androidx.benchmark')
- id('com.android.library')
- }
-
- repositories {
- maven { url "$prebuiltsRoot/androidx/external" }
- maven { url "$prebuiltsRoot/androidx/internal" }
- }
-
+ projectSetup.writeDefaultBuildGradle(
+ prefix = PLUGINS_HEADER,
+ suffix = """
android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
-
defaultConfig {
- minSdkVersion $minSdkVersion
testInstrumentationRunnerArguments additionalTestOutputDir: "/fake_path/files"
}
}
@@ -281,7 +173,7 @@
""".trimIndent()
)
- propertiesFile.appendText("android.enableAdditionalTestOutput=true")
+ projectSetup.gradlePropertiesFile.appendText("android.enableAdditionalTestOutput=true")
versionPropertiesFile.writeText("buildVersion=3.6.0-alpha05")
val output = gradleRunner.withArguments("tasks").build()
@@ -297,31 +189,17 @@
@Test
fun applyPluginOnAgp35() {
- buildFile.writeText(
- """
- plugins {
- id('androidx.benchmark')
- id('com.android.library')
- }
-
- repositories {
- maven { url "$prebuiltsRoot/androidx/external" }
- maven { url "$prebuiltsRoot/androidx/internal" }
- }
-
+ projectSetup.writeDefaultBuildGradle(
+ prefix = PLUGINS_HEADER,
+ suffix = """
android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
-
defaultConfig {
- minSdkVersion $minSdkVersion
testInstrumentationRunnerArguments.remove("additionalTestOutputDir")
}
}
dependencies {
androidTestImplementation "androidx.benchmark:benchmark:1.0.0-alpha01"
-
}
tasks.register("printInstrumentationArgs") {
@@ -331,7 +209,7 @@
tasks.register("printTestBuildType") {
println android.testBuildType
}
- """.trimIndent()
+ """.trimIndent()
)
versionPropertiesFile.writeText("buildVersion=3.5.0-rc03")
@@ -352,32 +230,11 @@
@Test
fun applyPluginDefaultAgpProperties() {
- buildFile.writeText(
- """
- import com.android.build.gradle.TestedExtension
-
- plugins {
- id('com.android.library')
- id('androidx.benchmark')
- }
-
- repositories {
- maven { url "$prebuiltsRoot/androidx/external" }
- maven { url "$prebuiltsRoot/androidx/internal" }
- }
-
- android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
-
- defaultConfig {
- minSdkVersion $minSdkVersion
- }
- }
-
+ projectSetup.writeDefaultBuildGradle(
+ prefix = "import com.android.build.gradle.TestedExtension\n$PLUGINS_HEADER",
+ suffix = """
dependencies {
androidTestImplementation "androidx.benchmark:benchmark:1.0.0-alpha01"
-
}
tasks.register("printTestInstrumentationRunner") {
@@ -388,7 +245,7 @@
def extension = project.extensions.getByType(TestedExtension)
println extension.buildTypes.getByName("debug").testCoverageEnabled
}
- """.trimIndent()
+ """.trimIndent()
)
val runnerOutput = gradleRunner.withArguments("printTestInstrumentationRunner").build()
@@ -402,26 +259,11 @@
@Test
fun applyPluginOverrideAgpProperties() {
- buildFile.writeText(
- """
- import com.android.build.gradle.TestedExtension
-
- plugins {
- id('com.android.library')
- id('androidx.benchmark')
- }
-
- repositories {
- maven { url "$prebuiltsRoot/androidx/external" }
- maven { url "$prebuiltsRoot/androidx/internal" }
- }
-
+ projectSetup.writeDefaultBuildGradle(
+ prefix = "import com.android.build.gradle.TestedExtension\n$PLUGINS_HEADER",
+ suffix = """
android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
-
defaultConfig {
- minSdkVersion $minSdkVersion
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -434,7 +276,6 @@
dependencies {
androidTestImplementation "androidx.benchmark:benchmark:1.0.0-alpha01"
-
}
tasks.register("printTestInstrumentationRunner") {
@@ -459,24 +300,11 @@
@Test
fun applyPluginAndroidOldRunner36() {
- buildFile.writeText(
- """
- plugins {
- id('com.android.library')
- id('androidx.benchmark')
- }
-
- repositories {
- maven { url "$prebuiltsRoot/androidx/external" }
- maven { url "$prebuiltsRoot/androidx/internal" }
- }
-
+ projectSetup.writeDefaultBuildGradle(
+ prefix = PLUGINS_HEADER,
+ suffix = """
android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
-
defaultConfig {
- minSdkVersion $minSdkVersion
testInstrumentationRunner "androidx.benchmark.AndroidBenchmarkRunner"
testInstrumentationRunnerArguments additionalTestOutputDir: "/fake_path/files"
}
@@ -485,10 +313,9 @@
dependencies {
androidTestImplementation "androidx.benchmark:benchmark:1.0.0-alpha04"
}
- """.trimIndent()
+ """.trimIndent()
)
-
- propertiesFile.appendText("android.enableAdditionalTestOutput=true")
+ projectSetup.gradlePropertiesFile.appendText("android.enableAdditionalTestOutput=true")
assertFailsWith(UnexpectedBuildFailure::class) {
gradleRunner.withArguments("assemble").build()
@@ -497,24 +324,11 @@
@Test
fun applyPluginAndroidOldRunner35() {
- buildFile.writeText(
- """
- plugins {
- id('com.android.library')
- id('androidx.benchmark')
- }
-
- repositories {
- maven { url "$prebuiltsRoot/androidx/external" }
- maven { url "$prebuiltsRoot/androidx/internal" }
- }
-
+ projectSetup.writeDefaultBuildGradle(
+ prefix = PLUGINS_HEADER,
+ suffix = """
android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
-
defaultConfig {
- minSdkVersion $minSdkVersion
testInstrumentationRunner "androidx.benchmark.AndroidBenchmarkRunner"
testInstrumentationRunnerArguments.remove("additionalTestOutputDir")
}
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
index 307500d..af794f6 100644
--- a/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
@@ -255,6 +255,7 @@
private fun Project.configureRootProject() {
setDependencyVersions()
configureKtlintCheckFile()
+ configureCheckInvalidSuppress()
if (isRunningOnBuildServer()) {
gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS
diff --git a/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt b/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
index 274eed9..d87c862 100644
--- a/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
@@ -101,8 +101,14 @@
"-Xep:EqualsGetClass:ERROR",
"-Xep:UnusedVariable:ERROR",
"-Xep:UnusedMethod:ERROR",
+ "-Xep:UndefinedEquals:ERROR",
+ "-Xep:ThreadLocalUsage:ERROR",
"-Xep:FutureReturnValueIgnored:ERROR",
+ "-Xep:ArgumentSelectionDefectChecker:ERROR",
"-Xep:HidingField:ERROR",
+ "-Xep:UnsynchronizedOverridesSynchronized:ERROR",
+ "-Xep:Finally:ERROR",
+ "-Xep:ThreadPriorityCheck:ERROR",
"-Xep:AutoValueFinalMethods:ERROR",
// Nullaway
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
index 081337c..5030956 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
@@ -34,7 +34,6 @@
val BENCHMARK = LibraryGroup("androidx.benchmark")
val CAMERA = LibraryGroup("androidx.camera", false)
val CAR = LibraryGroup("androidx.car", false)
- val CAR_APP = LibraryGroup("androidx.car.app")
val CARDVIEW = LibraryGroup("androidx.cardview")
val COLLECTION = LibraryGroup("androidx.collection")
val CONCURRENT = LibraryGroup("androidx.concurrent")
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
index fd90bb1..5592f5e 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
@@ -41,7 +41,6 @@
val CAMERA_LIFECYCLE = Version("1.0.0-alpha02")
val CAMERA_VIEW = Version("1.0.0-alpha05")
val CAR = Version("1.0.0-alpha8")
- val CAR_APP = Version("1.0.0-alpha01")
val CAR_MODERATOR = Version("1.0.0-alpha1")
val CARDVIEW = Version("1.1.0-alpha01")
val COLLECTION = Version("1.2.0-alpha01")
diff --git a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
index 3ea3629..c0c5777 100644
--- a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
@@ -41,7 +41,7 @@
ignore(LibraryGroups.BENCHMARK.group, "benchmark-gradle-plugin")
prebuilts(LibraryGroups.BENCHMARK, "1.0.0")
prebuilts(LibraryGroups.BIOMETRIC, "biometric", "1.0.1")
- prebuilts(LibraryGroups.BROWSER, "1.2.0")
+ prebuilts(LibraryGroups.BROWSER, "1.3.0-alpha01")
ignore(LibraryGroups.CAMERA.group, "camera-testing")
ignore(LibraryGroups.CAMERA.group, "camera-extensions-stub")
ignore(LibraryGroups.CAMERA.group, "camera-testlib-extensions")
@@ -73,7 +73,7 @@
ignore(LibraryGroups.FRAGMENT.group, "fragment-lint")
ignore(LibraryGroups.FRAGMENT.group, "fragment-testing-lint")
ignore(LibraryGroups.FRAGMENT.group, "fragment-truth")
- prebuilts(LibraryGroups.FRAGMENT, "1.2.0-rc04")
+ prebuilts(LibraryGroups.FRAGMENT, "1.2.0-rc05")
prebuilts(LibraryGroups.GRIDLAYOUT, "1.0.0")
prebuilts(LibraryGroups.HEIFWRITER, "1.0.0")
prebuilts(LibraryGroups.INTERPOLATOR, "1.0.0")
@@ -102,6 +102,7 @@
ignore(LibraryGroups.NAVIGATION.group, "navigation-safe-args-gradle-plugin")
prebuilts(LibraryGroups.NAVIGATION, "2.2.0-rc04")
ignore(LibraryGroups.PAGING.group, "paging-guava")
+ ignore(LibraryGroups.PAGING.group, "paging-testutils")
prebuilts(LibraryGroups.PAGING, "2.1.0")
prebuilts(LibraryGroups.PALETTE, "1.0.0")
prebuilts(LibraryGroups.PERCENTLAYOUT, "1.0.0")
@@ -143,7 +144,7 @@
prebuilts(LibraryGroups.WEBKIT, "1.2.0-alpha01")
ignore(LibraryGroups.WORK.group, "work-gcm")
ignore(LibraryGroups.WORK.group, "work-runtime-lint")
- prebuilts(LibraryGroups.WORK, "2.3.0-beta02")
+ prebuilts(LibraryGroups.WORK, "2.3.0-rc01")
default(Ignore)
}
diff --git a/buildSrc/src/main/kotlin/androidx/build/SdkResourceGenerator.kt b/buildSrc/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
index 5defbc6..c2ebd63 100644
--- a/buildSrc/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
@@ -59,6 +59,9 @@
val kotlinStdlib: String = KOTLIN_STDLIB
@get:Input
+ val rootProjectPath: String = project.rootProject.rootDir.absolutePath
+
+ @get:Input
lateinit var gradleVersion: String
@get:OutputFile
@@ -77,6 +80,7 @@
writer.write("navigationCommon=$navigationCommon\n")
writer.write("kotlinStdlib=$kotlinStdlib\n")
writer.write("gradleVersion=$gradleVersion\n")
+ writer.write("rootProjectPath=$rootProjectPath\n")
writer.close()
}
diff --git a/buildSrc/src/main/kotlin/androidx/build/checkInvalidSuppress.kt b/buildSrc/src/main/kotlin/androidx/build/checkInvalidSuppress.kt
new file mode 100644
index 0000000..85033cd
--- /dev/null
+++ b/buildSrc/src/main/kotlin/androidx/build/checkInvalidSuppress.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright 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 androidx.build
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.GradleException
+import org.gradle.api.Project
+import org.gradle.api.tasks.Internal
+import org.gradle.api.tasks.TaskAction
+import org.gradle.api.tasks.options.Option
+import org.jetbrains.kotlin.konan.file.File
+
+// first level line filter - we ignore lines that don't contain the following for speed
+const val ROOT_MATCH = "noinspection"
+// Map of invalid pattern to correct replacement
+// These could be regex for fancy whitespace matching, but don't seem to need in practice
+val MATCHERS = mapOf(
+ "//noinspection deprecation" to "@SuppressWarnings(\"deprecation\")",
+ "//noinspection unchecked" to "@SuppressWarnings(\"unchecked\")"
+)
+
+open class CheckInvalidSuppressTask : DefaultTask() {
+
+ @Option(option = "files", description = "List of files to check")
+ @Internal
+ lateinit var filenamesOption: String
+
+ @Option(
+ option = "format",
+ description = "Use --format to auto-correct invalid suppressions"
+ )
+ @Internal
+ var autocorrectOption = false
+
+ // Check a line for any invalid suppressions, and return it if found
+ fun getInvalidSuppression(line: String): String {
+ MATCHERS.keys.forEach { bad ->
+ if (line.trimStart().startsWith(bad)) {
+ return bad
+ }
+ }
+ return ""
+ }
+
+ // Get report for line with invalid suppression
+ fun getReportForLine(filename: String, i: Int, lines: List<String>, good: String): String {
+ var context = ""
+ for (index in 0..2) {
+ if (index + i >= lines.size) break
+ context += lines[index + i] + "\n"
+ }
+ return "\n%s:%d:\nError: unsupported comment suppression\n%sInstead, use: %s\n"
+ .format(
+ filename, i, context, good
+ )
+ }
+
+ @TaskAction
+ fun checkForInvalidSuppression() {
+ val filenames = filenamesOption.split(" ")
+ var report = ""
+
+ for (filename in filenames) {
+ // suppress comments ignored in kotlin, but may as well block there too
+ if (!filename.endsWith(".java") && !filename.endsWith(".kt"))
+ continue
+
+ // check file exists
+ if (!File(filename).exists)
+ continue
+
+ val lines = File(filename).readStrings()
+ for ((i, line) in lines.withIndex()) {
+ if (line.contains(ROOT_MATCH)) {
+ val bad = getInvalidSuppression(line)
+ if (bad != "") {
+ if (autocorrectOption) {
+ if (line.trimStart() == bad) {
+ lines[i] = line.replaceFirst(bad, MATCHERS[bad]!!)
+ } else {
+ lines[i] = line.replaceFirst(bad, MATCHERS[bad]!! + " // ")
+ }
+ File(filename).writeLines(lines)
+ } else {
+ report += getReportForLine(filename, i, lines, MATCHERS[bad]!!)
+ }
+ }
+ }
+ }
+ }
+ if (report != "") {
+ throw GradleException(
+ "Invalid, IDEA-specific warning suppression found. These cause " +
+ "warnings during compilation." + "\n" + report
+ )
+ }
+ }
+}
+
+fun Project.configureCheckInvalidSuppress() {
+ tasks.register("checkInvalidSuppress", CheckInvalidSuppressTask::class.java) { task ->
+ task.description = "Task used to find IDEA-specific warning suppressions that do not " +
+ "work for command line builds."
+ task.group = "Verification"
+ }
+}
diff --git a/camera/camera-camera2/api/1.0.0-alpha08.txt b/camera/camera-camera2/api/1.0.0-alpha08.txt
new file mode 100644
index 0000000..c4e0698
--- /dev/null
+++ b/camera/camera-camera2/api/1.0.0-alpha08.txt
@@ -0,0 +1,9 @@
+// Signature format: 3.0
+package androidx.camera.camera2 {
+
+ public final class Camera2Config {
+ method public static androidx.camera.core.CameraXConfig defaultConfig();
+ }
+
+}
+
diff --git a/camera/camera-camera2/api/current.txt b/camera/camera-camera2/api/current.txt
new file mode 100644
index 0000000..c4e0698
--- /dev/null
+++ b/camera/camera-camera2/api/current.txt
@@ -0,0 +1,9 @@
+// Signature format: 3.0
+package androidx.camera.camera2 {
+
+ public final class Camera2Config {
+ method public static androidx.camera.core.CameraXConfig defaultConfig();
+ }
+
+}
+
diff --git a/camera/camera-camera2/api/public_plus_experimental_1.0.0-alpha08.txt b/camera/camera-camera2/api/public_plus_experimental_1.0.0-alpha08.txt
new file mode 100644
index 0000000..a6359b6
--- /dev/null
+++ b/camera/camera-camera2/api/public_plus_experimental_1.0.0-alpha08.txt
@@ -0,0 +1,31 @@
+// Signature format: 3.0
+package androidx.camera.camera2 {
+
+ public final class Camera2Config {
+ method public static androidx.camera.core.CameraXConfig defaultConfig();
+ }
+
+}
+
+package androidx.camera.camera2.interop {
+
+ @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2CameraInfo {
+ method public static String extractCameraId(androidx.camera.core.CameraInfo);
+ }
+
+ @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2Interop {
+ }
+
+ public static final class Camera2Interop.Extender<T> {
+ ctor public Camera2Interop.Extender(androidx.camera.core.ExtendableBuilder<T!>);
+ method public <ValueT> androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setCaptureRequestOption(android.hardware.camera2.CaptureRequest.Key<ValueT!>, ValueT);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setDeviceStateCallback(android.hardware.camera2.CameraDevice.StateCallback);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setSessionCaptureCallback(android.hardware.camera2.CameraCaptureSession.CaptureCallback);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setSessionStateCallback(android.hardware.camera2.CameraCaptureSession.StateCallback);
+ }
+
+ @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalCamera2Interop {
+ }
+
+}
+
diff --git a/camera/camera-camera2/api/public_plus_experimental_current.txt b/camera/camera-camera2/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..a6359b6
--- /dev/null
+++ b/camera/camera-camera2/api/public_plus_experimental_current.txt
@@ -0,0 +1,31 @@
+// Signature format: 3.0
+package androidx.camera.camera2 {
+
+ public final class Camera2Config {
+ method public static androidx.camera.core.CameraXConfig defaultConfig();
+ }
+
+}
+
+package androidx.camera.camera2.interop {
+
+ @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2CameraInfo {
+ method public static String extractCameraId(androidx.camera.core.CameraInfo);
+ }
+
+ @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2Interop {
+ }
+
+ public static final class Camera2Interop.Extender<T> {
+ ctor public Camera2Interop.Extender(androidx.camera.core.ExtendableBuilder<T!>);
+ method public <ValueT> androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setCaptureRequestOption(android.hardware.camera2.CaptureRequest.Key<ValueT!>, ValueT);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setDeviceStateCallback(android.hardware.camera2.CameraDevice.StateCallback);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setSessionCaptureCallback(android.hardware.camera2.CameraCaptureSession.CaptureCallback);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setSessionStateCallback(android.hardware.camera2.CameraCaptureSession.StateCallback);
+ }
+
+ @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalCamera2Interop {
+ }
+
+}
+
diff --git a/car-app/app/api/res-1.0.0-alpha01.txt b/camera/camera-camera2/api/res-1.0.0-alpha08.txt
similarity index 100%
rename from car-app/app/api/res-1.0.0-alpha01.txt
rename to camera/camera-camera2/api/res-1.0.0-alpha08.txt
diff --git a/camera/camera-camera2/api/restricted_1.0.0-alpha08.txt b/camera/camera-camera2/api/restricted_1.0.0-alpha08.txt
new file mode 100644
index 0000000..c4e0698
--- /dev/null
+++ b/camera/camera-camera2/api/restricted_1.0.0-alpha08.txt
@@ -0,0 +1,9 @@
+// Signature format: 3.0
+package androidx.camera.camera2 {
+
+ public final class Camera2Config {
+ method public static androidx.camera.core.CameraXConfig defaultConfig();
+ }
+
+}
+
diff --git a/camera/camera-camera2/api/restricted_current.txt b/camera/camera-camera2/api/restricted_current.txt
new file mode 100644
index 0000000..c4e0698
--- /dev/null
+++ b/camera/camera-camera2/api/restricted_current.txt
@@ -0,0 +1,9 @@
+// Signature format: 3.0
+package androidx.camera.camera2 {
+
+ public final class Camera2Config {
+ method public static androidx.camera.core.CameraXConfig defaultConfig();
+ }
+
+}
+
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java
index a621c5a..905162d 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java
@@ -153,7 +153,7 @@
assumeTrue(isSupportAeRegion(mCameraSelector));
FocusMeteringAction action =
- FocusMeteringAction.Builder.from(mMeteringPoint1,
+ new FocusMeteringAction.Builder(mMeteringPoint1,
FocusMeteringAction.FLAG_AE).build();
ListenableFuture<FocusMeteringResult> future =
mCamera.getCameraControl().startFocusAndMetering(action);
@@ -166,7 +166,7 @@
assumeTrue(isSupportAwbRegion(mCameraSelector));
FocusMeteringAction action =
- FocusMeteringAction.Builder.from(mMeteringPoint1,
+ new FocusMeteringAction.Builder(mMeteringPoint1,
FocusMeteringAction.FLAG_AWB).build();
ListenableFuture<FocusMeteringResult> future =
mCamera.getCameraControl().startFocusAndMetering(action);
@@ -179,7 +179,7 @@
assumeTrue(isSupportAeRegion(mCameraSelector) || isSupportAwbRegion(mCameraSelector));
FocusMeteringAction action =
- FocusMeteringAction.Builder.from(mMeteringPoint1,
+ new FocusMeteringAction.Builder(mMeteringPoint1,
FocusMeteringAction.FLAG_AE | FocusMeteringAction.FLAG_AWB).build();
ListenableFuture<FocusMeteringResult> future =
mCamera.getCameraControl().startFocusAndMetering(action);
@@ -198,7 +198,7 @@
MeteringPoint point3 = factory.createPoint(0.2f, 0.2f);
MeteringPoint point4 = factory.createPoint(0.3f, 0.4f);
FocusMeteringAction action =
- FocusMeteringAction.Builder.from(point1,
+ new FocusMeteringAction.Builder(point1,
FocusMeteringAction.FLAG_AE | FocusMeteringAction.FLAG_AWB)
.addPoint(point2,
FocusMeteringAction.FLAG_AE | FocusMeteringAction.FLAG_AWB)
@@ -217,7 +217,7 @@
@Test
public void cancelFocusMetering_futureCompletes() {
FocusMeteringAction action =
- FocusMeteringAction.Builder.from(mMeteringPoint1).build();
+ new FocusMeteringAction.Builder(mMeteringPoint1).build();
mCamera.getCameraControl().startFocusAndMetering(action);
ListenableFuture<Void> result = mCamera.getCameraControl().cancelFocusAndMetering();
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlTest.java
index 6ee4db5..ce5f92c 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlTest.java
@@ -408,7 +408,7 @@
SurfaceOrientedMeteringPointFactory factory = new SurfaceOrientedMeteringPointFactory(1.0f,
1.0f);
- FocusMeteringAction action = FocusMeteringAction.Builder.from(factory.createPoint(0, 0))
+ FocusMeteringAction action = new FocusMeteringAction.Builder(factory.createPoint(0, 0))
.build();
mCamera2CameraControl.startFocusAndMetering(action);
@@ -448,7 +448,7 @@
SurfaceOrientedMeteringPointFactory factory = new SurfaceOrientedMeteringPointFactory(1.0f,
1.0f);
- FocusMeteringAction action = FocusMeteringAction.Builder.from(factory.createPoint(0, 0))
+ FocusMeteringAction action = new FocusMeteringAction.Builder(factory.createPoint(0, 0))
.build();
mCamera2CameraControl.startFocusAndMetering(action);
HandlerUtil.waitForLooperToIdle(mHandler);
@@ -474,7 +474,7 @@
SurfaceOrientedMeteringPointFactory factory = new SurfaceOrientedMeteringPointFactory(1.0f,
1.0f);
- FocusMeteringAction action = FocusMeteringAction.Builder.from(factory.createPoint(0, 0),
+ FocusMeteringAction action = new FocusMeteringAction.Builder(factory.createPoint(0, 0),
FocusMeteringAction.FLAG_AE | FocusMeteringAction.FLAG_AWB)
.build();
mCamera2CameraControl.startFocusAndMetering(action);
@@ -492,7 +492,7 @@
SurfaceOrientedMeteringPointFactory factory = new SurfaceOrientedMeteringPointFactory(1.0f,
1.0f);
- FocusMeteringAction action = FocusMeteringAction.Builder.from(factory.createPoint(0, 0))
+ FocusMeteringAction action = new FocusMeteringAction.Builder(factory.createPoint(0, 0))
.build();
mCamera2CameraControl.startFocusAndMetering(action);
HandlerUtil.waitForLooperToIdle(mHandler);
@@ -538,7 +538,7 @@
SurfaceOrientedMeteringPointFactory factory = new SurfaceOrientedMeteringPointFactory(1.0f,
1.0f);
- FocusMeteringAction action = FocusMeteringAction.Builder.from(factory.createPoint(0, 0))
+ FocusMeteringAction action = new FocusMeteringAction.Builder(factory.createPoint(0, 0))
.build();
mCamera2CameraControl.startFocusAndMetering(action);
HandlerUtil.waitForLooperToIdle(mHandler);
@@ -574,7 +574,7 @@
public void cancelFocusAndMetering_AFNotInvolved_notCancelAF() throws InterruptedException {
SurfaceOrientedMeteringPointFactory factory = new SurfaceOrientedMeteringPointFactory(1.0f,
1.0f);
- FocusMeteringAction action = FocusMeteringAction.Builder.from(factory.createPoint(0, 0),
+ FocusMeteringAction action = new FocusMeteringAction.Builder(factory.createPoint(0, 0),
FocusMeteringAction.FLAG_AE)
.build();
mCamera2CameraControl.startFocusAndMetering(action);
@@ -592,7 +592,7 @@
public void startFocus_afModeIsSetToAuto() throws InterruptedException {
SurfaceOrientedMeteringPointFactory factory = new SurfaceOrientedMeteringPointFactory(1.0f,
1.0f);
- FocusMeteringAction action = FocusMeteringAction.Builder.from(factory.createPoint(0, 0))
+ FocusMeteringAction action = new FocusMeteringAction.Builder(factory.createPoint(0, 0))
.build();
mCamera2CameraControl.startFocusAndMetering(action);
HandlerUtil.waitForLooperToIdle(mHandler);
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java
index c5467c9..01fe4c7 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/FocusMeteringControl.java
@@ -35,9 +35,6 @@
import androidx.camera.core.FocusMeteringResult;
import androidx.camera.core.MeteringPoint;
import androidx.camera.core.impl.CaptureConfig;
-import androidx.camera.core.impl.utils.executor.CameraXExecutors;
-import androidx.camera.core.impl.utils.futures.FutureCallback;
-import androidx.camera.core.impl.utils.futures.Futures;
import androidx.concurrent.futures.CallbackToFutureAdapter;
import androidx.concurrent.futures.CallbackToFutureAdapter.Completer;
@@ -154,20 +151,7 @@
if (!mIsActive) {
mExecutor.execute(() -> {
- ListenableFuture<Void> future = cancelFocusAndMetering();
- Futures.addCallback(future, new FutureCallback<Void>() {
- @Override
- public void onSuccess(@Nullable Void result) {
- }
-
- @Override
- public void onFailure(Throwable t) {
- if (!(t instanceof CameraControl.OperationCanceledException)) {
- // Throw the unexpected error.
- throw new RuntimeException(t);
- }
- }
- }, CameraXExecutors.directExecutor());
+ cancelFocusAndMeteringWithoutAsyncResult();
});
}
}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
index 0594c70..7c20bdc 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
@@ -461,8 +461,8 @@
private static boolean isPossibleMod16FromAspectRatio(Size resolution, Rational aspectRatio) {
int width = resolution.getWidth();
int height = resolution.getHeight();
- Rational invAspectRatio = new Rational(aspectRatio.getDenominator(),
- aspectRatio.getNumerator());
+ Rational invAspectRatio = new Rational(/* numerator= */aspectRatio.getDenominator(),
+ /* denominator= */aspectRatio.getNumerator());
if (width % 16 == 0 && height % 16 == 0) {
return ratioIntersectsMod16Segment(Math.max(0, height - ALIGN16), width, aspectRatio)
|| ratioIntersectsMod16Segment(Math.max(0, width - ALIGN16), height,
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/DisplayOrientedMeteringPointFactoryTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/DisplayOrientedMeteringPointFactoryTest.java
index e9d69d7..65967e2 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/DisplayOrientedMeteringPointFactoryTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/DisplayOrientedMeteringPointFactoryTest.java
@@ -24,7 +24,6 @@
import android.os.Build;
import android.view.Display;
import android.view.Surface;
-import android.view.WindowManager;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.CameraX;
@@ -63,7 +62,6 @@
private static final float HEIGHT = 640;
private static final String FRONT_CAMERA_ID = "1";
private static final String BACK_CAMERA_ID = "0";
- private Context mMockContext;
private Display mMockDisplay;
private static final CameraSelector FRONT_CAM =
new CameraSelector.Builder().requireLensFacing(
@@ -104,10 +102,6 @@
mMockDisplay = Mockito.mock(Display.class);
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
- WindowManager mockWindowManager = Mockito.mock(WindowManager.class);
- when(mockWindowManager.getDefaultDisplay()).thenReturn(mMockDisplay);
- mMockContext = Mockito.mock(Context.class);
- when(mMockContext.getSystemService(Context.WINDOW_SERVICE)).thenReturn(mockWindowManager);
}
@After
@@ -118,7 +112,7 @@
@Test
public void defaultAreaSize() {
DisplayOrientedMeteringPointFactory factory = new DisplayOrientedMeteringPointFactory(
- mMockContext, BACK_CAM, WIDTH, HEIGHT);
+ mMockDisplay, BACK_CAM, WIDTH, HEIGHT);
MeteringPoint point = factory.createPoint(0, 0);
assertThat(point.getSize()).isEqualTo(MeteringPointFactory.getDefaultPointSize());
@@ -128,7 +122,7 @@
@Test
public void createPointWithValidAreaSize() {
DisplayOrientedMeteringPointFactory factory = new DisplayOrientedMeteringPointFactory(
- mMockContext, BACK_CAM, WIDTH, HEIGHT);
+ mMockDisplay, BACK_CAM, WIDTH, HEIGHT);
final float areaSize = 0.2f;
MeteringPoint point = factory.createPoint(0, 0, areaSize);
@@ -141,7 +135,7 @@
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
DisplayOrientedMeteringPointFactory factory = new DisplayOrientedMeteringPointFactory(
- mMockContext, BACK_CAM, WIDTH, HEIGHT);
+ mMockDisplay, BACK_CAM, WIDTH, HEIGHT);
MeteringPoint meteringPoint = factory.createPoint(0f, 0f);
assertThat(meteringPoint.getX()).isEqualTo(0f);
@@ -167,7 +161,7 @@
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
DisplayOrientedMeteringPointFactory factory = new DisplayOrientedMeteringPointFactory(
- mMockContext, FRONT_CAM, WIDTH, HEIGHT);
+ mMockDisplay, FRONT_CAM, WIDTH, HEIGHT);
MeteringPoint meteringPoint = factory.createPoint(0f, 0f);
assertThat(meteringPoint.getX()).isEqualTo(1f);
@@ -193,7 +187,7 @@
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_90);
DisplayOrientedMeteringPointFactory factory = new DisplayOrientedMeteringPointFactory(
- mMockContext, BACK_CAM, WIDTH, HEIGHT);
+ mMockDisplay, BACK_CAM, WIDTH, HEIGHT);
MeteringPoint meteringPoint = factory.createPoint(0f, 0f);
assertThat(meteringPoint.getX()).isEqualTo(0f);
@@ -219,7 +213,7 @@
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_90);
DisplayOrientedMeteringPointFactory factory = new DisplayOrientedMeteringPointFactory(
- mMockContext, FRONT_CAM, WIDTH, HEIGHT);
+ mMockDisplay, FRONT_CAM, WIDTH, HEIGHT);
MeteringPoint meteringPoint = factory.createPoint(0f, 0f);
assertThat(meteringPoint.getX()).isEqualTo(1f);
@@ -245,7 +239,7 @@
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_180);
DisplayOrientedMeteringPointFactory factory = new DisplayOrientedMeteringPointFactory(
- mMockContext, BACK_CAM, WIDTH, HEIGHT);
+ mMockDisplay, BACK_CAM, WIDTH, HEIGHT);
MeteringPoint meteringPoint = factory.createPoint(0f, 0f);
assertThat(meteringPoint.getX()).isEqualTo(1f);
@@ -271,7 +265,7 @@
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_180);
DisplayOrientedMeteringPointFactory factory = new DisplayOrientedMeteringPointFactory(
- mMockContext, FRONT_CAM, WIDTH, HEIGHT);
+ mMockDisplay, FRONT_CAM, WIDTH, HEIGHT);
MeteringPoint meteringPoint = factory.createPoint(0f, 0f);
assertThat(meteringPoint.getX()).isEqualTo(0f);
@@ -297,7 +291,7 @@
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_270);
DisplayOrientedMeteringPointFactory factory = new DisplayOrientedMeteringPointFactory(
- mMockContext, BACK_CAM, WIDTH, HEIGHT);
+ mMockDisplay, BACK_CAM, WIDTH, HEIGHT);
MeteringPoint meteringPoint = factory.createPoint(0f, 0f);
assertThat(meteringPoint.getX()).isEqualTo(1f);
@@ -323,7 +317,7 @@
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_270);
DisplayOrientedMeteringPointFactory factory = new DisplayOrientedMeteringPointFactory(
- mMockContext, FRONT_CAM, WIDTH, HEIGHT);
+ mMockDisplay, FRONT_CAM, WIDTH, HEIGHT);
MeteringPoint meteringPoint = factory.createPoint(0f, 0f);
assertThat(meteringPoint.getX()).isEqualTo(0f);
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/FocusMeteringControlTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/FocusMeteringControlTest.java
index c96cfba..aacdb60 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/FocusMeteringControlTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/FocusMeteringControlTest.java
@@ -301,7 +301,7 @@
@Test
public void startFocusAndMetering_defaultPoint_3ARectssAreCorrect() {
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(mPoint1).build(),
+ new FocusMeteringAction.Builder(mPoint1).build(),
PREVIEW_ASPECT_RATIO_4_X_3);
MeteringRectangle[] afRects = getAfRects(mFocusMeteringControl);
@@ -320,7 +320,7 @@
public void startFocusAndMetering_multiplePoint_3ARectsAreCorrect() {
// Max AF count = 3, Max AE count = 3, Max AWB count = 1
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(mPoint1)
+ new FocusMeteringAction.Builder(mPoint1)
.addPoint(mPoint2)
.addPoint(mPoint3)
.build(), PREVIEW_ASPECT_RATIO_4_X_3);
@@ -347,7 +347,7 @@
public void startFocusAndMetering_multiplePointVariousModes() {
// Max AF count = 3, Max AE count = 3, Max AWB count = 1
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(mPoint1, FLAG_AWB)
+ new FocusMeteringAction.Builder(mPoint1, FLAG_AWB)
.addPoint(mPoint2, FLAG_AF | FLAG_AE)
.addPoint(mPoint3, FLAG_AF | FLAG_AE | FLAG_AWB)
.build(), PREVIEW_ASPECT_RATIO_4_X_3);
@@ -372,7 +372,7 @@
public void startFocusAndMetering_multiplePointVariousModes2() {
// Max AF count = 3, Max AE count = 3, Max AWB count = 1
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(mPoint1, FLAG_AF)
+ new FocusMeteringAction.Builder(mPoint1, FLAG_AF)
.addPoint(mPoint2, FLAG_AWB)
.addPoint(mPoint3, FLAG_AE)
.build(), PREVIEW_ASPECT_RATIO_4_X_3);
@@ -401,7 +401,7 @@
MeteringPoint centorPt = mPointFactory.createPoint(0.5f, 0.5f);
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(centorPt).build(),
+ new FocusMeteringAction.Builder(centorPt).build(),
PREVIEW_ASPECT_RATIO_4_X_3);
MeteringRectangle[] afRects = getAfRects(mFocusMeteringControl);
@@ -421,7 +421,7 @@
// use 16:9 preview aspect ratio
Rational previewAspectRatio = new Rational(16, 9);
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(mPoint1).build(),
+ new FocusMeteringAction.Builder(mPoint1).build(),
previewAspectRatio);
MeteringRectangle[] afRects = getAfRects(mFocusMeteringControl);
@@ -437,7 +437,7 @@
mFocusMeteringControl = initFocusMeteringControl(CAMERA1_ID);
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(mPoint1).build(),
+ new FocusMeteringAction.Builder(mPoint1).build(),
PREVIEW_ASPECT_RATIO_4_X_3);
MeteringRectangle[] afRects = getAfRects(mFocusMeteringControl);
@@ -458,7 +458,7 @@
new SurfaceOrientedMeteringPointFactory(1.0f, 1.0f, imageAnalysis);
MeteringPoint point = factory.createPoint(0, 0);
- mFocusMeteringControl.startFocusAndMetering(FocusMeteringAction.Builder.from(point).build(),
+ mFocusMeteringControl.startFocusAndMetering(new FocusMeteringAction.Builder(point).build(),
PREVIEW_ASPECT_RATIO_4_X_3);
MeteringRectangle[] afRects = getAfRects(mFocusMeteringControl);
@@ -473,7 +473,7 @@
MeteringPoint point2 = mPointFactory.createPoint(0.5f, 0.5f, 0.5f);
MeteringPoint point3 = mPointFactory.createPoint(0.5f, 0.5f, 0.1f);
- mFocusMeteringControl.startFocusAndMetering(FocusMeteringAction.Builder.from(point1)
+ mFocusMeteringControl.startFocusAndMetering(new FocusMeteringAction.Builder(point1)
.addPoint(point2)
.addPoint(point3).build(), PREVIEW_ASPECT_RATIO_4_X_3);
MeteringRectangle[] afRects = getAfRects(mFocusMeteringControl);
@@ -497,7 +497,7 @@
@Test
public void withAFPoints_AFIsTriggered() {
- mFocusMeteringControl.startFocusAndMetering(FocusMeteringAction.Builder.from(mPoint1,
+ mFocusMeteringControl.startFocusAndMetering(new FocusMeteringAction.Builder(mPoint1,
FLAG_AF | FLAG_AE | FLAG_AWB).build(),
PREVIEW_ASPECT_RATIO_4_X_3);
@@ -505,19 +505,19 @@
Mockito.reset(mFocusMeteringControl);
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(mPoint1, FLAG_AF).build(),
+ new FocusMeteringAction.Builder(mPoint1, FLAG_AF).build(),
PREVIEW_ASPECT_RATIO_4_X_3);
verify(mFocusMeteringControl).triggerAf();
Mockito.reset(mFocusMeteringControl);
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(mPoint1, FLAG_AF | FLAG_AE).build(),
+ new FocusMeteringAction.Builder(mPoint1, FLAG_AF | FLAG_AE).build(),
PREVIEW_ASPECT_RATIO_4_X_3);
verify(mFocusMeteringControl).triggerAf();
Mockito.reset(mFocusMeteringControl);
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(mPoint1, FLAG_AF | FLAG_AWB).build(),
+ new FocusMeteringAction.Builder(mPoint1, FLAG_AF | FLAG_AWB).build(),
PREVIEW_ASPECT_RATIO_4_X_3);
verify(mFocusMeteringControl).triggerAf();
Mockito.reset(mFocusMeteringControl);
@@ -526,25 +526,25 @@
@Test
public void withoutAFPoints_AFIsNotTriggered() {
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(mPoint1, FLAG_AE).build(),
+ new FocusMeteringAction.Builder(mPoint1, FLAG_AE).build(),
PREVIEW_ASPECT_RATIO_4_X_3);
verify(mFocusMeteringControl, never()).triggerAf();
Mockito.reset(mFocusMeteringControl);
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(mPoint1, FLAG_AWB).build(),
+ new FocusMeteringAction.Builder(mPoint1, FLAG_AWB).build(),
PREVIEW_ASPECT_RATIO_4_X_3);
verify(mFocusMeteringControl, never()).triggerAf();
Mockito.reset(mFocusMeteringControl);
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(mPoint1, FLAG_AE).build(),
+ new FocusMeteringAction.Builder(mPoint1, FLAG_AE).build(),
PREVIEW_ASPECT_RATIO_4_X_3);
verify(mFocusMeteringControl, never()).triggerAf();
Mockito.reset(mFocusMeteringControl);
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(mPoint1,
+ new FocusMeteringAction.Builder(mPoint1,
FLAG_AE | FLAG_AWB).build(),
PREVIEW_ASPECT_RATIO_4_X_3);
verify(mFocusMeteringControl, never()).triggerAf();
@@ -554,7 +554,7 @@
@Test
public void updateSessionConfigIsCalled() {
mFocusMeteringControl.startFocusAndMetering(
- FocusMeteringAction.Builder.from(mPoint1).build(),
+ new FocusMeteringAction.Builder(mPoint1).build(),
PREVIEW_ASPECT_RATIO_4_X_3);
verify(mCamera2CameraControl, times(1)).updateSessionConfig();
@@ -564,7 +564,7 @@
public void autoCancelDuration_cancelIsCalled() throws InterruptedException {
mFocusMeteringControl = spy(mFocusMeteringControl);
final long autocancelDuration = 500;
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1)
.setAutoCancelDuration(autocancelDuration, TimeUnit.MILLISECONDS)
.build();
@@ -581,7 +581,7 @@
mFocusMeteringControl = spy(mFocusMeteringControl);
final long autocancelDuration = 500;
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1)
.setAutoCancelDuration(autocancelDuration, TimeUnit.MILLISECONDS)
.disableAutoCancel()
.build();
@@ -687,7 +687,7 @@
@Test
public void startFocusMeteringAEAWB_regionsUpdated_completesWithFocusFalse()
throws ExecutionException, InterruptedException, TimeoutException {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FLAG_AE | FLAG_AWB)
.build();
ListenableFuture<FocusMeteringResult> future =
@@ -706,7 +706,7 @@
@Test
public void startFocusMeteringAE_regionsUpdated_completesWithFocusFalse()
throws ExecutionException, InterruptedException, TimeoutException {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FLAG_AE).build();
ListenableFuture<FocusMeteringResult> future2 =
@@ -723,7 +723,7 @@
@Test
public void startFocusMeteringAWB_regionsUpdated_completesWithFocusFalse()
throws ExecutionException, InterruptedException, TimeoutException {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FLAG_AWB)
.build();
@@ -741,7 +741,7 @@
@Test
public void startFocusMetering_AFLockedWith3ARegionsUpdated_completesWithfocusTrue()
throws ExecutionException, InterruptedException, TimeoutException {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1).build();
ListenableFuture<FocusMeteringResult> future =
mFocusMeteringControl.startFocusAndMetering(action,
@@ -764,7 +764,7 @@
@Test
public void startFocusMetering_AFLockedThen3ARegions_completesWithFocusTrue()
throws ExecutionException, InterruptedException, TimeoutException {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1).build();
ListenableFuture<FocusMeteringResult> future =
mFocusMeteringControl.startFocusAndMetering(action,
@@ -789,7 +789,7 @@
@Test
public void startFocusMetering_NotAFLocked_completesWithFocusFalse()
throws ExecutionException, InterruptedException, TimeoutException {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1).build();
ListenableFuture<FocusMeteringResult> future =
mFocusMeteringControl.startFocusAndMetering(action, PREVIEW_ASPECT_RATIO_4_X_3);
@@ -812,7 +812,7 @@
public void startFocusMeteringAFOnly_AfRegionUpdated_completesWithFocusTrue()
throws ExecutionException, InterruptedException, TimeoutException {
FocusMeteringAction action =
- FocusMeteringAction.Builder.from(mPoint1, FLAG_AF).build();
+ new FocusMeteringAction.Builder(mPoint1, FLAG_AF).build();
ListenableFuture<FocusMeteringResult> future =
mFocusMeteringControl.startFocusAndMetering(action, PREVIEW_ASPECT_RATIO_4_X_3);
@@ -834,7 +834,7 @@
throws ExecutionException, InterruptedException, TimeoutException {
// Use camera which does not support AF_AUTO
FocusMeteringControl focusMeteringControl = initFocusMeteringControl(CAMERA2_ID);
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1)
.build();
ListenableFuture<FocusMeteringResult> result = focusMeteringControl.startFocusAndMetering(
@@ -852,7 +852,7 @@
@Test
public void startFocusMetering_cancelBeforeCompleted_failWithOperationCancelledOperation() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1).build();
ListenableFuture<FocusMeteringResult> future = mFocusMeteringControl.startFocusAndMetering(
action, PREVIEW_ASPECT_RATIO_4_X_3);
@@ -869,7 +869,7 @@
@Test
public void startThenCancelThenStart_previous2FuturesFailsWithOperationCancelled()
throws ExecutionException, InterruptedException, TimeoutException {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1)
.build();
ListenableFuture<FocusMeteringResult> result1 =
@@ -900,7 +900,7 @@
@Test
public void startMultipleActions_cancelNonLatest()
throws ExecutionException, InterruptedException, TimeoutException {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1)
.build();
ListenableFuture<FocusMeteringResult> result1 =
@@ -931,7 +931,7 @@
@Test
public void startFocusMetering_focusedThenCancel_futureStillCompletes()
throws ExecutionException, InterruptedException, TimeoutException {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1)
.build();
ListenableFuture<FocusMeteringResult> result =
@@ -955,7 +955,7 @@
@Test
public void cancelFocusAndMetering_regionIsReset() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FLAG_AF | FLAG_AE | FLAG_AWB)
.addPoint(mPoint2, FLAG_AF | FLAG_AE | FLAG_AWB)
.build();
@@ -982,7 +982,7 @@
@Test
public void cancelFocusAndMetering_updateSessionIsCalled() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FLAG_AF | FLAG_AE | FLAG_AWB)
.addPoint(mPoint2, FLAG_AF | FLAG_AE | FLAG_AWB)
.build();
@@ -998,7 +998,7 @@
@Test
public void cancelFocusAndMetering_triggerCancelAfProperly() {
// If AF is enabled, cancel operation needs to call cancelAfAeTriggerInternal(true, false)
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FLAG_AF | FLAG_AE | FLAG_AWB)
.build();
@@ -1007,19 +1007,19 @@
mFocusMeteringControl.cancelFocusAndMetering();
verify(mFocusMeteringControl, times(1)).cancelAfAeTrigger(true, false);
- action = FocusMeteringAction.Builder.from(mPoint1, FLAG_AF | FLAG_AE).build();
+ action = new FocusMeteringAction.Builder(mPoint1, FLAG_AF | FLAG_AE).build();
mFocusMeteringControl.startFocusAndMetering(action, PREVIEW_ASPECT_RATIO_4_X_3);
Mockito.reset(mFocusMeteringControl);
mFocusMeteringControl.cancelFocusAndMetering();
verify(mFocusMeteringControl, times(1)).cancelAfAeTrigger(true, false);
- action = FocusMeteringAction.Builder.from(mPoint1, FLAG_AF | FLAG_AWB).build();
+ action = new FocusMeteringAction.Builder(mPoint1, FLAG_AF | FLAG_AWB).build();
mFocusMeteringControl.startFocusAndMetering(action, PREVIEW_ASPECT_RATIO_4_X_3);
Mockito.reset(mFocusMeteringControl);
mFocusMeteringControl.cancelFocusAndMetering();
verify(mFocusMeteringControl, times(1)).cancelAfAeTrigger(true, false);
- action = FocusMeteringAction.Builder.from(mPoint1, FLAG_AF)
+ action = new FocusMeteringAction.Builder(mPoint1, FLAG_AF)
.build();
mFocusMeteringControl.startFocusAndMetering(action, PREVIEW_ASPECT_RATIO_4_X_3);
Mockito.reset(mFocusMeteringControl);
@@ -1029,20 +1029,20 @@
@Test
public void cancelFocusAndMetering_AFNotInvolved_cancelAfNotTriggered() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1, FLAG_AE).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1, FLAG_AE).build();
mFocusMeteringControl.startFocusAndMetering(action, PREVIEW_ASPECT_RATIO_4_X_3);
Mockito.reset(mFocusMeteringControl);
mFocusMeteringControl.cancelFocusAndMetering();
verify(mFocusMeteringControl, never()).cancelAfAeTrigger(true, false);
- action = FocusMeteringAction.Builder.from(mPoint1, FLAG_AWB).build();
+ action = new FocusMeteringAction.Builder(mPoint1, FLAG_AWB).build();
mFocusMeteringControl.startFocusAndMetering(action, PREVIEW_ASPECT_RATIO_4_X_3);
Mockito.reset(mFocusMeteringControl);
mFocusMeteringControl.cancelFocusAndMetering();
verify(mFocusMeteringControl, never()).cancelAfAeTrigger(true, false);
- action = FocusMeteringAction.Builder.from(mPoint1, FLAG_AE | FLAG_AWB).build();
+ action = new FocusMeteringAction.Builder(mPoint1, FLAG_AE | FLAG_AWB).build();
mFocusMeteringControl.startFocusAndMetering(action, PREVIEW_ASPECT_RATIO_4_X_3);
Mockito.reset(mFocusMeteringControl);
mFocusMeteringControl.cancelFocusAndMetering();
@@ -1051,7 +1051,7 @@
@Test
public void cancelFocusMetering_actionIsCancelledAndfutureCompletes() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1).build();
ListenableFuture<FocusMeteringResult> actionResult =
mFocusMeteringControl.startFocusAndMetering(action,
PREVIEW_ASPECT_RATIO_4_X_3);
@@ -1077,7 +1077,7 @@
mFocusMeteringControl = spy(mFocusMeteringControl);
final long autocancelDuration = 500;
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1)
.setAutoCancelDuration(autocancelDuration, TimeUnit.MILLISECONDS)
.build();
@@ -1094,7 +1094,7 @@
@Test
public void startFocusMetering_isAfAutoModeIsTrue() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1).build();
verifyAfMode(CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
@@ -1113,7 +1113,7 @@
@Test
public void startFocusMetering_AfNotInvolved_isAfAutoModeIsSet() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FLAG_AE | FLAG_AWB).build();
verifyAfMode(CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
@@ -1123,7 +1123,7 @@
@Test
public void startAndThenCancel_isAfAutoModeIsFalse() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1).build();
mFocusMeteringControl.startFocusAndMetering(action, PREVIEW_ASPECT_RATIO_4_X_3);
mFocusMeteringControl.cancelFocusAndMetering();
verifyAfMode(CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
@@ -1132,7 +1132,7 @@
@Test
public void startFocusMeteringAFAEAWB_noPointsAreSupported_failFuture() {
FocusMeteringControl focusMeteringControl = initFocusMeteringControl(CAMERA3_ID);
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FLAG_AF | FLAG_AE | FLAG_AWB).build();
ListenableFuture<FocusMeteringResult> future =
@@ -1153,7 +1153,7 @@
@Test
public void startFocusMeteringAEAWB_noPointsAreSupported_failFuture() {
FocusMeteringControl focusMeteringControl = initFocusMeteringControl(CAMERA3_ID);
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FLAG_AE | FLAG_AWB).build();
ListenableFuture<FocusMeteringResult> future =
@@ -1174,7 +1174,7 @@
@Test
public void startFocusMeteringAFAWB_noPointsAreSupported_failFuture() {
FocusMeteringControl focusMeteringControl = initFocusMeteringControl(CAMERA3_ID);
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FLAG_AF | FLAG_AWB).build();
ListenableFuture<FocusMeteringResult> future =
@@ -1196,8 +1196,8 @@
throws ExecutionException, InterruptedException, TimeoutException {
// Camera0 only support 3 AF, 3 AE, 1 AWB regions, here we try to have 1 AE region, 2 AWB
// regions. it should still complete the future.
- FocusMeteringAction action = FocusMeteringAction.Builder
- .from(mPoint1, FLAG_AE | FLAG_AWB)
+ FocusMeteringAction action =
+ new FocusMeteringAction.Builder(mPoint1, FLAG_AE | FLAG_AWB)
.addPoint(mPoint2, FLAG_AWB)
.build();
diff --git a/camera/camera-core/api/1.0.0-alpha08.txt b/camera/camera-core/api/1.0.0-alpha08.txt
new file mode 100644
index 0000000..8a23bc6
--- /dev/null
+++ b/camera/camera-core/api/1.0.0-alpha08.txt
@@ -0,0 +1,244 @@
+// Signature format: 3.0
+package androidx.camera.core {
+
+ public class AspectRatio {
+ field public static final int RATIO_16_9 = 1; // 0x1
+ field public static final int RATIO_4_3 = 0; // 0x0
+ }
+
+ public interface Camera {
+ method public androidx.camera.core.CameraControl getCameraControl();
+ method public androidx.camera.core.CameraInfo getCameraInfo();
+ }
+
+ public interface CameraControl {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelFocusAndMetering();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
+ }
+
+ public static final class CameraControl.OperationCanceledException extends java.lang.Exception {
+ }
+
+ public interface CameraInfo {
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getLinearZoom();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getMaxZoomRatio();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getMinZoomRatio();
+ method public int getSensorRotationDegrees();
+ method public int getSensorRotationDegrees(int);
+ method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getZoomRatio();
+ method public boolean hasFlashUnit();
+ }
+
+ public final class CameraInfoUnavailableException extends java.lang.Exception {
+ }
+
+ public final class CameraSelector {
+ field public static final androidx.camera.core.CameraSelector DEFAULT_BACK_CAMERA;
+ field public static final androidx.camera.core.CameraSelector DEFAULT_FRONT_CAMERA;
+ field public static final int LENS_FACING_BACK = 1; // 0x1
+ field public static final int LENS_FACING_FRONT = 0; // 0x0
+ }
+
+ public static final class CameraSelector.Builder {
+ ctor public CameraSelector.Builder();
+ method public androidx.camera.core.CameraSelector build();
+ method public androidx.camera.core.CameraSelector.Builder requireLensFacing(int);
+ }
+
+ public final class CameraXConfig {
+ field public static final androidx.camera.core.impl.Config.Option<java.lang.Class<?>!> OPTION_TARGET_CLASS;
+ field public static final androidx.camera.core.impl.Config.Option<java.lang.String!> OPTION_TARGET_NAME;
+ }
+
+ public static final class CameraXConfig.Builder {
+ ctor public CameraXConfig.Builder();
+ method public androidx.camera.core.CameraXConfig build();
+ method public static androidx.camera.core.CameraXConfig.Builder fromConfig(androidx.camera.core.CameraXConfig);
+ method public androidx.camera.core.CameraXConfig.Builder setCameraExecutor(java.util.concurrent.Executor);
+ }
+
+ public static interface CameraXConfig.Provider {
+ method public androidx.camera.core.CameraXConfig getCameraXConfig();
+ }
+
+ public final class DisplayOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public DisplayOrientedMeteringPointFactory(android.content.Context, androidx.camera.core.CameraSelector, float, float);
+ ctor public DisplayOrientedMeteringPointFactory(android.view.Display, androidx.camera.core.CameraSelector, float, float);
+ }
+
+ public interface ExtendableBuilder<T> {
+ method public T build();
+ }
+
+ public final class FocusMeteringAction {
+ method public long getAutoCancelDurationInMillis();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAe();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAf();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAwb();
+ method public boolean isAutoCancelEnabled();
+ field public static final int FLAG_AE = 2; // 0x2
+ field public static final int FLAG_AF = 1; // 0x1
+ field public static final int FLAG_AWB = 4; // 0x4
+ }
+
+ public static class FocusMeteringAction.Builder {
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction build();
+ method public androidx.camera.core.FocusMeteringAction.Builder disableAutoCancel();
+ method public static androidx.camera.core.FocusMeteringAction.Builder from(androidx.camera.core.MeteringPoint);
+ method public static androidx.camera.core.FocusMeteringAction.Builder from(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction.Builder setAutoCancelDuration(@IntRange(from=1) long, java.util.concurrent.TimeUnit);
+ }
+
+ public final class FocusMeteringResult {
+ method public boolean isFocusSuccessful();
+ }
+
+ public final class ImageAnalysis extends androidx.camera.core.UseCase {
+ method public void clearAnalyzer();
+ method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+ method public void setTargetRotation(int);
+ field public static final int STRATEGY_BLOCK_PRODUCER = 1; // 0x1
+ field public static final int STRATEGY_KEEP_ONLY_LATEST = 0; // 0x0
+ }
+
+ public static interface ImageAnalysis.Analyzer {
+ method public void analyze(androidx.camera.core.ImageProxy);
+ }
+
+ public static final class ImageAnalysis.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageAnalysis> {
+ ctor public ImageAnalysis.Builder();
+ method public androidx.camera.core.ImageAnalysis build();
+ method public androidx.camera.core.ImageAnalysis.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageAnalysis.Builder setBackpressureStrategy(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
+ }
+
+ public class ImageCapture extends androidx.camera.core.UseCase {
+ method public int getFlashMode();
+ method public void setFlashMode(int);
+ method public void setTargetAspectRatioCustom(android.util.Rational);
+ method public void setTargetRotation(int);
+ method public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+ method public void takePicture(java.io.File, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ method public void takePicture(java.io.File, androidx.camera.core.ImageCapture.Metadata, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ field public static final int CAPTURE_MODE_MAXIMIZE_QUALITY = 0; // 0x0
+ field public static final int CAPTURE_MODE_MINIMIZE_LATENCY = 1; // 0x1
+ field public static final int ERROR_CAMERA_CLOSED = 3; // 0x3
+ field public static final int ERROR_CAPTURE_FAILED = 2; // 0x2
+ field public static final int ERROR_FILE_IO = 1; // 0x1
+ field public static final int ERROR_INVALID_CAMERA = 4; // 0x4
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int FLASH_MODE_AUTO = 0; // 0x0
+ field public static final int FLASH_MODE_OFF = 2; // 0x2
+ field public static final int FLASH_MODE_ON = 1; // 0x1
+ }
+
+ public static final class ImageCapture.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageCapture> {
+ ctor public ImageCapture.Builder();
+ method public androidx.camera.core.ImageCapture build();
+ method public androidx.camera.core.ImageCapture.Builder setCaptureMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
+ method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
+ }
+
+ public static final class ImageCapture.Metadata {
+ ctor public ImageCapture.Metadata();
+ method public android.location.Location? getLocation();
+ method public boolean isReversedHorizontal();
+ method public boolean isReversedVertical();
+ method public void setLocation(android.location.Location?);
+ method public void setReversedHorizontal(boolean);
+ method public void setReversedVertical(boolean);
+ }
+
+ public abstract static class ImageCapture.OnImageCapturedCallback {
+ ctor public ImageCapture.OnImageCapturedCallback();
+ method public void onCaptureSuccess(androidx.camera.core.ImageProxy);
+ method public void onError(int, String, Throwable?);
+ }
+
+ public static interface ImageCapture.OnImageSavedCallback {
+ method public void onError(int, String, Throwable?);
+ method public void onImageSaved(java.io.File);
+ }
+
+ public interface ImageInfo {
+ method public int getRotationDegrees();
+ method public long getTimestamp();
+ }
+
+ public interface ImageProxy extends java.lang.AutoCloseable {
+ method public void close();
+ method public android.graphics.Rect getCropRect();
+ method public int getFormat();
+ method public int getHeight();
+ method public androidx.camera.core.ImageInfo getImageInfo();
+ method public androidx.camera.core.ImageProxy.PlaneProxy![] getPlanes();
+ method public int getWidth();
+ method public void setCropRect(android.graphics.Rect?);
+ }
+
+ public static interface ImageProxy.PlaneProxy {
+ method public java.nio.ByteBuffer getBuffer();
+ method public int getPixelStride();
+ method public int getRowStride();
+ }
+
+ public class MeteringPoint {
+ method public float getSize();
+ }
+
+ public abstract class MeteringPointFactory {
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float);
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float, float);
+ method public static float getDefaultPointSize();
+ }
+
+ public class Preview extends androidx.camera.core.UseCase {
+ method @UiThread public androidx.camera.core.Preview.PreviewSurfaceProvider? getPreviewSurfaceProvider();
+ method @UiThread public void setPreviewSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.PreviewSurfaceProvider?);
+ method @UiThread public void setPreviewSurfaceProvider(androidx.camera.core.Preview.PreviewSurfaceProvider?);
+ }
+
+ public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
+ ctor public Preview.Builder();
+ method public androidx.camera.core.Preview build();
+ method public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.Preview.Builder setTargetName(String);
+ method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.Preview.Builder setTargetRotation(int);
+ }
+
+ public static interface Preview.PreviewSurfaceProvider {
+ method public com.google.common.util.concurrent.ListenableFuture<android.view.Surface!> provideSurface(android.util.Size, com.google.common.util.concurrent.ListenableFuture<java.lang.Void!>);
+ }
+
+ public class SurfaceOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public SurfaceOrientedMeteringPointFactory(float, float);
+ ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
+ }
+
+ public class TorchState {
+ field public static final int OFF = 0; // 0x0
+ field public static final int ON = 1; // 0x1
+ }
+
+ public abstract class UseCase {
+ }
+
+}
+
diff --git a/camera/camera-core/api/api_lint.ignore b/camera/camera-core/api/api_lint.ignore
new file mode 100644
index 0000000..1a0493c
--- /dev/null
+++ b/camera/camera-core/api/api_lint.ignore
@@ -0,0 +1,9 @@
+// Baseline format: 1.0
+HiddenTypeParameter: androidx.camera.core.CameraXConfig#OPTION_TARGET_CLASS:
+ Field CameraXConfig.OPTION_TARGET_CLASS references hidden type androidx.camera.core.impl.Config.Option<java.lang.Class<?>>.
+HiddenTypeParameter: androidx.camera.core.CameraXConfig#OPTION_TARGET_NAME:
+ Field CameraXConfig.OPTION_TARGET_NAME references hidden type androidx.camera.core.impl.Config.Option<java.lang.String>.
+
+
+TopLevelBuilder: androidx.camera.core.ExtendableBuilder:
+ Builder should be defined as inner class: androidx.camera.core.ExtendableBuilder
diff --git a/camera/camera-core/api/current.txt b/camera/camera-core/api/current.txt
new file mode 100644
index 0000000..8a23bc6
--- /dev/null
+++ b/camera/camera-core/api/current.txt
@@ -0,0 +1,244 @@
+// Signature format: 3.0
+package androidx.camera.core {
+
+ public class AspectRatio {
+ field public static final int RATIO_16_9 = 1; // 0x1
+ field public static final int RATIO_4_3 = 0; // 0x0
+ }
+
+ public interface Camera {
+ method public androidx.camera.core.CameraControl getCameraControl();
+ method public androidx.camera.core.CameraInfo getCameraInfo();
+ }
+
+ public interface CameraControl {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelFocusAndMetering();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
+ }
+
+ public static final class CameraControl.OperationCanceledException extends java.lang.Exception {
+ }
+
+ public interface CameraInfo {
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getLinearZoom();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getMaxZoomRatio();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getMinZoomRatio();
+ method public int getSensorRotationDegrees();
+ method public int getSensorRotationDegrees(int);
+ method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getZoomRatio();
+ method public boolean hasFlashUnit();
+ }
+
+ public final class CameraInfoUnavailableException extends java.lang.Exception {
+ }
+
+ public final class CameraSelector {
+ field public static final androidx.camera.core.CameraSelector DEFAULT_BACK_CAMERA;
+ field public static final androidx.camera.core.CameraSelector DEFAULT_FRONT_CAMERA;
+ field public static final int LENS_FACING_BACK = 1; // 0x1
+ field public static final int LENS_FACING_FRONT = 0; // 0x0
+ }
+
+ public static final class CameraSelector.Builder {
+ ctor public CameraSelector.Builder();
+ method public androidx.camera.core.CameraSelector build();
+ method public androidx.camera.core.CameraSelector.Builder requireLensFacing(int);
+ }
+
+ public final class CameraXConfig {
+ field public static final androidx.camera.core.impl.Config.Option<java.lang.Class<?>!> OPTION_TARGET_CLASS;
+ field public static final androidx.camera.core.impl.Config.Option<java.lang.String!> OPTION_TARGET_NAME;
+ }
+
+ public static final class CameraXConfig.Builder {
+ ctor public CameraXConfig.Builder();
+ method public androidx.camera.core.CameraXConfig build();
+ method public static androidx.camera.core.CameraXConfig.Builder fromConfig(androidx.camera.core.CameraXConfig);
+ method public androidx.camera.core.CameraXConfig.Builder setCameraExecutor(java.util.concurrent.Executor);
+ }
+
+ public static interface CameraXConfig.Provider {
+ method public androidx.camera.core.CameraXConfig getCameraXConfig();
+ }
+
+ public final class DisplayOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public DisplayOrientedMeteringPointFactory(android.content.Context, androidx.camera.core.CameraSelector, float, float);
+ ctor public DisplayOrientedMeteringPointFactory(android.view.Display, androidx.camera.core.CameraSelector, float, float);
+ }
+
+ public interface ExtendableBuilder<T> {
+ method public T build();
+ }
+
+ public final class FocusMeteringAction {
+ method public long getAutoCancelDurationInMillis();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAe();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAf();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAwb();
+ method public boolean isAutoCancelEnabled();
+ field public static final int FLAG_AE = 2; // 0x2
+ field public static final int FLAG_AF = 1; // 0x1
+ field public static final int FLAG_AWB = 4; // 0x4
+ }
+
+ public static class FocusMeteringAction.Builder {
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction build();
+ method public androidx.camera.core.FocusMeteringAction.Builder disableAutoCancel();
+ method public static androidx.camera.core.FocusMeteringAction.Builder from(androidx.camera.core.MeteringPoint);
+ method public static androidx.camera.core.FocusMeteringAction.Builder from(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction.Builder setAutoCancelDuration(@IntRange(from=1) long, java.util.concurrent.TimeUnit);
+ }
+
+ public final class FocusMeteringResult {
+ method public boolean isFocusSuccessful();
+ }
+
+ public final class ImageAnalysis extends androidx.camera.core.UseCase {
+ method public void clearAnalyzer();
+ method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+ method public void setTargetRotation(int);
+ field public static final int STRATEGY_BLOCK_PRODUCER = 1; // 0x1
+ field public static final int STRATEGY_KEEP_ONLY_LATEST = 0; // 0x0
+ }
+
+ public static interface ImageAnalysis.Analyzer {
+ method public void analyze(androidx.camera.core.ImageProxy);
+ }
+
+ public static final class ImageAnalysis.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageAnalysis> {
+ ctor public ImageAnalysis.Builder();
+ method public androidx.camera.core.ImageAnalysis build();
+ method public androidx.camera.core.ImageAnalysis.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageAnalysis.Builder setBackpressureStrategy(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
+ }
+
+ public class ImageCapture extends androidx.camera.core.UseCase {
+ method public int getFlashMode();
+ method public void setFlashMode(int);
+ method public void setTargetAspectRatioCustom(android.util.Rational);
+ method public void setTargetRotation(int);
+ method public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+ method public void takePicture(java.io.File, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ method public void takePicture(java.io.File, androidx.camera.core.ImageCapture.Metadata, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ field public static final int CAPTURE_MODE_MAXIMIZE_QUALITY = 0; // 0x0
+ field public static final int CAPTURE_MODE_MINIMIZE_LATENCY = 1; // 0x1
+ field public static final int ERROR_CAMERA_CLOSED = 3; // 0x3
+ field public static final int ERROR_CAPTURE_FAILED = 2; // 0x2
+ field public static final int ERROR_FILE_IO = 1; // 0x1
+ field public static final int ERROR_INVALID_CAMERA = 4; // 0x4
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int FLASH_MODE_AUTO = 0; // 0x0
+ field public static final int FLASH_MODE_OFF = 2; // 0x2
+ field public static final int FLASH_MODE_ON = 1; // 0x1
+ }
+
+ public static final class ImageCapture.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageCapture> {
+ ctor public ImageCapture.Builder();
+ method public androidx.camera.core.ImageCapture build();
+ method public androidx.camera.core.ImageCapture.Builder setCaptureMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
+ method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
+ }
+
+ public static final class ImageCapture.Metadata {
+ ctor public ImageCapture.Metadata();
+ method public android.location.Location? getLocation();
+ method public boolean isReversedHorizontal();
+ method public boolean isReversedVertical();
+ method public void setLocation(android.location.Location?);
+ method public void setReversedHorizontal(boolean);
+ method public void setReversedVertical(boolean);
+ }
+
+ public abstract static class ImageCapture.OnImageCapturedCallback {
+ ctor public ImageCapture.OnImageCapturedCallback();
+ method public void onCaptureSuccess(androidx.camera.core.ImageProxy);
+ method public void onError(int, String, Throwable?);
+ }
+
+ public static interface ImageCapture.OnImageSavedCallback {
+ method public void onError(int, String, Throwable?);
+ method public void onImageSaved(java.io.File);
+ }
+
+ public interface ImageInfo {
+ method public int getRotationDegrees();
+ method public long getTimestamp();
+ }
+
+ public interface ImageProxy extends java.lang.AutoCloseable {
+ method public void close();
+ method public android.graphics.Rect getCropRect();
+ method public int getFormat();
+ method public int getHeight();
+ method public androidx.camera.core.ImageInfo getImageInfo();
+ method public androidx.camera.core.ImageProxy.PlaneProxy![] getPlanes();
+ method public int getWidth();
+ method public void setCropRect(android.graphics.Rect?);
+ }
+
+ public static interface ImageProxy.PlaneProxy {
+ method public java.nio.ByteBuffer getBuffer();
+ method public int getPixelStride();
+ method public int getRowStride();
+ }
+
+ public class MeteringPoint {
+ method public float getSize();
+ }
+
+ public abstract class MeteringPointFactory {
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float);
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float, float);
+ method public static float getDefaultPointSize();
+ }
+
+ public class Preview extends androidx.camera.core.UseCase {
+ method @UiThread public androidx.camera.core.Preview.PreviewSurfaceProvider? getPreviewSurfaceProvider();
+ method @UiThread public void setPreviewSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.PreviewSurfaceProvider?);
+ method @UiThread public void setPreviewSurfaceProvider(androidx.camera.core.Preview.PreviewSurfaceProvider?);
+ }
+
+ public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
+ ctor public Preview.Builder();
+ method public androidx.camera.core.Preview build();
+ method public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.Preview.Builder setTargetName(String);
+ method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.Preview.Builder setTargetRotation(int);
+ }
+
+ public static interface Preview.PreviewSurfaceProvider {
+ method public com.google.common.util.concurrent.ListenableFuture<android.view.Surface!> provideSurface(android.util.Size, com.google.common.util.concurrent.ListenableFuture<java.lang.Void!>);
+ }
+
+ public class SurfaceOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public SurfaceOrientedMeteringPointFactory(float, float);
+ ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
+ }
+
+ public class TorchState {
+ field public static final int OFF = 0; // 0x0
+ field public static final int ON = 1; // 0x1
+ }
+
+ public abstract class UseCase {
+ }
+
+}
+
diff --git a/camera/camera-core/api/public_plus_experimental_1.0.0-alpha08.txt b/camera/camera-core/api/public_plus_experimental_1.0.0-alpha08.txt
new file mode 100644
index 0000000..8b6aaf2
--- /dev/null
+++ b/camera/camera-core/api/public_plus_experimental_1.0.0-alpha08.txt
@@ -0,0 +1,248 @@
+// Signature format: 3.0
+package androidx.camera.core {
+
+ public class AspectRatio {
+ field public static final int RATIO_16_9 = 1; // 0x1
+ field public static final int RATIO_4_3 = 0; // 0x0
+ }
+
+ public interface Camera {
+ method public androidx.camera.core.CameraControl getCameraControl();
+ method public androidx.camera.core.CameraInfo getCameraInfo();
+ }
+
+ public interface CameraControl {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelFocusAndMetering();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
+ }
+
+ public static final class CameraControl.OperationCanceledException extends java.lang.Exception {
+ }
+
+ public interface CameraInfo {
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getLinearZoom();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getMaxZoomRatio();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getMinZoomRatio();
+ method public int getSensorRotationDegrees();
+ method public int getSensorRotationDegrees(int);
+ method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getZoomRatio();
+ method public boolean hasFlashUnit();
+ }
+
+ public final class CameraInfoUnavailableException extends java.lang.Exception {
+ }
+
+ public final class CameraSelector {
+ field public static final androidx.camera.core.CameraSelector DEFAULT_BACK_CAMERA;
+ field public static final androidx.camera.core.CameraSelector DEFAULT_FRONT_CAMERA;
+ field public static final int LENS_FACING_BACK = 1; // 0x1
+ field public static final int LENS_FACING_FRONT = 0; // 0x0
+ }
+
+ public static final class CameraSelector.Builder {
+ ctor public CameraSelector.Builder();
+ method public androidx.camera.core.CameraSelector build();
+ method public androidx.camera.core.CameraSelector.Builder requireLensFacing(int);
+ }
+
+ public final class CameraXConfig {
+ field public static final androidx.camera.core.impl.Config.Option<java.lang.Class<?>!> OPTION_TARGET_CLASS;
+ field public static final androidx.camera.core.impl.Config.Option<java.lang.String!> OPTION_TARGET_NAME;
+ }
+
+ public static final class CameraXConfig.Builder {
+ ctor public CameraXConfig.Builder();
+ method public androidx.camera.core.CameraXConfig build();
+ method public static androidx.camera.core.CameraXConfig.Builder fromConfig(androidx.camera.core.CameraXConfig);
+ method public androidx.camera.core.CameraXConfig.Builder setCameraExecutor(java.util.concurrent.Executor);
+ }
+
+ public static interface CameraXConfig.Provider {
+ method public androidx.camera.core.CameraXConfig getCameraXConfig();
+ }
+
+ public final class DisplayOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public DisplayOrientedMeteringPointFactory(android.content.Context, androidx.camera.core.CameraSelector, float, float);
+ ctor public DisplayOrientedMeteringPointFactory(android.view.Display, androidx.camera.core.CameraSelector, float, float);
+ }
+
+ @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalGetImage {
+ }
+
+ public interface ExtendableBuilder<T> {
+ method public T build();
+ }
+
+ public final class FocusMeteringAction {
+ method public long getAutoCancelDurationInMillis();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAe();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAf();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAwb();
+ method public boolean isAutoCancelEnabled();
+ field public static final int FLAG_AE = 2; // 0x2
+ field public static final int FLAG_AF = 1; // 0x1
+ field public static final int FLAG_AWB = 4; // 0x4
+ }
+
+ public static class FocusMeteringAction.Builder {
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction build();
+ method public androidx.camera.core.FocusMeteringAction.Builder disableAutoCancel();
+ method public static androidx.camera.core.FocusMeteringAction.Builder from(androidx.camera.core.MeteringPoint);
+ method public static androidx.camera.core.FocusMeteringAction.Builder from(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction.Builder setAutoCancelDuration(@IntRange(from=1) long, java.util.concurrent.TimeUnit);
+ }
+
+ public final class FocusMeteringResult {
+ method public boolean isFocusSuccessful();
+ }
+
+ public final class ImageAnalysis extends androidx.camera.core.UseCase {
+ method public void clearAnalyzer();
+ method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+ method public void setTargetRotation(int);
+ field public static final int STRATEGY_BLOCK_PRODUCER = 1; // 0x1
+ field public static final int STRATEGY_KEEP_ONLY_LATEST = 0; // 0x0
+ }
+
+ public static interface ImageAnalysis.Analyzer {
+ method public void analyze(androidx.camera.core.ImageProxy);
+ }
+
+ public static final class ImageAnalysis.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageAnalysis> {
+ ctor public ImageAnalysis.Builder();
+ method public androidx.camera.core.ImageAnalysis build();
+ method public androidx.camera.core.ImageAnalysis.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageAnalysis.Builder setBackpressureStrategy(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
+ }
+
+ public class ImageCapture extends androidx.camera.core.UseCase {
+ method public int getFlashMode();
+ method public void setFlashMode(int);
+ method public void setTargetAspectRatioCustom(android.util.Rational);
+ method public void setTargetRotation(int);
+ method public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+ method public void takePicture(java.io.File, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ method public void takePicture(java.io.File, androidx.camera.core.ImageCapture.Metadata, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ field public static final int CAPTURE_MODE_MAXIMIZE_QUALITY = 0; // 0x0
+ field public static final int CAPTURE_MODE_MINIMIZE_LATENCY = 1; // 0x1
+ field public static final int ERROR_CAMERA_CLOSED = 3; // 0x3
+ field public static final int ERROR_CAPTURE_FAILED = 2; // 0x2
+ field public static final int ERROR_FILE_IO = 1; // 0x1
+ field public static final int ERROR_INVALID_CAMERA = 4; // 0x4
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int FLASH_MODE_AUTO = 0; // 0x0
+ field public static final int FLASH_MODE_OFF = 2; // 0x2
+ field public static final int FLASH_MODE_ON = 1; // 0x1
+ }
+
+ public static final class ImageCapture.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageCapture> {
+ ctor public ImageCapture.Builder();
+ method public androidx.camera.core.ImageCapture build();
+ method public androidx.camera.core.ImageCapture.Builder setCaptureMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
+ method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
+ }
+
+ public static final class ImageCapture.Metadata {
+ ctor public ImageCapture.Metadata();
+ method public android.location.Location? getLocation();
+ method public boolean isReversedHorizontal();
+ method public boolean isReversedVertical();
+ method public void setLocation(android.location.Location?);
+ method public void setReversedHorizontal(boolean);
+ method public void setReversedVertical(boolean);
+ }
+
+ public abstract static class ImageCapture.OnImageCapturedCallback {
+ ctor public ImageCapture.OnImageCapturedCallback();
+ method public void onCaptureSuccess(androidx.camera.core.ImageProxy);
+ method public void onError(int, String, Throwable?);
+ }
+
+ public static interface ImageCapture.OnImageSavedCallback {
+ method public void onError(int, String, Throwable?);
+ method public void onImageSaved(java.io.File);
+ }
+
+ public interface ImageInfo {
+ method public int getRotationDegrees();
+ method public long getTimestamp();
+ }
+
+ public interface ImageProxy extends java.lang.AutoCloseable {
+ method public void close();
+ method public android.graphics.Rect getCropRect();
+ method public int getFormat();
+ method public int getHeight();
+ method @androidx.camera.core.ExperimentalGetImage public android.media.Image? getImage();
+ method public androidx.camera.core.ImageInfo getImageInfo();
+ method public androidx.camera.core.ImageProxy.PlaneProxy![] getPlanes();
+ method public int getWidth();
+ method public void setCropRect(android.graphics.Rect?);
+ }
+
+ public static interface ImageProxy.PlaneProxy {
+ method public java.nio.ByteBuffer getBuffer();
+ method public int getPixelStride();
+ method public int getRowStride();
+ }
+
+ public class MeteringPoint {
+ method public float getSize();
+ }
+
+ public abstract class MeteringPointFactory {
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float);
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float, float);
+ method public static float getDefaultPointSize();
+ }
+
+ public class Preview extends androidx.camera.core.UseCase {
+ method @UiThread public androidx.camera.core.Preview.PreviewSurfaceProvider? getPreviewSurfaceProvider();
+ method @UiThread public void setPreviewSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.PreviewSurfaceProvider?);
+ method @UiThread public void setPreviewSurfaceProvider(androidx.camera.core.Preview.PreviewSurfaceProvider?);
+ }
+
+ public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
+ ctor public Preview.Builder();
+ method public androidx.camera.core.Preview build();
+ method public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.Preview.Builder setTargetName(String);
+ method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.Preview.Builder setTargetRotation(int);
+ }
+
+ public static interface Preview.PreviewSurfaceProvider {
+ method public com.google.common.util.concurrent.ListenableFuture<android.view.Surface!> provideSurface(android.util.Size, com.google.common.util.concurrent.ListenableFuture<java.lang.Void!>);
+ }
+
+ public class SurfaceOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public SurfaceOrientedMeteringPointFactory(float, float);
+ ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
+ }
+
+ public class TorchState {
+ field public static final int OFF = 0; // 0x0
+ field public static final int ON = 1; // 0x1
+ }
+
+ public abstract class UseCase {
+ }
+
+}
+
diff --git a/camera/camera-core/api/public_plus_experimental_current.txt b/camera/camera-core/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..8b6aaf2
--- /dev/null
+++ b/camera/camera-core/api/public_plus_experimental_current.txt
@@ -0,0 +1,248 @@
+// Signature format: 3.0
+package androidx.camera.core {
+
+ public class AspectRatio {
+ field public static final int RATIO_16_9 = 1; // 0x1
+ field public static final int RATIO_4_3 = 0; // 0x0
+ }
+
+ public interface Camera {
+ method public androidx.camera.core.CameraControl getCameraControl();
+ method public androidx.camera.core.CameraInfo getCameraInfo();
+ }
+
+ public interface CameraControl {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelFocusAndMetering();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
+ }
+
+ public static final class CameraControl.OperationCanceledException extends java.lang.Exception {
+ }
+
+ public interface CameraInfo {
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getLinearZoom();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getMaxZoomRatio();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getMinZoomRatio();
+ method public int getSensorRotationDegrees();
+ method public int getSensorRotationDegrees(int);
+ method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getZoomRatio();
+ method public boolean hasFlashUnit();
+ }
+
+ public final class CameraInfoUnavailableException extends java.lang.Exception {
+ }
+
+ public final class CameraSelector {
+ field public static final androidx.camera.core.CameraSelector DEFAULT_BACK_CAMERA;
+ field public static final androidx.camera.core.CameraSelector DEFAULT_FRONT_CAMERA;
+ field public static final int LENS_FACING_BACK = 1; // 0x1
+ field public static final int LENS_FACING_FRONT = 0; // 0x0
+ }
+
+ public static final class CameraSelector.Builder {
+ ctor public CameraSelector.Builder();
+ method public androidx.camera.core.CameraSelector build();
+ method public androidx.camera.core.CameraSelector.Builder requireLensFacing(int);
+ }
+
+ public final class CameraXConfig {
+ field public static final androidx.camera.core.impl.Config.Option<java.lang.Class<?>!> OPTION_TARGET_CLASS;
+ field public static final androidx.camera.core.impl.Config.Option<java.lang.String!> OPTION_TARGET_NAME;
+ }
+
+ public static final class CameraXConfig.Builder {
+ ctor public CameraXConfig.Builder();
+ method public androidx.camera.core.CameraXConfig build();
+ method public static androidx.camera.core.CameraXConfig.Builder fromConfig(androidx.camera.core.CameraXConfig);
+ method public androidx.camera.core.CameraXConfig.Builder setCameraExecutor(java.util.concurrent.Executor);
+ }
+
+ public static interface CameraXConfig.Provider {
+ method public androidx.camera.core.CameraXConfig getCameraXConfig();
+ }
+
+ public final class DisplayOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public DisplayOrientedMeteringPointFactory(android.content.Context, androidx.camera.core.CameraSelector, float, float);
+ ctor public DisplayOrientedMeteringPointFactory(android.view.Display, androidx.camera.core.CameraSelector, float, float);
+ }
+
+ @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalGetImage {
+ }
+
+ public interface ExtendableBuilder<T> {
+ method public T build();
+ }
+
+ public final class FocusMeteringAction {
+ method public long getAutoCancelDurationInMillis();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAe();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAf();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAwb();
+ method public boolean isAutoCancelEnabled();
+ field public static final int FLAG_AE = 2; // 0x2
+ field public static final int FLAG_AF = 1; // 0x1
+ field public static final int FLAG_AWB = 4; // 0x4
+ }
+
+ public static class FocusMeteringAction.Builder {
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction build();
+ method public androidx.camera.core.FocusMeteringAction.Builder disableAutoCancel();
+ method public static androidx.camera.core.FocusMeteringAction.Builder from(androidx.camera.core.MeteringPoint);
+ method public static androidx.camera.core.FocusMeteringAction.Builder from(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction.Builder setAutoCancelDuration(@IntRange(from=1) long, java.util.concurrent.TimeUnit);
+ }
+
+ public final class FocusMeteringResult {
+ method public boolean isFocusSuccessful();
+ }
+
+ public final class ImageAnalysis extends androidx.camera.core.UseCase {
+ method public void clearAnalyzer();
+ method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+ method public void setTargetRotation(int);
+ field public static final int STRATEGY_BLOCK_PRODUCER = 1; // 0x1
+ field public static final int STRATEGY_KEEP_ONLY_LATEST = 0; // 0x0
+ }
+
+ public static interface ImageAnalysis.Analyzer {
+ method public void analyze(androidx.camera.core.ImageProxy);
+ }
+
+ public static final class ImageAnalysis.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageAnalysis> {
+ ctor public ImageAnalysis.Builder();
+ method public androidx.camera.core.ImageAnalysis build();
+ method public androidx.camera.core.ImageAnalysis.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageAnalysis.Builder setBackpressureStrategy(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
+ }
+
+ public class ImageCapture extends androidx.camera.core.UseCase {
+ method public int getFlashMode();
+ method public void setFlashMode(int);
+ method public void setTargetAspectRatioCustom(android.util.Rational);
+ method public void setTargetRotation(int);
+ method public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+ method public void takePicture(java.io.File, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ method public void takePicture(java.io.File, androidx.camera.core.ImageCapture.Metadata, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ field public static final int CAPTURE_MODE_MAXIMIZE_QUALITY = 0; // 0x0
+ field public static final int CAPTURE_MODE_MINIMIZE_LATENCY = 1; // 0x1
+ field public static final int ERROR_CAMERA_CLOSED = 3; // 0x3
+ field public static final int ERROR_CAPTURE_FAILED = 2; // 0x2
+ field public static final int ERROR_FILE_IO = 1; // 0x1
+ field public static final int ERROR_INVALID_CAMERA = 4; // 0x4
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int FLASH_MODE_AUTO = 0; // 0x0
+ field public static final int FLASH_MODE_OFF = 2; // 0x2
+ field public static final int FLASH_MODE_ON = 1; // 0x1
+ }
+
+ public static final class ImageCapture.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageCapture> {
+ ctor public ImageCapture.Builder();
+ method public androidx.camera.core.ImageCapture build();
+ method public androidx.camera.core.ImageCapture.Builder setCaptureMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
+ method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
+ }
+
+ public static final class ImageCapture.Metadata {
+ ctor public ImageCapture.Metadata();
+ method public android.location.Location? getLocation();
+ method public boolean isReversedHorizontal();
+ method public boolean isReversedVertical();
+ method public void setLocation(android.location.Location?);
+ method public void setReversedHorizontal(boolean);
+ method public void setReversedVertical(boolean);
+ }
+
+ public abstract static class ImageCapture.OnImageCapturedCallback {
+ ctor public ImageCapture.OnImageCapturedCallback();
+ method public void onCaptureSuccess(androidx.camera.core.ImageProxy);
+ method public void onError(int, String, Throwable?);
+ }
+
+ public static interface ImageCapture.OnImageSavedCallback {
+ method public void onError(int, String, Throwable?);
+ method public void onImageSaved(java.io.File);
+ }
+
+ public interface ImageInfo {
+ method public int getRotationDegrees();
+ method public long getTimestamp();
+ }
+
+ public interface ImageProxy extends java.lang.AutoCloseable {
+ method public void close();
+ method public android.graphics.Rect getCropRect();
+ method public int getFormat();
+ method public int getHeight();
+ method @androidx.camera.core.ExperimentalGetImage public android.media.Image? getImage();
+ method public androidx.camera.core.ImageInfo getImageInfo();
+ method public androidx.camera.core.ImageProxy.PlaneProxy![] getPlanes();
+ method public int getWidth();
+ method public void setCropRect(android.graphics.Rect?);
+ }
+
+ public static interface ImageProxy.PlaneProxy {
+ method public java.nio.ByteBuffer getBuffer();
+ method public int getPixelStride();
+ method public int getRowStride();
+ }
+
+ public class MeteringPoint {
+ method public float getSize();
+ }
+
+ public abstract class MeteringPointFactory {
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float);
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float, float);
+ method public static float getDefaultPointSize();
+ }
+
+ public class Preview extends androidx.camera.core.UseCase {
+ method @UiThread public androidx.camera.core.Preview.PreviewSurfaceProvider? getPreviewSurfaceProvider();
+ method @UiThread public void setPreviewSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.PreviewSurfaceProvider?);
+ method @UiThread public void setPreviewSurfaceProvider(androidx.camera.core.Preview.PreviewSurfaceProvider?);
+ }
+
+ public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
+ ctor public Preview.Builder();
+ method public androidx.camera.core.Preview build();
+ method public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.Preview.Builder setTargetName(String);
+ method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.Preview.Builder setTargetRotation(int);
+ }
+
+ public static interface Preview.PreviewSurfaceProvider {
+ method public com.google.common.util.concurrent.ListenableFuture<android.view.Surface!> provideSurface(android.util.Size, com.google.common.util.concurrent.ListenableFuture<java.lang.Void!>);
+ }
+
+ public class SurfaceOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public SurfaceOrientedMeteringPointFactory(float, float);
+ ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
+ }
+
+ public class TorchState {
+ field public static final int OFF = 0; // 0x0
+ field public static final int ON = 1; // 0x1
+ }
+
+ public abstract class UseCase {
+ }
+
+}
+
diff --git a/car-app/app/api/res-1.0.0-alpha01.txt b/camera/camera-core/api/res-1.0.0-alpha08.txt
similarity index 100%
copy from car-app/app/api/res-1.0.0-alpha01.txt
copy to camera/camera-core/api/res-1.0.0-alpha08.txt
diff --git a/camera/camera-core/api/restricted_1.0.0-alpha08.txt b/camera/camera-core/api/restricted_1.0.0-alpha08.txt
new file mode 100644
index 0000000..e2a4ce4
--- /dev/null
+++ b/camera/camera-core/api/restricted_1.0.0-alpha08.txt
@@ -0,0 +1,495 @@
+// Signature format: 3.0
+package androidx.camera.core {
+
+ public class AspectRatio {
+ field public static final int RATIO_16_9 = 1; // 0x1
+ field public static final int RATIO_4_3 = 0; // 0x0
+ }
+
+ @IntDef({androidx.camera.core.AspectRatio.RATIO_4_3, androidx.camera.core.AspectRatio.RATIO_16_9}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface AspectRatio.Ratio {
+ }
+
+ public interface Camera {
+ method public androidx.camera.core.CameraControl getCameraControl();
+ method public androidx.camera.core.CameraInfo getCameraInfo();
+ }
+
+ public interface CameraControl {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelFocusAndMetering();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
+ }
+
+ public static final class CameraControl.OperationCanceledException extends java.lang.Exception {
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public CameraControl.OperationCanceledException(String);
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public CameraControl.OperationCanceledException(String, Throwable);
+ }
+
+ public interface CameraInfo {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.camera.core.CameraInfo.ImplementationType public String getImplementationType();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getLinearZoom();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getMaxZoomRatio();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getMinZoomRatio();
+ method public int getSensorRotationDegrees();
+ method public int getSensorRotationDegrees(int);
+ method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getZoomRatio();
+ method public boolean hasFlashUnit();
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String IMPLEMENTATION_TYPE_CAMERA2 = "androidx.camera.camera2";
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String IMPLEMENTATION_TYPE_CAMERA2_LEGACY = "androidx.camera.camera2.legacy";
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String IMPLEMENTATION_TYPE_FAKE = "androidx.camera.fake";
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String IMPLEMENTATION_TYPE_UNKNOWN = "<unknown>";
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @StringDef(open=true, value={androidx.camera.core.CameraInfo.IMPLEMENTATION_TYPE_UNKNOWN, androidx.camera.core.CameraInfo.IMPLEMENTATION_TYPE_CAMERA2_LEGACY, androidx.camera.core.CameraInfo.IMPLEMENTATION_TYPE_CAMERA2, androidx.camera.core.CameraInfo.IMPLEMENTATION_TYPE_FAKE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CameraInfo.ImplementationType {
+ }
+
+ public final class CameraInfoUnavailableException extends java.lang.Exception {
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public CameraInfoUnavailableException(String!, Throwable!);
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public CameraInfoUnavailableException(String!);
+ }
+
+ public final class CameraSelector {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public java.util.LinkedHashSet<androidx.camera.core.impl.CameraIdFilter!> getCameraFilterSet();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public Integer? getLensFacing();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public String select(java.util.Set<java.lang.String!>);
+ field public static final androidx.camera.core.CameraSelector DEFAULT_BACK_CAMERA;
+ field public static final androidx.camera.core.CameraSelector DEFAULT_FRONT_CAMERA;
+ field public static final int LENS_FACING_BACK = 1; // 0x1
+ field public static final int LENS_FACING_FRONT = 0; // 0x0
+ }
+
+ public static final class CameraSelector.Builder {
+ ctor public CameraSelector.Builder();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.CameraSelector.Builder appendFilter(androidx.camera.core.impl.CameraIdFilter);
+ method public androidx.camera.core.CameraSelector build();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.CameraSelector.Builder fromSelector(androidx.camera.core.CameraSelector);
+ method public androidx.camera.core.CameraSelector.Builder requireLensFacing(@androidx.camera.core.CameraSelector.LensFacing int);
+ }
+
+ @IntDef({androidx.camera.core.CameraSelector.LENS_FACING_FRONT, androidx.camera.core.CameraSelector.LENS_FACING_BACK}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CameraSelector.LensFacing {
+ }
+
+ @MainThread @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class CameraX {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static java.util.Collection<androidx.camera.core.UseCase!>? getActiveUseCases();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.impl.CameraFactory getCameraFactory();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.impl.CameraInfoInternal getCameraInfo(String!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static String? getCameraWithCameraSelector(androidx.camera.core.CameraSelector);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static String? getCameraWithLensFacing(@androidx.camera.core.CameraSelector.LensFacing int) throws androidx.camera.core.CameraInfoUnavailableException;
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static android.content.Context getContext();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.camera.core.CameraSelector.LensFacing public static int getDefaultLensFacing() throws androidx.camera.core.CameraInfoUnavailableException;
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static <C extends androidx.camera.core.impl.UseCaseConfig<?>> C? getDefaultUseCaseConfig(Class<C!>!, androidx.camera.core.CameraInfo?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.CameraX!> getOrCreateInstance(android.content.Context);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.impl.CameraDeviceSurfaceManager getSurfaceManager();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public static com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> initialize(android.content.Context, androidx.camera.core.CameraXConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static boolean isBound(androidx.camera.core.UseCase);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static boolean isInitialized();
+ method public static com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> shutdown();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static void unbind(androidx.camera.core.UseCase!...);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static void unbindAll();
+ }
+
+ public final class CameraXConfig implements androidx.camera.core.impl.Config {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public boolean containsOption(androidx.camera.core.impl.Config.Option<?>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void findOptions(String, androidx.camera.core.impl.Config.OptionMatcher);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public java.util.concurrent.Executor? getCameraExecutor(java.util.concurrent.Executor?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.CameraFactory.Provider? getCameraFactoryProvider(androidx.camera.core.impl.CameraFactory.Provider?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.CameraDeviceSurfaceManager.Provider? getDeviceSurfaceManagerProvider(androidx.camera.core.impl.CameraDeviceSurfaceManager.Provider?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public Class<androidx.camera.core.CameraX!>? getTargetClass(Class<androidx.camera.core.CameraX!>?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public Class<androidx.camera.core.CameraX!> getTargetClass();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public String? getTargetName(String?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public String getTargetName();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.UseCaseConfigFactory.Provider? getUseCaseConfigFactoryProvider(androidx.camera.core.impl.UseCaseConfigFactory.Provider?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public java.util.Set<androidx.camera.core.impl.Config.Option<?>!> listOptions();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public <ValueT> ValueT? retrieveOption(androidx.camera.core.impl.Config.Option<ValueT!>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public <ValueT> ValueT? retrieveOption(androidx.camera.core.impl.Config.Option<ValueT!>, ValueT?);
+ field public static final androidx.camera.core.impl.Config.Option<java.lang.Class<?>!> OPTION_TARGET_CLASS;
+ field public static final androidx.camera.core.impl.Config.Option<java.lang.String!> OPTION_TARGET_NAME;
+ }
+
+ public static final class CameraXConfig.Builder {
+ ctor public CameraXConfig.Builder();
+ method public androidx.camera.core.CameraXConfig build();
+ method public static androidx.camera.core.CameraXConfig.Builder fromConfig(androidx.camera.core.CameraXConfig);
+ method public androidx.camera.core.CameraXConfig.Builder setCameraExecutor(java.util.concurrent.Executor);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.CameraXConfig.Builder setCameraFactoryProvider(androidx.camera.core.impl.CameraFactory.Provider);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.CameraXConfig.Builder setDeviceSurfaceManagerProvider(androidx.camera.core.impl.CameraDeviceSurfaceManager.Provider);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.CameraXConfig.Builder setTargetClass(Class<androidx.camera.core.CameraX!>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.CameraXConfig.Builder setTargetName(String);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.CameraXConfig.Builder setUseCaseConfigFactoryProvider(androidx.camera.core.impl.UseCaseConfigFactory.Provider);
+ }
+
+ public static interface CameraXConfig.Provider {
+ method public androidx.camera.core.CameraXConfig getCameraXConfig();
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class CameraXThreads {
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String TAG = "CameraX-";
+ }
+
+ public final class DisplayOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public DisplayOrientedMeteringPointFactory(android.content.Context, androidx.camera.core.CameraSelector, float, float);
+ ctor public DisplayOrientedMeteringPointFactory(android.view.Display, androidx.camera.core.CameraSelector, float, float);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected android.graphics.PointF convertPoint(float, float);
+ }
+
+ public interface ExtendableBuilder<T> {
+ method public T build();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.MutableConfig getMutableConfig();
+ }
+
+ public final class FocusMeteringAction {
+ method public long getAutoCancelDurationInMillis();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAe();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAf();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAwb();
+ method public boolean isAutoCancelEnabled();
+ field public static final int FLAG_AE = 2; // 0x2
+ field public static final int FLAG_AF = 1; // 0x1
+ field public static final int FLAG_AWB = 4; // 0x4
+ }
+
+ public static class FocusMeteringAction.Builder {
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint, @androidx.camera.core.FocusMeteringAction.MeteringMode int);
+ method public androidx.camera.core.FocusMeteringAction build();
+ method public androidx.camera.core.FocusMeteringAction.Builder disableAutoCancel();
+ method public static androidx.camera.core.FocusMeteringAction.Builder from(androidx.camera.core.MeteringPoint);
+ method public static androidx.camera.core.FocusMeteringAction.Builder from(androidx.camera.core.MeteringPoint, @androidx.camera.core.FocusMeteringAction.MeteringMode int);
+ method public androidx.camera.core.FocusMeteringAction.Builder setAutoCancelDuration(@IntRange(from=1) long, java.util.concurrent.TimeUnit);
+ }
+
+ @IntDef(flag=true, value={androidx.camera.core.FocusMeteringAction.FLAG_AF, androidx.camera.core.FocusMeteringAction.FLAG_AE, androidx.camera.core.FocusMeteringAction.FLAG_AWB}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface FocusMeteringAction.MeteringMode {
+ }
+
+ public final class FocusMeteringResult {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.FocusMeteringResult create(boolean);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.FocusMeteringResult emptyInstance();
+ method public boolean isFocusSuccessful();
+ }
+
+ public final class ImageAnalysis extends androidx.camera.core.UseCase {
+ method public void clearAnalyzer();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected java.util.Map<java.lang.String!,android.util.Size!> onSuggestedResolutionUpdated(java.util.Map<java.lang.String!,android.util.Size!>);
+ method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+ method public void setTargetRotation(int);
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final androidx.camera.core.ImageAnalysis.Defaults! DEFAULT_CONFIG;
+ field public static final int STRATEGY_BLOCK_PRODUCER = 1; // 0x1
+ field public static final int STRATEGY_KEEP_ONLY_LATEST = 0; // 0x0
+ }
+
+ public static interface ImageAnalysis.Analyzer {
+ method public void analyze(androidx.camera.core.ImageProxy);
+ }
+
+ @IntDef({androidx.camera.core.ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST, androidx.camera.core.ImageAnalysis.STRATEGY_BLOCK_PRODUCER}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ImageAnalysis.BackpressureStrategy {
+ }
+
+ public static final class ImageAnalysis.Builder implements androidx.camera.core.impl.UseCaseConfig.Builder<androidx.camera.core.ImageAnalysis,androidx.camera.core.impl.ImageAnalysisConfig,androidx.camera.core.ImageAnalysis.Builder> {
+ ctor public ImageAnalysis.Builder();
+ method public androidx.camera.core.ImageAnalysis build();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.ImageAnalysis.Builder fromConfig(androidx.camera.core.impl.ImageAnalysisConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.MutableConfig getMutableConfig();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.ImageAnalysisConfig getUseCaseConfig();
+ method public androidx.camera.core.ImageAnalysis.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageAnalysis.Builder setBackpressureStrategy(@androidx.camera.core.ImageAnalysis.BackpressureStrategy int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setCaptureOptionUnpacker(androidx.camera.core.impl.CaptureConfig.OptionUnpacker);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setDefaultCaptureConfig(androidx.camera.core.impl.CaptureConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setDefaultResolution(android.util.Size);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setDefaultSessionConfig(androidx.camera.core.impl.SessionConfig);
+ method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setMaxResolution(android.util.Size);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setSessionOptionUnpacker(androidx.camera.core.impl.SessionConfig.OptionUnpacker);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setSupportedResolutions(java.util.List<android.util.Pair<java.lang.Integer!,android.util.Size![]!>!>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setSurfaceOccupancyPriority(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(@androidx.camera.core.AspectRatio.Ratio int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatioCustom(android.util.Rational);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setTargetClass(Class<androidx.camera.core.ImageAnalysis!>);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setUseCaseEventCallback(androidx.camera.core.UseCase.EventCallback);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final class ImageAnalysis.Defaults {
+ ctor public ImageAnalysis.Defaults();
+ method public androidx.camera.core.impl.ImageAnalysisConfig getConfig(androidx.camera.core.CameraInfo?);
+ }
+
+ public class ImageCapture extends androidx.camera.core.UseCase {
+ method @androidx.camera.core.ImageCapture.FlashMode public int getFlashMode();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected java.util.Map<java.lang.String!,android.util.Size!> onSuggestedResolutionUpdated(java.util.Map<java.lang.String!,android.util.Size!>);
+ method public void setFlashMode(@androidx.camera.core.ImageCapture.FlashMode int);
+ method public void setTargetAspectRatioCustom(android.util.Rational);
+ method public void setTargetRotation(int);
+ method public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+ method public void takePicture(java.io.File, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ method public void takePicture(java.io.File, androidx.camera.core.ImageCapture.Metadata, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ field public static final int CAPTURE_MODE_MAXIMIZE_QUALITY = 0; // 0x0
+ field public static final int CAPTURE_MODE_MINIMIZE_LATENCY = 1; // 0x1
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final androidx.camera.core.ImageCapture.Defaults! DEFAULT_CONFIG;
+ field public static final int ERROR_CAMERA_CLOSED = 3; // 0x3
+ field public static final int ERROR_CAPTURE_FAILED = 2; // 0x2
+ field public static final int ERROR_FILE_IO = 1; // 0x1
+ field public static final int ERROR_INVALID_CAMERA = 4; // 0x4
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int FLASH_MODE_AUTO = 0; // 0x0
+ field public static final int FLASH_MODE_OFF = 2; // 0x2
+ field public static final int FLASH_MODE_ON = 1; // 0x1
+ }
+
+ public static final class ImageCapture.Builder implements androidx.camera.core.impl.UseCaseConfig.Builder<androidx.camera.core.ImageCapture,androidx.camera.core.impl.ImageCaptureConfig,androidx.camera.core.ImageCapture.Builder> {
+ ctor public ImageCapture.Builder();
+ method public androidx.camera.core.ImageCapture build();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.ImageCapture.Builder fromConfig(androidx.camera.core.impl.ImageCaptureConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.MutableConfig getMutableConfig();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.ImageCaptureConfig getUseCaseConfig();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setBufferFormat(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setCameraSelector(androidx.camera.core.CameraSelector);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setCaptureBundle(androidx.camera.core.impl.CaptureBundle);
+ method public androidx.camera.core.ImageCapture.Builder setCaptureMode(@androidx.camera.core.ImageCapture.CaptureMode int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setCaptureOptionUnpacker(androidx.camera.core.impl.CaptureConfig.OptionUnpacker);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setCaptureProcessor(androidx.camera.core.impl.CaptureProcessor);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setDefaultCaptureConfig(androidx.camera.core.impl.CaptureConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setDefaultResolution(android.util.Size);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setDefaultSessionConfig(androidx.camera.core.impl.SessionConfig);
+ method public androidx.camera.core.ImageCapture.Builder setFlashMode(@androidx.camera.core.ImageCapture.FlashMode int);
+ method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setMaxCaptureStages(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setMaxResolution(android.util.Size);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setSessionOptionUnpacker(androidx.camera.core.impl.SessionConfig.OptionUnpacker);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setSupportedResolutions(java.util.List<android.util.Pair<java.lang.Integer!,android.util.Size![]!>!>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setSurfaceOccupancyPriority(int);
+ method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(@androidx.camera.core.AspectRatio.Ratio int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setTargetAspectRatioCustom(android.util.Rational);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setTargetClass(Class<androidx.camera.core.ImageCapture!>);
+ method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
+ method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setUseCaseEventCallback(androidx.camera.core.UseCase.EventCallback);
+ }
+
+ @IntDef({androidx.camera.core.ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY, androidx.camera.core.ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ImageCapture.CaptureMode {
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final class ImageCapture.Defaults {
+ ctor public ImageCapture.Defaults();
+ method public androidx.camera.core.impl.ImageCaptureConfig getConfig(androidx.camera.core.CameraInfo?);
+ }
+
+ @IntDef({androidx.camera.core.ImageCapture.FLASH_MODE_AUTO, androidx.camera.core.ImageCapture.FLASH_MODE_ON, androidx.camera.core.ImageCapture.FLASH_MODE_OFF}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ImageCapture.FlashMode {
+ }
+
+ @IntDef({androidx.camera.core.ImageCapture.ERROR_UNKNOWN, androidx.camera.core.ImageCapture.ERROR_FILE_IO, androidx.camera.core.ImageCapture.ERROR_CAPTURE_FAILED, androidx.camera.core.ImageCapture.ERROR_CAMERA_CLOSED, androidx.camera.core.ImageCapture.ERROR_INVALID_CAMERA}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ImageCapture.ImageCaptureError {
+ }
+
+ public static final class ImageCapture.Metadata {
+ ctor public ImageCapture.Metadata();
+ method public android.location.Location? getLocation();
+ method public boolean isReversedHorizontal();
+ method public boolean isReversedVertical();
+ method public void setLocation(android.location.Location?);
+ method public void setReversedHorizontal(boolean);
+ method public void setReversedVertical(boolean);
+ }
+
+ public abstract static class ImageCapture.OnImageCapturedCallback {
+ ctor public ImageCapture.OnImageCapturedCallback();
+ method public void onCaptureSuccess(androidx.camera.core.ImageProxy);
+ method public void onError(@androidx.camera.core.ImageCapture.ImageCaptureError int, String, Throwable?);
+ }
+
+ public static interface ImageCapture.OnImageSavedCallback {
+ method public void onError(@androidx.camera.core.ImageCapture.ImageCaptureError int, String, Throwable?);
+ method public void onImageSaved(java.io.File);
+ }
+
+ public interface ImageInfo {
+ method public int getRotationDegrees();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public Object? getTag();
+ method public long getTimestamp();
+ }
+
+ public interface ImageProxy extends java.lang.AutoCloseable {
+ method public void close();
+ method public android.graphics.Rect getCropRect();
+ method public int getFormat();
+ method public int getHeight();
+ method public androidx.camera.core.ImageInfo getImageInfo();
+ method public androidx.camera.core.ImageProxy.PlaneProxy![] getPlanes();
+ method public int getWidth();
+ method public void setCropRect(android.graphics.Rect?);
+ }
+
+ public static interface ImageProxy.PlaneProxy {
+ method public java.nio.ByteBuffer getBuffer();
+ method public int getPixelStride();
+ method public int getRowStride();
+ }
+
+ public class MeteringPoint {
+ method public float getSize();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public android.util.Rational? getSurfaceAspectRatio();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public float getX();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public float getY();
+ }
+
+ public abstract class MeteringPointFactory {
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public MeteringPointFactory();
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public MeteringPointFactory(android.util.Rational?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected abstract android.graphics.PointF convertPoint(float, float);
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float);
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float, float);
+ method public static float getDefaultPointSize();
+ }
+
+ public class Preview extends androidx.camera.core.UseCase {
+ method @UiThread public androidx.camera.core.Preview.PreviewSurfaceProvider? getPreviewSurfaceProvider();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected java.util.Map<java.lang.String!,android.util.Size!> onSuggestedResolutionUpdated(java.util.Map<java.lang.String!,android.util.Size!>);
+ method @UiThread public void setPreviewSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.PreviewSurfaceProvider?);
+ method @UiThread public void setPreviewSurfaceProvider(androidx.camera.core.Preview.PreviewSurfaceProvider?);
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final androidx.camera.core.Preview.Defaults! DEFAULT_CONFIG;
+ }
+
+ public static final class Preview.Builder implements androidx.camera.core.impl.UseCaseConfig.Builder<androidx.camera.core.Preview,androidx.camera.core.impl.PreviewConfig,androidx.camera.core.Preview.Builder> {
+ ctor public Preview.Builder();
+ method public androidx.camera.core.Preview build();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.Preview.Builder fromConfig(androidx.camera.core.impl.PreviewConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.MutableConfig getMutableConfig();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.PreviewConfig getUseCaseConfig();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setCameraSelector(androidx.camera.core.CameraSelector);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setCaptureOptionUnpacker(androidx.camera.core.impl.CaptureConfig.OptionUnpacker);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setCaptureProcessor(androidx.camera.core.impl.CaptureProcessor);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setDefaultCaptureConfig(androidx.camera.core.impl.CaptureConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setDefaultResolution(android.util.Size);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setDefaultSessionConfig(androidx.camera.core.impl.SessionConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setImageInfoProcessor(androidx.camera.core.impl.ImageInfoProcessor);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setMaxResolution(android.util.Size);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setSessionOptionUnpacker(androidx.camera.core.impl.SessionConfig.OptionUnpacker);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setSupportedResolutions(java.util.List<android.util.Pair<java.lang.Integer!,android.util.Size![]!>!>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setSurfaceOccupancyPriority(int);
+ method public androidx.camera.core.Preview.Builder setTargetAspectRatio(@androidx.camera.core.AspectRatio.Ratio int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setTargetAspectRatioCustom(android.util.Rational);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setTargetClass(Class<androidx.camera.core.Preview!>);
+ method public androidx.camera.core.Preview.Builder setTargetName(String);
+ method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.Preview.Builder setTargetRotation(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setUseCaseEventCallback(androidx.camera.core.UseCase.EventCallback);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final class Preview.Defaults {
+ ctor public Preview.Defaults();
+ method public androidx.camera.core.impl.PreviewConfig getConfig(androidx.camera.core.CameraInfo?);
+ }
+
+ public static interface Preview.PreviewSurfaceProvider {
+ method public com.google.common.util.concurrent.ListenableFuture<android.view.Surface!> provideSurface(android.util.Size, com.google.common.util.concurrent.ListenableFuture<java.lang.Void!>);
+ }
+
+ public class SurfaceOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public SurfaceOrientedMeteringPointFactory(float, float);
+ ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected android.graphics.PointF convertPoint(float, float);
+ }
+
+ public class TorchState {
+ field public static final int OFF = 0; // 0x0
+ field public static final int ON = 1; // 0x1
+ }
+
+ @IntDef({androidx.camera.core.TorchState.OFF, androidx.camera.core.TorchState.ON}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface TorchState.State {
+ }
+
+ public abstract class UseCase {
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected UseCase(androidx.camera.core.impl.UseCaseConfig<?>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void addStateChangeCallback(androidx.camera.core.UseCase.StateChangeCallback);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected androidx.camera.core.impl.UseCaseConfig<?> applyDefaults(androidx.camera.core.impl.UseCaseConfig<?>, androidx.camera.core.impl.UseCaseConfig.Builder<?,?,?>?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final void attachCameraControl(String!, androidx.camera.core.impl.CameraControlInternal!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected void attachToCamera(String!, androidx.camera.core.impl.SessionConfig!);
+ method @CallSuper @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void clear();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public java.util.Set<java.lang.String!>! getAttachedCameraIds();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public android.util.Size! getAttachedSurfaceResolution(String!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.CameraInternal? getBoundCamera();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected String getBoundCameraId();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected androidx.camera.core.impl.CameraControlInternal! getCameraControl(String!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected androidx.camera.core.impl.UseCaseConfig.Builder<?,?,?>? getDefaultBuilder(androidx.camera.core.CameraInfo?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public int getImageFormat();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public String getName();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.SessionConfig! getSessionConfig(String!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.UseCaseConfig<?>! getUseCaseConfig();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected boolean isCurrentlyBoundCamera(String);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected final void notifyActive();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected final void notifyInactive();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected final void notifyReset();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected final void notifyState();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected final void notifyUpdated();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected void onBind(androidx.camera.core.impl.CameraInternal);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected void onCameraControlReady(String!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void onStateOffline(String);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void onStateOnline(String);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected abstract java.util.Map<java.lang.String!,android.util.Size!> onSuggestedResolutionUpdated(java.util.Map<java.lang.String!,android.util.Size!>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void removeStateChangeCallback(androidx.camera.core.UseCase.StateChangeCallback);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected void setImageFormat(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void updateSuggestedResolution(java.util.Map<java.lang.String!,android.util.Size!>!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected final void updateUseCaseConfig(androidx.camera.core.impl.UseCaseConfig<?>);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static interface UseCase.EventCallback {
+ method public void onBind(String);
+ method public void onUnbind();
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static interface UseCase.StateChangeCallback {
+ method public void onUseCaseActive(androidx.camera.core.UseCase);
+ method public void onUseCaseInactive(androidx.camera.core.UseCase);
+ method public void onUseCaseReset(androidx.camera.core.UseCase);
+ method public void onUseCaseUpdated(androidx.camera.core.UseCase);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public class VideoCapture extends androidx.camera.core.UseCase {
+ ctor public VideoCapture(androidx.camera.core.impl.VideoCaptureConfig!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected java.util.Map<java.lang.String!,android.util.Size!> onSuggestedResolutionUpdated(java.util.Map<java.lang.String!,android.util.Size!>);
+ method public void setTargetRotation(int);
+ method public void startRecording(java.io.File, java.util.concurrent.Executor, androidx.camera.core.VideoCapture.OnVideoSavedCallback);
+ method public void startRecording(java.io.File, androidx.camera.core.VideoCapture.Metadata, java.util.concurrent.Executor, androidx.camera.core.VideoCapture.OnVideoSavedCallback);
+ method public void stopRecording();
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final androidx.camera.core.VideoCapture.Defaults! DEFAULT_CONFIG;
+ field public static final int ERROR_ENCODER = 1; // 0x1
+ field public static final int ERROR_MUXER = 2; // 0x2
+ field public static final int ERROR_RECORDING_IN_PROGRESS = 3; // 0x3
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final class VideoCapture.Defaults {
+ ctor public VideoCapture.Defaults();
+ method public androidx.camera.core.impl.VideoCaptureConfig getConfig(androidx.camera.core.CameraInfo?);
+ }
+
+ public static final class VideoCapture.Metadata {
+ ctor public VideoCapture.Metadata();
+ field public android.location.Location? location;
+ }
+
+ public static interface VideoCapture.OnVideoSavedCallback {
+ method public void onError(@androidx.camera.core.VideoCapture.VideoCaptureError int, String, Throwable?);
+ method public void onVideoSaved(java.io.File);
+ }
+
+ @IntDef({androidx.camera.core.VideoCapture.ERROR_UNKNOWN, androidx.camera.core.VideoCapture.ERROR_ENCODER, androidx.camera.core.VideoCapture.ERROR_MUXER, androidx.camera.core.VideoCapture.ERROR_RECORDING_IN_PROGRESS}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface VideoCapture.VideoCaptureError {
+ }
+
+}
+
+package @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) androidx.camera.core.impl.annotation {
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface ExecutedBy {
+ method public abstract String value();
+ }
+
+}
+
diff --git a/camera/camera-core/api/restricted_current.txt b/camera/camera-core/api/restricted_current.txt
new file mode 100644
index 0000000..e2a4ce4
--- /dev/null
+++ b/camera/camera-core/api/restricted_current.txt
@@ -0,0 +1,495 @@
+// Signature format: 3.0
+package androidx.camera.core {
+
+ public class AspectRatio {
+ field public static final int RATIO_16_9 = 1; // 0x1
+ field public static final int RATIO_4_3 = 0; // 0x0
+ }
+
+ @IntDef({androidx.camera.core.AspectRatio.RATIO_4_3, androidx.camera.core.AspectRatio.RATIO_16_9}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface AspectRatio.Ratio {
+ }
+
+ public interface Camera {
+ method public androidx.camera.core.CameraControl getCameraControl();
+ method public androidx.camera.core.CameraInfo getCameraInfo();
+ }
+
+ public interface CameraControl {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelFocusAndMetering();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
+ }
+
+ public static final class CameraControl.OperationCanceledException extends java.lang.Exception {
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public CameraControl.OperationCanceledException(String);
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public CameraControl.OperationCanceledException(String, Throwable);
+ }
+
+ public interface CameraInfo {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.camera.core.CameraInfo.ImplementationType public String getImplementationType();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getLinearZoom();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getMaxZoomRatio();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getMinZoomRatio();
+ method public int getSensorRotationDegrees();
+ method public int getSensorRotationDegrees(int);
+ method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+ method public androidx.lifecycle.LiveData<java.lang.Float!> getZoomRatio();
+ method public boolean hasFlashUnit();
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String IMPLEMENTATION_TYPE_CAMERA2 = "androidx.camera.camera2";
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String IMPLEMENTATION_TYPE_CAMERA2_LEGACY = "androidx.camera.camera2.legacy";
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String IMPLEMENTATION_TYPE_FAKE = "androidx.camera.fake";
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String IMPLEMENTATION_TYPE_UNKNOWN = "<unknown>";
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @StringDef(open=true, value={androidx.camera.core.CameraInfo.IMPLEMENTATION_TYPE_UNKNOWN, androidx.camera.core.CameraInfo.IMPLEMENTATION_TYPE_CAMERA2_LEGACY, androidx.camera.core.CameraInfo.IMPLEMENTATION_TYPE_CAMERA2, androidx.camera.core.CameraInfo.IMPLEMENTATION_TYPE_FAKE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CameraInfo.ImplementationType {
+ }
+
+ public final class CameraInfoUnavailableException extends java.lang.Exception {
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public CameraInfoUnavailableException(String!, Throwable!);
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public CameraInfoUnavailableException(String!);
+ }
+
+ public final class CameraSelector {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public java.util.LinkedHashSet<androidx.camera.core.impl.CameraIdFilter!> getCameraFilterSet();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public Integer? getLensFacing();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public String select(java.util.Set<java.lang.String!>);
+ field public static final androidx.camera.core.CameraSelector DEFAULT_BACK_CAMERA;
+ field public static final androidx.camera.core.CameraSelector DEFAULT_FRONT_CAMERA;
+ field public static final int LENS_FACING_BACK = 1; // 0x1
+ field public static final int LENS_FACING_FRONT = 0; // 0x0
+ }
+
+ public static final class CameraSelector.Builder {
+ ctor public CameraSelector.Builder();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.CameraSelector.Builder appendFilter(androidx.camera.core.impl.CameraIdFilter);
+ method public androidx.camera.core.CameraSelector build();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.CameraSelector.Builder fromSelector(androidx.camera.core.CameraSelector);
+ method public androidx.camera.core.CameraSelector.Builder requireLensFacing(@androidx.camera.core.CameraSelector.LensFacing int);
+ }
+
+ @IntDef({androidx.camera.core.CameraSelector.LENS_FACING_FRONT, androidx.camera.core.CameraSelector.LENS_FACING_BACK}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CameraSelector.LensFacing {
+ }
+
+ @MainThread @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class CameraX {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static java.util.Collection<androidx.camera.core.UseCase!>? getActiveUseCases();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.impl.CameraFactory getCameraFactory();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.impl.CameraInfoInternal getCameraInfo(String!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static String? getCameraWithCameraSelector(androidx.camera.core.CameraSelector);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static String? getCameraWithLensFacing(@androidx.camera.core.CameraSelector.LensFacing int) throws androidx.camera.core.CameraInfoUnavailableException;
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static android.content.Context getContext();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.camera.core.CameraSelector.LensFacing public static int getDefaultLensFacing() throws androidx.camera.core.CameraInfoUnavailableException;
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static <C extends androidx.camera.core.impl.UseCaseConfig<?>> C? getDefaultUseCaseConfig(Class<C!>!, androidx.camera.core.CameraInfo?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.CameraX!> getOrCreateInstance(android.content.Context);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.impl.CameraDeviceSurfaceManager getSurfaceManager();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public static com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> initialize(android.content.Context, androidx.camera.core.CameraXConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static boolean isBound(androidx.camera.core.UseCase);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static boolean isInitialized();
+ method public static com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> shutdown();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static void unbind(androidx.camera.core.UseCase!...);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static void unbindAll();
+ }
+
+ public final class CameraXConfig implements androidx.camera.core.impl.Config {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public boolean containsOption(androidx.camera.core.impl.Config.Option<?>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void findOptions(String, androidx.camera.core.impl.Config.OptionMatcher);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public java.util.concurrent.Executor? getCameraExecutor(java.util.concurrent.Executor?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.CameraFactory.Provider? getCameraFactoryProvider(androidx.camera.core.impl.CameraFactory.Provider?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.CameraDeviceSurfaceManager.Provider? getDeviceSurfaceManagerProvider(androidx.camera.core.impl.CameraDeviceSurfaceManager.Provider?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public Class<androidx.camera.core.CameraX!>? getTargetClass(Class<androidx.camera.core.CameraX!>?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public Class<androidx.camera.core.CameraX!> getTargetClass();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public String? getTargetName(String?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public String getTargetName();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.UseCaseConfigFactory.Provider? getUseCaseConfigFactoryProvider(androidx.camera.core.impl.UseCaseConfigFactory.Provider?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public java.util.Set<androidx.camera.core.impl.Config.Option<?>!> listOptions();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public <ValueT> ValueT? retrieveOption(androidx.camera.core.impl.Config.Option<ValueT!>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public <ValueT> ValueT? retrieveOption(androidx.camera.core.impl.Config.Option<ValueT!>, ValueT?);
+ field public static final androidx.camera.core.impl.Config.Option<java.lang.Class<?>!> OPTION_TARGET_CLASS;
+ field public static final androidx.camera.core.impl.Config.Option<java.lang.String!> OPTION_TARGET_NAME;
+ }
+
+ public static final class CameraXConfig.Builder {
+ ctor public CameraXConfig.Builder();
+ method public androidx.camera.core.CameraXConfig build();
+ method public static androidx.camera.core.CameraXConfig.Builder fromConfig(androidx.camera.core.CameraXConfig);
+ method public androidx.camera.core.CameraXConfig.Builder setCameraExecutor(java.util.concurrent.Executor);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.CameraXConfig.Builder setCameraFactoryProvider(androidx.camera.core.impl.CameraFactory.Provider);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.CameraXConfig.Builder setDeviceSurfaceManagerProvider(androidx.camera.core.impl.CameraDeviceSurfaceManager.Provider);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.CameraXConfig.Builder setTargetClass(Class<androidx.camera.core.CameraX!>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.CameraXConfig.Builder setTargetName(String);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.CameraXConfig.Builder setUseCaseConfigFactoryProvider(androidx.camera.core.impl.UseCaseConfigFactory.Provider);
+ }
+
+ public static interface CameraXConfig.Provider {
+ method public androidx.camera.core.CameraXConfig getCameraXConfig();
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class CameraXThreads {
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final String TAG = "CameraX-";
+ }
+
+ public final class DisplayOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public DisplayOrientedMeteringPointFactory(android.content.Context, androidx.camera.core.CameraSelector, float, float);
+ ctor public DisplayOrientedMeteringPointFactory(android.view.Display, androidx.camera.core.CameraSelector, float, float);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected android.graphics.PointF convertPoint(float, float);
+ }
+
+ public interface ExtendableBuilder<T> {
+ method public T build();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.MutableConfig getMutableConfig();
+ }
+
+ public final class FocusMeteringAction {
+ method public long getAutoCancelDurationInMillis();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAe();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAf();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAwb();
+ method public boolean isAutoCancelEnabled();
+ field public static final int FLAG_AE = 2; // 0x2
+ field public static final int FLAG_AF = 1; // 0x1
+ field public static final int FLAG_AWB = 4; // 0x4
+ }
+
+ public static class FocusMeteringAction.Builder {
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint, @androidx.camera.core.FocusMeteringAction.MeteringMode int);
+ method public androidx.camera.core.FocusMeteringAction build();
+ method public androidx.camera.core.FocusMeteringAction.Builder disableAutoCancel();
+ method public static androidx.camera.core.FocusMeteringAction.Builder from(androidx.camera.core.MeteringPoint);
+ method public static androidx.camera.core.FocusMeteringAction.Builder from(androidx.camera.core.MeteringPoint, @androidx.camera.core.FocusMeteringAction.MeteringMode int);
+ method public androidx.camera.core.FocusMeteringAction.Builder setAutoCancelDuration(@IntRange(from=1) long, java.util.concurrent.TimeUnit);
+ }
+
+ @IntDef(flag=true, value={androidx.camera.core.FocusMeteringAction.FLAG_AF, androidx.camera.core.FocusMeteringAction.FLAG_AE, androidx.camera.core.FocusMeteringAction.FLAG_AWB}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface FocusMeteringAction.MeteringMode {
+ }
+
+ public final class FocusMeteringResult {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.FocusMeteringResult create(boolean);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.FocusMeteringResult emptyInstance();
+ method public boolean isFocusSuccessful();
+ }
+
+ public final class ImageAnalysis extends androidx.camera.core.UseCase {
+ method public void clearAnalyzer();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected java.util.Map<java.lang.String!,android.util.Size!> onSuggestedResolutionUpdated(java.util.Map<java.lang.String!,android.util.Size!>);
+ method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+ method public void setTargetRotation(int);
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final androidx.camera.core.ImageAnalysis.Defaults! DEFAULT_CONFIG;
+ field public static final int STRATEGY_BLOCK_PRODUCER = 1; // 0x1
+ field public static final int STRATEGY_KEEP_ONLY_LATEST = 0; // 0x0
+ }
+
+ public static interface ImageAnalysis.Analyzer {
+ method public void analyze(androidx.camera.core.ImageProxy);
+ }
+
+ @IntDef({androidx.camera.core.ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST, androidx.camera.core.ImageAnalysis.STRATEGY_BLOCK_PRODUCER}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ImageAnalysis.BackpressureStrategy {
+ }
+
+ public static final class ImageAnalysis.Builder implements androidx.camera.core.impl.UseCaseConfig.Builder<androidx.camera.core.ImageAnalysis,androidx.camera.core.impl.ImageAnalysisConfig,androidx.camera.core.ImageAnalysis.Builder> {
+ ctor public ImageAnalysis.Builder();
+ method public androidx.camera.core.ImageAnalysis build();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.ImageAnalysis.Builder fromConfig(androidx.camera.core.impl.ImageAnalysisConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.MutableConfig getMutableConfig();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.ImageAnalysisConfig getUseCaseConfig();
+ method public androidx.camera.core.ImageAnalysis.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageAnalysis.Builder setBackpressureStrategy(@androidx.camera.core.ImageAnalysis.BackpressureStrategy int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setCaptureOptionUnpacker(androidx.camera.core.impl.CaptureConfig.OptionUnpacker);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setDefaultCaptureConfig(androidx.camera.core.impl.CaptureConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setDefaultResolution(android.util.Size);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setDefaultSessionConfig(androidx.camera.core.impl.SessionConfig);
+ method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setMaxResolution(android.util.Size);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setSessionOptionUnpacker(androidx.camera.core.impl.SessionConfig.OptionUnpacker);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setSupportedResolutions(java.util.List<android.util.Pair<java.lang.Integer!,android.util.Size![]!>!>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setSurfaceOccupancyPriority(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(@androidx.camera.core.AspectRatio.Ratio int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatioCustom(android.util.Rational);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setTargetClass(Class<androidx.camera.core.ImageAnalysis!>);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageAnalysis.Builder setUseCaseEventCallback(androidx.camera.core.UseCase.EventCallback);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final class ImageAnalysis.Defaults {
+ ctor public ImageAnalysis.Defaults();
+ method public androidx.camera.core.impl.ImageAnalysisConfig getConfig(androidx.camera.core.CameraInfo?);
+ }
+
+ public class ImageCapture extends androidx.camera.core.UseCase {
+ method @androidx.camera.core.ImageCapture.FlashMode public int getFlashMode();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected java.util.Map<java.lang.String!,android.util.Size!> onSuggestedResolutionUpdated(java.util.Map<java.lang.String!,android.util.Size!>);
+ method public void setFlashMode(@androidx.camera.core.ImageCapture.FlashMode int);
+ method public void setTargetAspectRatioCustom(android.util.Rational);
+ method public void setTargetRotation(int);
+ method public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+ method public void takePicture(java.io.File, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ method public void takePicture(java.io.File, androidx.camera.core.ImageCapture.Metadata, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ field public static final int CAPTURE_MODE_MAXIMIZE_QUALITY = 0; // 0x0
+ field public static final int CAPTURE_MODE_MINIMIZE_LATENCY = 1; // 0x1
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final androidx.camera.core.ImageCapture.Defaults! DEFAULT_CONFIG;
+ field public static final int ERROR_CAMERA_CLOSED = 3; // 0x3
+ field public static final int ERROR_CAPTURE_FAILED = 2; // 0x2
+ field public static final int ERROR_FILE_IO = 1; // 0x1
+ field public static final int ERROR_INVALID_CAMERA = 4; // 0x4
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int FLASH_MODE_AUTO = 0; // 0x0
+ field public static final int FLASH_MODE_OFF = 2; // 0x2
+ field public static final int FLASH_MODE_ON = 1; // 0x1
+ }
+
+ public static final class ImageCapture.Builder implements androidx.camera.core.impl.UseCaseConfig.Builder<androidx.camera.core.ImageCapture,androidx.camera.core.impl.ImageCaptureConfig,androidx.camera.core.ImageCapture.Builder> {
+ ctor public ImageCapture.Builder();
+ method public androidx.camera.core.ImageCapture build();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.ImageCapture.Builder fromConfig(androidx.camera.core.impl.ImageCaptureConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.MutableConfig getMutableConfig();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.ImageCaptureConfig getUseCaseConfig();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setBufferFormat(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setCameraSelector(androidx.camera.core.CameraSelector);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setCaptureBundle(androidx.camera.core.impl.CaptureBundle);
+ method public androidx.camera.core.ImageCapture.Builder setCaptureMode(@androidx.camera.core.ImageCapture.CaptureMode int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setCaptureOptionUnpacker(androidx.camera.core.impl.CaptureConfig.OptionUnpacker);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setCaptureProcessor(androidx.camera.core.impl.CaptureProcessor);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setDefaultCaptureConfig(androidx.camera.core.impl.CaptureConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setDefaultResolution(android.util.Size);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setDefaultSessionConfig(androidx.camera.core.impl.SessionConfig);
+ method public androidx.camera.core.ImageCapture.Builder setFlashMode(@androidx.camera.core.ImageCapture.FlashMode int);
+ method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setMaxCaptureStages(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setMaxResolution(android.util.Size);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setSessionOptionUnpacker(androidx.camera.core.impl.SessionConfig.OptionUnpacker);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setSupportedResolutions(java.util.List<android.util.Pair<java.lang.Integer!,android.util.Size![]!>!>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setSurfaceOccupancyPriority(int);
+ method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(@androidx.camera.core.AspectRatio.Ratio int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setTargetAspectRatioCustom(android.util.Rational);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setTargetClass(Class<androidx.camera.core.ImageCapture!>);
+ method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
+ method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.ImageCapture.Builder setUseCaseEventCallback(androidx.camera.core.UseCase.EventCallback);
+ }
+
+ @IntDef({androidx.camera.core.ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY, androidx.camera.core.ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ImageCapture.CaptureMode {
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final class ImageCapture.Defaults {
+ ctor public ImageCapture.Defaults();
+ method public androidx.camera.core.impl.ImageCaptureConfig getConfig(androidx.camera.core.CameraInfo?);
+ }
+
+ @IntDef({androidx.camera.core.ImageCapture.FLASH_MODE_AUTO, androidx.camera.core.ImageCapture.FLASH_MODE_ON, androidx.camera.core.ImageCapture.FLASH_MODE_OFF}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ImageCapture.FlashMode {
+ }
+
+ @IntDef({androidx.camera.core.ImageCapture.ERROR_UNKNOWN, androidx.camera.core.ImageCapture.ERROR_FILE_IO, androidx.camera.core.ImageCapture.ERROR_CAPTURE_FAILED, androidx.camera.core.ImageCapture.ERROR_CAMERA_CLOSED, androidx.camera.core.ImageCapture.ERROR_INVALID_CAMERA}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ImageCapture.ImageCaptureError {
+ }
+
+ public static final class ImageCapture.Metadata {
+ ctor public ImageCapture.Metadata();
+ method public android.location.Location? getLocation();
+ method public boolean isReversedHorizontal();
+ method public boolean isReversedVertical();
+ method public void setLocation(android.location.Location?);
+ method public void setReversedHorizontal(boolean);
+ method public void setReversedVertical(boolean);
+ }
+
+ public abstract static class ImageCapture.OnImageCapturedCallback {
+ ctor public ImageCapture.OnImageCapturedCallback();
+ method public void onCaptureSuccess(androidx.camera.core.ImageProxy);
+ method public void onError(@androidx.camera.core.ImageCapture.ImageCaptureError int, String, Throwable?);
+ }
+
+ public static interface ImageCapture.OnImageSavedCallback {
+ method public void onError(@androidx.camera.core.ImageCapture.ImageCaptureError int, String, Throwable?);
+ method public void onImageSaved(java.io.File);
+ }
+
+ public interface ImageInfo {
+ method public int getRotationDegrees();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public Object? getTag();
+ method public long getTimestamp();
+ }
+
+ public interface ImageProxy extends java.lang.AutoCloseable {
+ method public void close();
+ method public android.graphics.Rect getCropRect();
+ method public int getFormat();
+ method public int getHeight();
+ method public androidx.camera.core.ImageInfo getImageInfo();
+ method public androidx.camera.core.ImageProxy.PlaneProxy![] getPlanes();
+ method public int getWidth();
+ method public void setCropRect(android.graphics.Rect?);
+ }
+
+ public static interface ImageProxy.PlaneProxy {
+ method public java.nio.ByteBuffer getBuffer();
+ method public int getPixelStride();
+ method public int getRowStride();
+ }
+
+ public class MeteringPoint {
+ method public float getSize();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public android.util.Rational? getSurfaceAspectRatio();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public float getX();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public float getY();
+ }
+
+ public abstract class MeteringPointFactory {
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public MeteringPointFactory();
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public MeteringPointFactory(android.util.Rational?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected abstract android.graphics.PointF convertPoint(float, float);
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float);
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float, float);
+ method public static float getDefaultPointSize();
+ }
+
+ public class Preview extends androidx.camera.core.UseCase {
+ method @UiThread public androidx.camera.core.Preview.PreviewSurfaceProvider? getPreviewSurfaceProvider();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected java.util.Map<java.lang.String!,android.util.Size!> onSuggestedResolutionUpdated(java.util.Map<java.lang.String!,android.util.Size!>);
+ method @UiThread public void setPreviewSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.PreviewSurfaceProvider?);
+ method @UiThread public void setPreviewSurfaceProvider(androidx.camera.core.Preview.PreviewSurfaceProvider?);
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final androidx.camera.core.Preview.Defaults! DEFAULT_CONFIG;
+ }
+
+ public static final class Preview.Builder implements androidx.camera.core.impl.UseCaseConfig.Builder<androidx.camera.core.Preview,androidx.camera.core.impl.PreviewConfig,androidx.camera.core.Preview.Builder> {
+ ctor public Preview.Builder();
+ method public androidx.camera.core.Preview build();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.camera.core.Preview.Builder fromConfig(androidx.camera.core.impl.PreviewConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.MutableConfig getMutableConfig();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.PreviewConfig getUseCaseConfig();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setCameraSelector(androidx.camera.core.CameraSelector);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setCaptureOptionUnpacker(androidx.camera.core.impl.CaptureConfig.OptionUnpacker);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setCaptureProcessor(androidx.camera.core.impl.CaptureProcessor);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setDefaultCaptureConfig(androidx.camera.core.impl.CaptureConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setDefaultResolution(android.util.Size);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setDefaultSessionConfig(androidx.camera.core.impl.SessionConfig);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setImageInfoProcessor(androidx.camera.core.impl.ImageInfoProcessor);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setMaxResolution(android.util.Size);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setSessionOptionUnpacker(androidx.camera.core.impl.SessionConfig.OptionUnpacker);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setSupportedResolutions(java.util.List<android.util.Pair<java.lang.Integer!,android.util.Size![]!>!>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setSurfaceOccupancyPriority(int);
+ method public androidx.camera.core.Preview.Builder setTargetAspectRatio(@androidx.camera.core.AspectRatio.Ratio int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setTargetAspectRatioCustom(android.util.Rational);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setTargetClass(Class<androidx.camera.core.Preview!>);
+ method public androidx.camera.core.Preview.Builder setTargetName(String);
+ method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.Preview.Builder setTargetRotation(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.Preview.Builder setUseCaseEventCallback(androidx.camera.core.UseCase.EventCallback);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final class Preview.Defaults {
+ ctor public Preview.Defaults();
+ method public androidx.camera.core.impl.PreviewConfig getConfig(androidx.camera.core.CameraInfo?);
+ }
+
+ public static interface Preview.PreviewSurfaceProvider {
+ method public com.google.common.util.concurrent.ListenableFuture<android.view.Surface!> provideSurface(android.util.Size, com.google.common.util.concurrent.ListenableFuture<java.lang.Void!>);
+ }
+
+ public class SurfaceOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public SurfaceOrientedMeteringPointFactory(float, float);
+ ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected android.graphics.PointF convertPoint(float, float);
+ }
+
+ public class TorchState {
+ field public static final int OFF = 0; // 0x0
+ field public static final int ON = 1; // 0x1
+ }
+
+ @IntDef({androidx.camera.core.TorchState.OFF, androidx.camera.core.TorchState.ON}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface TorchState.State {
+ }
+
+ public abstract class UseCase {
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected UseCase(androidx.camera.core.impl.UseCaseConfig<?>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void addStateChangeCallback(androidx.camera.core.UseCase.StateChangeCallback);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected androidx.camera.core.impl.UseCaseConfig<?> applyDefaults(androidx.camera.core.impl.UseCaseConfig<?>, androidx.camera.core.impl.UseCaseConfig.Builder<?,?,?>?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final void attachCameraControl(String!, androidx.camera.core.impl.CameraControlInternal!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected void attachToCamera(String!, androidx.camera.core.impl.SessionConfig!);
+ method @CallSuper @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void clear();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public java.util.Set<java.lang.String!>! getAttachedCameraIds();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public android.util.Size! getAttachedSurfaceResolution(String!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.CameraInternal? getBoundCamera();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected String getBoundCameraId();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected androidx.camera.core.impl.CameraControlInternal! getCameraControl(String!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected androidx.camera.core.impl.UseCaseConfig.Builder<?,?,?>? getDefaultBuilder(androidx.camera.core.CameraInfo?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public int getImageFormat();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public String getName();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.SessionConfig! getSessionConfig(String!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public androidx.camera.core.impl.UseCaseConfig<?>! getUseCaseConfig();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected boolean isCurrentlyBoundCamera(String);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected final void notifyActive();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected final void notifyInactive();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected final void notifyReset();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected final void notifyState();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected final void notifyUpdated();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected void onBind(androidx.camera.core.impl.CameraInternal);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected void onCameraControlReady(String!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void onStateOffline(String);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void onStateOnline(String);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected abstract java.util.Map<java.lang.String!,android.util.Size!> onSuggestedResolutionUpdated(java.util.Map<java.lang.String!,android.util.Size!>);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void removeStateChangeCallback(androidx.camera.core.UseCase.StateChangeCallback);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected void setImageFormat(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void updateSuggestedResolution(java.util.Map<java.lang.String!,android.util.Size!>!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected final void updateUseCaseConfig(androidx.camera.core.impl.UseCaseConfig<?>);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static interface UseCase.EventCallback {
+ method public void onBind(String);
+ method public void onUnbind();
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static interface UseCase.StateChangeCallback {
+ method public void onUseCaseActive(androidx.camera.core.UseCase);
+ method public void onUseCaseInactive(androidx.camera.core.UseCase);
+ method public void onUseCaseReset(androidx.camera.core.UseCase);
+ method public void onUseCaseUpdated(androidx.camera.core.UseCase);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public class VideoCapture extends androidx.camera.core.UseCase {
+ ctor public VideoCapture(androidx.camera.core.impl.VideoCaptureConfig!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected java.util.Map<java.lang.String!,android.util.Size!> onSuggestedResolutionUpdated(java.util.Map<java.lang.String!,android.util.Size!>);
+ method public void setTargetRotation(int);
+ method public void startRecording(java.io.File, java.util.concurrent.Executor, androidx.camera.core.VideoCapture.OnVideoSavedCallback);
+ method public void startRecording(java.io.File, androidx.camera.core.VideoCapture.Metadata, java.util.concurrent.Executor, androidx.camera.core.VideoCapture.OnVideoSavedCallback);
+ method public void stopRecording();
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final androidx.camera.core.VideoCapture.Defaults! DEFAULT_CONFIG;
+ field public static final int ERROR_ENCODER = 1; // 0x1
+ field public static final int ERROR_MUXER = 2; // 0x2
+ field public static final int ERROR_RECORDING_IN_PROGRESS = 3; // 0x3
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final class VideoCapture.Defaults {
+ ctor public VideoCapture.Defaults();
+ method public androidx.camera.core.impl.VideoCaptureConfig getConfig(androidx.camera.core.CameraInfo?);
+ }
+
+ public static final class VideoCapture.Metadata {
+ ctor public VideoCapture.Metadata();
+ field public android.location.Location? location;
+ }
+
+ public static interface VideoCapture.OnVideoSavedCallback {
+ method public void onError(@androidx.camera.core.VideoCapture.VideoCaptureError int, String, Throwable?);
+ method public void onVideoSaved(java.io.File);
+ }
+
+ @IntDef({androidx.camera.core.VideoCapture.ERROR_UNKNOWN, androidx.camera.core.VideoCapture.ERROR_ENCODER, androidx.camera.core.VideoCapture.ERROR_MUXER, androidx.camera.core.VideoCapture.ERROR_RECORDING_IN_PROGRESS}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface VideoCapture.VideoCaptureError {
+ }
+
+}
+
+package @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) androidx.camera.core.impl.annotation {
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface ExecutedBy {
+ method public abstract String value();
+ }
+
+}
+
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/core/ImageReaderProxysTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageReaderProxysTest.java
similarity index 100%
rename from camera/camera-camera2/src/androidTest/java/androidx/camera/core/ImageReaderProxysTest.java
rename to camera/camera-core/src/androidTest/java/androidx/camera/core/ImageReaderProxysTest.java
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/DisplayOrientedMeteringPointFactory.java b/camera/camera-core/src/main/java/androidx/camera/core/DisplayOrientedMeteringPointFactory.java
index 455ff98..bdd6a79 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/DisplayOrientedMeteringPointFactory.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/DisplayOrientedMeteringPointFactory.java
@@ -16,11 +16,9 @@
package androidx.camera.core;
-import android.content.Context;
import android.graphics.PointF;
import android.view.Display;
import android.view.View;
-import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -42,7 +40,7 @@
* duty to transform the coordinates properly so that the width and height of this
* factory represents the full Preview FOV and also the (x,y) passed to create
* {@link MeteringPoint} needs to be adjusted by apps to the coordinates left-top (0,0) -
- * right-bottom (width, height). For Example, if the preview is scaled to 2X from the center and
+ * right-bottom (width, height). For example, if the preview is scaled to 2X from the center and
* is cropped in a {@link View}. Assuming that the dimension of View is (240, 320), then the
* width/height of this {@link DisplayOrientedMeteringPointFactory} should be (480, 640). And
* the (x, y) from the {@link View} should be converted to (x + (480-240)/2, y + (640 - 320)/2)
@@ -65,44 +63,18 @@
/**
* Creates a {@link DisplayOrientedMeteringPointFactory} for converting View (x, y) into a
- * {@link MeteringPoint} based on default display's orientation and {@link CameraSelector}.
+ * {@link MeteringPoint} based on the current display's rotation and {@link CameraSelector}.
*
* <p>The width/height of this factory forms a coordinate left-top (0, 0) - right-bottom
- * (width, height) which represents the full camera preview FOV in default display's
+ * (width, height) which represents the full camera preview FOV in the display's
* orientation. For apps showing full camera preview in a {@link View}, it is as simple as
* passing View's width/height and passing View (x, y) directly to create a
* {@link MeteringPoint}. Otherwise the (x, y) passed to
* {@link MeteringPointFactory#createPoint(float, float)} should be adjusted to this
* coordinate system first.
*
- * @param context context to get the {@link WindowManager} for default display rotation.
- * @param cameraSelector current cameraSelector to choose camera.
- * @param width the width of the coordinate which are mapped to the full camera preview
- * FOV in default display's orientation.
- * @param height the height of the coordinate which are mapped to the full camera
- * preview
- * FOVin default display's orientation.
- */
- public DisplayOrientedMeteringPointFactory(@NonNull Context context,
- @NonNull CameraSelector cameraSelector, float width, float height) {
- this(((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(),
- cameraSelector, width, height);
- }
-
- /**
- * Creates a {@link DisplayOrientedMeteringPointFactory} for converting View (x, y) into a
- * {@link MeteringPoint} based on custom display's rotation and {@link CameraSelector}. This is
- * used in multi-display situation.
- *
- * <p>The width/height of this factory forms a coordinate left-top (0, 0) - right-bottom
- * (width, height) which represents the full camera preview FOV in default display's
- * orientation. For apps showing full camera preview in a {@link View}, it is as simple as
- * passing View's width/height and passing View (x, y) directly to create a
- * {@link MeteringPoint}. Otherwise the (x, y) passed to
- * {@link MeteringPointFactory#createPoint(float, float)} should be adjusted to this
- * coordinate system first.
- *
- * @param display {@link Display} to get the orientation from.
+ * @param display {@link Display} to get the orientation from. This should be the
+ * current display where camera preview is showing.
* @param cameraSelector current cameraSelector to choose camera.
* @param width the width of the coordinate which are mapped to the full camera preview
* FOV in given display's orientation.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/FocusMeteringAction.java b/camera/camera-core/src/main/java/androidx/camera/core/FocusMeteringAction.java
index 27b7778..c09b700 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/FocusMeteringAction.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/FocusMeteringAction.java
@@ -34,15 +34,19 @@
/**
* A configuration used to trigger a focus and/or metering action.
*
- * <p>To construct a {@link FocusMeteringAction}, apps have to create a {@link Builder} by
- * {@link Builder#from(MeteringPoint)} or {@link Builder#from(MeteringPoint, int)}.
- * {@link MeteringPoint} is a point used to specify the focus/metering areas. Apps can use various
- * {@link MeteringPointFactory} to create the points. When the {@link FocusMeteringAction} is built,
- * pass it to {@link CameraControl#startFocusAndMetering(FocusMeteringAction)} to initiate the focus
+ * <p>A {@link FocusMeteringAction} must be created by the {@link Builder}. To construct a
+ * {@link Builder}, a {@link MeteringPoint} is required to specify the focus/metering area. Apps
+ * can use various {@link MeteringPointFactory} to create the points. After the
+ * {@link FocusMeteringAction} is built, apps can pass it to
+ * {@link CameraControl#startFocusAndMetering(FocusMeteringAction)} to initiate the focus
* and metering action.
*
- * <p>The default meteringMode is {@link #FLAG_AF} | {@link #FLAG_AE} | {@link #FLAG_AWB} which
- * means the point is used for all AF/AE/AWB regions. Apps can set the proper meteringMode to
+ * <p>When specifying a {@link MeteringPoint}, a metering mode can also be specified. Metering
+ * mode is a combination of flags consisting of {@link #FLAG_AF}, {@link #FLAG_AE}, and
+ * {@link #FLAG_AWB}. This combination indicates whether the {@link MeteringPoint} is
+ * used to set AF(Auto Focus) region, AE(Auto Exposure) region or AWB(Auto White Balance) region.
+ * The default meteringMode is {@link #FLAG_AF} | {@link #FLAG_AE} | {@link #FLAG_AWB} which
+ * means the point is used for all AF/AE/AWB regions. Apps can set the proper metering mode to
* optionally exclude some 3A regions. Multiple regions for specific 3A type are also supported
* via {@link Builder#addPoint(MeteringPoint)} or {@link Builder#addPoint(MeteringPoint, int)}.
* App can also this API to enable different region for AF and AE respectively.
@@ -65,12 +69,24 @@
*/
public final class FocusMeteringAction {
+ /**
+ * A flag used in metering mode indicating the AF (Auto Focus) region is enabled. An autofocus
+ * scan is also triggered when FLAG_AF is assigned.
+ */
public static final int FLAG_AF = 1;
+
+ /**
+ * A flag used in metering mode indicating the AE (Auto Exposure) region is enabled.
+ */
public static final int FLAG_AE = 1 << 1;
+
+ /**
+ * A flag used in metering mode indicating the AWB (Auto White Balance) region is enabled.
+ */
public static final int FLAG_AWB = 1 << 2;
@MeteringMode
- static final int DEFAULT_METERINGMODE = FLAG_AF | FLAG_AE | FLAG_AWB;
+ static final int DEFAULT_METERING_MODE = FLAG_AF | FLAG_AE | FLAG_AWB;
static final long DEFAULT_AUTOCANCEL_DURATION = 5000;
private final List<MeteringPoint> mMeteringPointsAf;
private final List<MeteringPoint> mMeteringPointsAe;
@@ -136,9 +152,7 @@
}
/**
- * The builder used to create the {@link FocusMeteringAction}. App must use
- * {@link Builder#from(MeteringPoint)}
- * or {@link Builder#from(MeteringPoint, int)} to create the {@link Builder}.
+ * The builder used to create the {@link FocusMeteringAction}.
*/
public static class Builder {
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
@@ -150,38 +164,32 @@
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
long mAutoCancelDurationInMillis = DEFAULT_AUTOCANCEL_DURATION;
- private Builder(@NonNull MeteringPoint point) {
- this(point, DEFAULT_METERINGMODE);
- }
-
- private Builder(@NonNull MeteringPoint point, @MeteringMode int mode) {
- addPoint(point, mode);
- }
-
/**
- * Creates the Builder from a {@link MeteringPoint} with default
- * mode {@link #FLAG_AF} | {@link #FLAG_AE} | {@link #FLAG_AWB}.
+ * Creates the Builder from a {@link MeteringPoint} with default mode {@link #FLAG_AF} |
+ * {@link #FLAG_AE} | {@link #FLAG_AWB}.
*/
- @NonNull
- public static Builder from(@NonNull MeteringPoint meteringPoint) {
- return new Builder(meteringPoint);
+ public Builder(@NonNull MeteringPoint point) {
+ this(point, DEFAULT_METERING_MODE);
}
/**
* Creates the Builder from a {@link MeteringPoint} and MeteringMode.
+ *
+ * <p>Metering mode is a combination of flags consisting of {@link #FLAG_AF},
+ * {@link #FLAG_AE}, and {@link #FLAG_AWB}. This combination indicates whether the
+ * {@link MeteringPoint} is used to set AF(Auto Focus) region, AE(Auto
+ * Exposure) region or AWB(Auto White Balance) region.
*/
- @NonNull
- public static Builder from(@NonNull MeteringPoint meteringPoint, @MeteringMode int mode) {
- return new Builder(meteringPoint, mode);
+ public Builder(@NonNull MeteringPoint point, @MeteringMode int meteringMode) {
+ addPoint(point, meteringMode);
}
/**
- * Adds another {@link MeteringPoint} with default mode {@link #FLAG_AF} |
+ * Adds another {@link MeteringPoint} with default metering mode {@link #FLAG_AF} |
* {@link #FLAG_AE} | {@link #FLAG_AWB}.
*
- * <p>The points added here will be appended in order after the point set in
- * {@link FocusMeteringAction.Builder#from(MeteringPoint)} or
- * {@link FocusMeteringAction.Builder#from(MeteringPoint, int)}.
+ * <p>The points added here will be appended in order after the point set in builder
+ * constructor.
*
* <p>If more points are added than what current device supports for AF/AE/AWB, only the
* first point and then in order up to the number of points supported on the device
@@ -195,15 +203,19 @@
*/
@NonNull
public Builder addPoint(@NonNull MeteringPoint point) {
- return addPoint(point, DEFAULT_METERINGMODE);
+ return addPoint(point, DEFAULT_METERING_MODE);
}
/**
* Adds another {@link MeteringPoint} with specified meteringMode.
*
- * <p>The points added here will be appended in order after the point set in
- * {@link FocusMeteringAction.Builder#from(MeteringPoint)} or
- * {@link FocusMeteringAction.Builder#from(MeteringPoint, int)}.
+ * <p>Metering mode is a combination of flags consisting of {@link #FLAG_AF},
+ * {@link #FLAG_AE}, and {@link #FLAG_AWB}. This combination indicates whether the
+ * {@link MeteringPoint} is used to set AF(Auto Focus) region, AE(Auto Exposure) region
+ * or AWB(Auto White Balance) region.
+ *
+ * <p>The points added here will be appended in order after the point set in builder
+ * constructor.
*
* <p>If more points are added than what current device supports for AF/AE/AWB, only the
* first point and then in order up to the number of points supported on the device
@@ -216,18 +228,19 @@
* @see CameraControl#startFocusAndMetering(FocusMeteringAction)
*/
@NonNull
- public Builder addPoint(@NonNull MeteringPoint point, @MeteringMode int mode) {
+ public Builder addPoint(@NonNull MeteringPoint point, @MeteringMode int meteringMode) {
+ Preconditions.checkArgument(point != null, "Point cannot be null.");
Preconditions.checkArgument(
- (mode >= FLAG_AF) && (mode <= (FLAG_AF | FLAG_AE | FLAG_AWB)),
- "Invalid metering mode " + mode);
+ (meteringMode >= FLAG_AF) && (meteringMode <= (FLAG_AF | FLAG_AE | FLAG_AWB)),
+ "Invalid metering mode " + meteringMode);
- if ((mode & FLAG_AF) != 0) {
+ if ((meteringMode & FLAG_AF) != 0) {
mMeteringPointsAf.add(point);
}
- if ((mode & FLAG_AE) != 0) {
+ if ((meteringMode & FLAG_AE) != 0) {
mMeteringPointsAe.add(point);
}
- if ((mode & FLAG_AWB) != 0) {
+ if ((meteringMode & FLAG_AWB) != 0) {
mMeteringPointsAwb.add(point);
}
return this;
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageReaderProxys.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageReaderProxys.java
index 1421c48..f4cdc15 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageReaderProxys.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageReaderProxys.java
@@ -19,17 +19,12 @@
import android.media.ImageReader;
import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-import androidx.annotation.RestrictTo.Scope;
import androidx.camera.core.impl.ImageReaderProxy;
/**
* Different implementations of {@link ImageReaderProxy}.
- *
- * @hide
*/
-@RestrictTo(Scope.LIBRARY_GROUP)
-public final class ImageReaderProxys {
+final class ImageReaderProxys {
private ImageReaderProxys() {
}
@@ -44,7 +39,7 @@
* @return new {@link ImageReaderProxy} instance
*/
@NonNull
- public static ImageReaderProxy createIsolatedReader(
+ static ImageReaderProxy createIsolatedReader(
int width, int height, int format, int maxImages) {
ImageReader imageReader = ImageReader.newInstance(width, height, format, maxImages);
return new AndroidImageReaderProxy(imageReader);
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ProcessingImageReader.java b/camera/camera-core/src/main/java/androidx/camera/core/ProcessingImageReader.java
index c7473ff..f5e4eb1 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ProcessingImageReader.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ProcessingImageReader.java
@@ -335,10 +335,9 @@
if (!mCaptureIdList.contains(tag)) {
Log.w(TAG, "ImageProxyBundle does not contain this id: " + tag);
image.close();
- return;
+ } else {
+ mSettableImageProxyBundle.addImageProxy(image);
}
-
- mSettableImageProxyBundle.addImageProxy(image);
}
}
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/SettableImageProxy.java b/camera/camera-core/src/main/java/androidx/camera/core/SettableImageProxy.java
index c17e8f1..542c67c 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/SettableImageProxy.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/SettableImageProxy.java
@@ -35,6 +35,7 @@
mImageInfo = imageInfo;
}
+ @SuppressWarnings("UnsynchronizedOverridesSynchronized")
@Override
@NonNull
public ImageInfo getImageInfo() {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/utils/executor/HighPriorityExecutor.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/utils/executor/HighPriorityExecutor.java
index 99702cc..ea835b9 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/utils/executor/HighPriorityExecutor.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/utils/executor/HighPriorityExecutor.java
@@ -36,6 +36,7 @@
private static final String THREAD_NAME =
CameraXThreads.TAG + "camerax_high_priority";
+ @SuppressWarnings("ThreadPriorityCheck")
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/FocusMeteringActionTest.java b/camera/camera-core/src/test/java/androidx/camera/core/FocusMeteringActionTest.java
index 5ae62c87..c4adaed 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/FocusMeteringActionTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/FocusMeteringActionTest.java
@@ -40,7 +40,7 @@
@Test
public void defaultBuilder_valueIsDefault() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1).build();
assertThat(action.getMeteringPointsAf()).containsExactly(mPoint1);
assertThat(action.getMeteringPointsAe()).containsExactly(mPoint1);
@@ -52,9 +52,10 @@
@Test
public void fromPointWithAFAEAWB() {
- FocusMeteringAction action = FocusMeteringAction.Builder
- .from(mPoint1, FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE
- | FocusMeteringAction.FLAG_AWB).build();
+ FocusMeteringAction action =
+ new FocusMeteringAction.Builder(mPoint1,
+ FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE
+ | FocusMeteringAction.FLAG_AWB).build();
assertThat(action.getMeteringPointsAf()).containsExactly(mPoint1);
assertThat(action.getMeteringPointsAe()).containsExactly(mPoint1);
assertThat(action.getMeteringPointsAwb()).containsExactly(mPoint1);
@@ -62,8 +63,8 @@
@Test
public void fromPointWithAFAE() {
- FocusMeteringAction action = FocusMeteringAction.Builder
- .from(mPoint1, FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
+ FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE).build();
assertThat(action.getMeteringPointsAf()).containsExactly(mPoint1);
assertThat(action.getMeteringPointsAe()).containsExactly(mPoint1);
assertThat(action.getMeteringPointsAwb()).isEmpty();
@@ -71,8 +72,8 @@
@Test
public void fromPointWithAFAWB() {
- FocusMeteringAction action = FocusMeteringAction.Builder
- .from(mPoint1, FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AWB).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
+ FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AWB).build();
assertThat(action.getMeteringPointsAf()).containsExactly(mPoint1);
assertThat(action.getMeteringPointsAe()).isEmpty();
assertThat(action.getMeteringPointsAwb()).containsExactly(mPoint1);
@@ -80,8 +81,8 @@
@Test
public void fromPointWithAEAWB() {
- FocusMeteringAction action = FocusMeteringAction.Builder
- .from(mPoint1, FocusMeteringAction.FLAG_AE | FocusMeteringAction.FLAG_AWB).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
+ FocusMeteringAction.FLAG_AE | FocusMeteringAction.FLAG_AWB).build();
assertThat(action.getMeteringPointsAf()).isEmpty();
assertThat(action.getMeteringPointsAe()).containsExactly(mPoint1);
assertThat(action.getMeteringPointsAwb()).containsExactly(mPoint1);
@@ -89,8 +90,8 @@
@Test
public void fromPointWithAF() {
- FocusMeteringAction action = FocusMeteringAction.Builder
- .from(mPoint1, FocusMeteringAction.FLAG_AF).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
+ FocusMeteringAction.FLAG_AF).build();
assertThat(action.getMeteringPointsAf()).containsExactly(mPoint1);
assertThat(action.getMeteringPointsAe()).isEmpty();
assertThat(action.getMeteringPointsAwb()).isEmpty();
@@ -98,8 +99,8 @@
@Test
public void fromPointWithAE() {
- FocusMeteringAction action = FocusMeteringAction.Builder
- .from(mPoint1, FocusMeteringAction.FLAG_AE).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
+ FocusMeteringAction.FLAG_AE).build();
assertThat(action.getMeteringPointsAf()).isEmpty();
assertThat(action.getMeteringPointsAe()).containsExactly(mPoint1);
assertThat(action.getMeteringPointsAwb()).isEmpty();
@@ -107,8 +108,8 @@
@Test
public void fromPointWithAWB() {
- FocusMeteringAction action = FocusMeteringAction.Builder
- .from(mPoint1, FocusMeteringAction.FLAG_AWB).build();
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
+ FocusMeteringAction.FLAG_AWB).build();
assertThat(action.getMeteringPointsAf()).isEmpty();
assertThat(action.getMeteringPointsAe()).isEmpty();
assertThat(action.getMeteringPointsAwb()).containsExactly(mPoint1);
@@ -116,7 +117,7 @@
@Test
public void multiplePointsWithDefaultMeteringMode() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1)
.addPoint(mPoint2)
.addPoint(mPoint3)
.build();
@@ -127,10 +128,9 @@
@Test
public void multiplePointsWithSameAF_AE_AWB() {
- FocusMeteringAction action = FocusMeteringAction.Builder
- .from(mPoint1,
- FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE
- | FocusMeteringAction.FLAG_AWB)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
+ FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE
+ | FocusMeteringAction.FLAG_AWB)
.addPoint(mPoint2,
FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE
| FocusMeteringAction.FLAG_AWB)
@@ -145,8 +145,8 @@
@Test
public void multiplePointsWithSameAF_AE() {
- FocusMeteringAction action = FocusMeteringAction.Builder
- .from(mPoint1, FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
+ FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE)
.addPoint(mPoint2, FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE)
.addPoint(mPoint3, FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE)
.build();
@@ -157,8 +157,8 @@
@Test
public void multiplePointsWithSameAE_AWB() {
- FocusMeteringAction action = FocusMeteringAction.Builder
- .from(mPoint1, FocusMeteringAction.FLAG_AE | FocusMeteringAction.FLAG_AWB)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
+ FocusMeteringAction.FLAG_AE | FocusMeteringAction.FLAG_AWB)
.addPoint(mPoint2, FocusMeteringAction.FLAG_AE | FocusMeteringAction.FLAG_AWB)
.addPoint(mPoint3, FocusMeteringAction.FLAG_AE | FocusMeteringAction.FLAG_AWB)
.build();
@@ -169,8 +169,8 @@
@Test
public void multiplePointsWithSameAF_AWB() {
- FocusMeteringAction action = FocusMeteringAction.Builder
- .from(mPoint1, FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AWB)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
+ FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AWB)
.addPoint(mPoint2, FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AWB)
.addPoint(mPoint3, FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AWB)
.build();
@@ -181,7 +181,7 @@
@Test
public void multiplePointsWithSameAWBOnly() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FocusMeteringAction.FLAG_AWB)
.addPoint(mPoint2, FocusMeteringAction.FLAG_AWB)
.addPoint(mPoint3, FocusMeteringAction.FLAG_AWB)
@@ -193,7 +193,7 @@
@Test
public void multiplePointsWithSameAEOnly() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FocusMeteringAction.FLAG_AE)
.addPoint(mPoint2, FocusMeteringAction.FLAG_AE)
.addPoint(mPoint3, FocusMeteringAction.FLAG_AE)
@@ -205,7 +205,7 @@
@Test
public void multiplePointsWithSameAFOnly() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FocusMeteringAction.FLAG_AF)
.addPoint(mPoint2, FocusMeteringAction.FLAG_AF)
.addPoint(mPoint3, FocusMeteringAction.FLAG_AF)
@@ -217,7 +217,7 @@
@Test
public void multiplePointsWithAFOnly_AEOnly_AWBOnly() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FocusMeteringAction.FLAG_AF)
.addPoint(mPoint2, FocusMeteringAction.FLAG_AE)
.addPoint(mPoint3, FocusMeteringAction.FLAG_AWB)
@@ -229,7 +229,7 @@
@Test
public void multiplePointsWithAFAE_AEAWB_AFAWB() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE)
.addPoint(mPoint2, FocusMeteringAction.FLAG_AE | FocusMeteringAction.FLAG_AWB)
.addPoint(mPoint3, FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AWB)
@@ -241,7 +241,7 @@
@Test
public void multiplePointsWithAFAEAWB_AEAWB_AFOnly() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE
| FocusMeteringAction.FLAG_AWB)
.addPoint(mPoint2, FocusMeteringAction.FLAG_AE | FocusMeteringAction.FLAG_AWB)
@@ -254,7 +254,7 @@
@Test
public void multiplePointsWithAEOnly_AFAWAEB_AEOnly() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1,
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1,
FocusMeteringAction.FLAG_AE)
.addPoint(mPoint2,
FocusMeteringAction.FLAG_AF | FocusMeteringAction.FLAG_AE
@@ -268,7 +268,7 @@
@Test
public void setAutoCancelDurationBySeconds() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1)
.setAutoCancelDuration(3, TimeUnit.SECONDS)
.build();
assertThat(action.getAutoCancelDurationInMillis()).isEqualTo(3000);
@@ -276,7 +276,7 @@
@Test
public void setAutoCancelDurationByMinutes() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1)
.setAutoCancelDuration(2, TimeUnit.MINUTES)
.build();
assertThat(action.getAutoCancelDurationInMillis()).isEqualTo(120000);
@@ -284,7 +284,7 @@
@Test
public void setAutoCancelDurationByMilliseconds() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1)
.setAutoCancelDuration(1500, TimeUnit.MILLISECONDS)
.build();
assertThat(action.getAutoCancelDurationInMillis()).isEqualTo(1500);
@@ -292,7 +292,7 @@
@Test
public void setAutoCancelDurationLargerThan0_shouldEnableAutoCancel() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1)
.setAutoCancelDuration(1, TimeUnit.MILLISECONDS)
.build();
@@ -301,15 +301,26 @@
@Test(expected = IllegalArgumentException.class)
public void setAutoCancelDuration0_shouldThrowException() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1)
.setAutoCancelDuration(0, TimeUnit.MILLISECONDS)
.build();
}
@Test(expected = IllegalArgumentException.class)
public void setAutoCancelDurationSmallerThan0_shouldThrowException() {
- FocusMeteringAction action = FocusMeteringAction.Builder.from(mPoint1)
+ FocusMeteringAction action = new FocusMeteringAction.Builder(mPoint1)
.setAutoCancelDuration(-1, TimeUnit.MILLISECONDS)
.build();
}
+
+ @Test(expected = IllegalArgumentException.class)
+ public void builderWithNullPoint() {
+ new FocusMeteringAction.Builder(null).build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void builderWithNullPoint2() {
+ new FocusMeteringAction.Builder(null, FocusMeteringAction.FLAG_AF).build();
+ }
+
}
diff --git a/camera/camera-lifecycle/api/1.0.0-alpha02.txt b/camera/camera-lifecycle/api/1.0.0-alpha02.txt
new file mode 100644
index 0000000..a6aba27
--- /dev/null
+++ b/camera/camera-lifecycle/api/1.0.0-alpha02.txt
@@ -0,0 +1,21 @@
+// Signature format: 3.0
+package androidx.camera.lifecycle {
+
+ public interface LifecycleCameraProvider {
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method public void unbind(androidx.camera.core.UseCase!...);
+ method public void unbindAll();
+ }
+
+ public final class ProcessCameraProvider implements androidx.camera.lifecycle.LifecycleCameraProvider {
+ method public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method public void unbind(androidx.camera.core.UseCase!...);
+ method public void unbindAll();
+ }
+
+}
+
diff --git a/camera/camera-lifecycle/api/current.txt b/camera/camera-lifecycle/api/current.txt
new file mode 100644
index 0000000..a6aba27
--- /dev/null
+++ b/camera/camera-lifecycle/api/current.txt
@@ -0,0 +1,21 @@
+// Signature format: 3.0
+package androidx.camera.lifecycle {
+
+ public interface LifecycleCameraProvider {
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method public void unbind(androidx.camera.core.UseCase!...);
+ method public void unbindAll();
+ }
+
+ public final class ProcessCameraProvider implements androidx.camera.lifecycle.LifecycleCameraProvider {
+ method public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method public void unbind(androidx.camera.core.UseCase!...);
+ method public void unbindAll();
+ }
+
+}
+
diff --git a/camera/camera-lifecycle/api/public_plus_experimental_1.0.0-alpha02.txt b/camera/camera-lifecycle/api/public_plus_experimental_1.0.0-alpha02.txt
new file mode 100644
index 0000000..a6aba27
--- /dev/null
+++ b/camera/camera-lifecycle/api/public_plus_experimental_1.0.0-alpha02.txt
@@ -0,0 +1,21 @@
+// Signature format: 3.0
+package androidx.camera.lifecycle {
+
+ public interface LifecycleCameraProvider {
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method public void unbind(androidx.camera.core.UseCase!...);
+ method public void unbindAll();
+ }
+
+ public final class ProcessCameraProvider implements androidx.camera.lifecycle.LifecycleCameraProvider {
+ method public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method public void unbind(androidx.camera.core.UseCase!...);
+ method public void unbindAll();
+ }
+
+}
+
diff --git a/camera/camera-lifecycle/api/public_plus_experimental_current.txt b/camera/camera-lifecycle/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..a6aba27
--- /dev/null
+++ b/camera/camera-lifecycle/api/public_plus_experimental_current.txt
@@ -0,0 +1,21 @@
+// Signature format: 3.0
+package androidx.camera.lifecycle {
+
+ public interface LifecycleCameraProvider {
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method public void unbind(androidx.camera.core.UseCase!...);
+ method public void unbindAll();
+ }
+
+ public final class ProcessCameraProvider implements androidx.camera.lifecycle.LifecycleCameraProvider {
+ method public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method public void unbind(androidx.camera.core.UseCase!...);
+ method public void unbindAll();
+ }
+
+}
+
diff --git a/savedstate/api/res-1.0.0-alpha02.txt b/camera/camera-lifecycle/api/res-1.0.0-alpha02.txt
similarity index 100%
copy from savedstate/api/res-1.0.0-alpha02.txt
copy to camera/camera-lifecycle/api/res-1.0.0-alpha02.txt
diff --git a/camera/camera-lifecycle/api/restricted_1.0.0-alpha02.txt b/camera/camera-lifecycle/api/restricted_1.0.0-alpha02.txt
new file mode 100644
index 0000000..a6aba27
--- /dev/null
+++ b/camera/camera-lifecycle/api/restricted_1.0.0-alpha02.txt
@@ -0,0 +1,21 @@
+// Signature format: 3.0
+package androidx.camera.lifecycle {
+
+ public interface LifecycleCameraProvider {
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method public void unbind(androidx.camera.core.UseCase!...);
+ method public void unbindAll();
+ }
+
+ public final class ProcessCameraProvider implements androidx.camera.lifecycle.LifecycleCameraProvider {
+ method public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method public void unbind(androidx.camera.core.UseCase!...);
+ method public void unbindAll();
+ }
+
+}
+
diff --git a/camera/camera-lifecycle/api/restricted_current.txt b/camera/camera-lifecycle/api/restricted_current.txt
new file mode 100644
index 0000000..a6aba27
--- /dev/null
+++ b/camera/camera-lifecycle/api/restricted_current.txt
@@ -0,0 +1,21 @@
+// Signature format: 3.0
+package androidx.camera.lifecycle {
+
+ public interface LifecycleCameraProvider {
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method public void unbind(androidx.camera.core.UseCase!...);
+ method public void unbindAll();
+ }
+
+ public final class ProcessCameraProvider implements androidx.camera.lifecycle.LifecycleCameraProvider {
+ method public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method public void unbind(androidx.camera.core.UseCase!...);
+ method public void unbindAll();
+ }
+
+}
+
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/TextureViewMeteringPointFactoryTest.java b/camera/camera-view/src/androidTest/java/androidx/camera/view/TextureViewMeteringPointFactoryTest.java
index 2f9e7c5..3ef79dc 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/TextureViewMeteringPointFactoryTest.java
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/TextureViewMeteringPointFactoryTest.java
@@ -28,9 +28,11 @@
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.util.Size;
+import android.view.Display;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.camera.camera2.Camera2Config;
@@ -94,7 +96,7 @@
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
private FakeLifecycleOwner mLifecycle;
private CountDownLatch mLatchForFrameReady;
- private Context mContext;
+ private Display mDisplay;
private TextureView mTextureView;
private int mWidth;
private int mHeight;
@@ -104,12 +106,15 @@
assumeTrue(CameraUtil.deviceHasCamera());
CoreAppTestUtil.assumeCompatibleDevice();
- mContext = ApplicationProvider.getApplicationContext();
+ Context context = ApplicationProvider.getApplicationContext();
+ WindowManager windowManager =
+ ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE));
+ mDisplay = windowManager.getDefaultDisplay();
CameraXConfig config = Camera2Config.defaultConfig();
- CameraX.initialize(mContext, config);
+ CameraX.initialize(context, config);
mLifecycle = new FakeLifecycleOwner();
mLatchForFrameReady = new CountDownLatch(1);
- mTextureView = new TextureView(mContext);
+ mTextureView = new TextureView(context);
setContentView(mTextureView);
}
@@ -131,7 +136,7 @@
// Creates the DisplayOrientedMeteringPointFactory with same width / height as TextureView
DisplayOrientedMeteringPointFactory displayFactory =
- new DisplayOrientedMeteringPointFactory(mContext, BACK_CAM,
+ new DisplayOrientedMeteringPointFactory(mDisplay, BACK_CAM,
mTextureView.getWidth(), mTextureView.getHeight());
// Uses DisplayOrientedMeteringPointFactory to verify if coordinates are correct.
@@ -150,7 +155,7 @@
// Creates the DisplayOrientedMeteringPointFactory with same width / height as TextureView
DisplayOrientedMeteringPointFactory displayFactory =
- new DisplayOrientedMeteringPointFactory(mContext, FRONT_CAM,
+ new DisplayOrientedMeteringPointFactory(mDisplay, FRONT_CAM,
mWidth, mHeight);
// Uses DisplayOrientedMeteringPointFactory to verify if coordinates are correct.
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/CameraView.java b/camera/camera-view/src/main/java/androidx/camera/view/CameraView.java
index 0dfbf2c..d057c7c 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/CameraView.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/CameraView.java
@@ -799,7 +799,7 @@
if (camera != null) {
ListenableFuture<FocusMeteringResult> future =
camera.getCameraControl().startFocusAndMetering(
- FocusMeteringAction.Builder.from(afPoint,
+ new FocusMeteringAction.Builder(afPoint,
FocusMeteringAction.FLAG_AF).addPoint(aePoint,
FocusMeteringAction.FLAG_AE).build());
Futures.addCallback(future, new FutureCallback<FocusMeteringResult>() {
diff --git a/car-app/OWNERS b/car-app/OWNERS
deleted file mode 100644
index 0ee2ded..0000000
--- a/car-app/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-jorgeper@google.com
-shiufai@google.com
-
diff --git a/car-app/app/api/1.0.0-alpha01.txt b/car-app/app/api/1.0.0-alpha01.txt
deleted file mode 100644
index da4f6cc..0000000
--- a/car-app/app/api/1.0.0-alpha01.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 3.0
diff --git a/car-app/app/api/current.txt b/car-app/app/api/current.txt
deleted file mode 100644
index da4f6cc..0000000
--- a/car-app/app/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 3.0
diff --git a/car-app/app/api/public_plus_experimental_1.0.0-alpha01.txt b/car-app/app/api/public_plus_experimental_1.0.0-alpha01.txt
deleted file mode 100644
index da4f6cc..0000000
--- a/car-app/app/api/public_plus_experimental_1.0.0-alpha01.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 3.0
diff --git a/car-app/app/api/public_plus_experimental_current.txt b/car-app/app/api/public_plus_experimental_current.txt
deleted file mode 100644
index da4f6cc..0000000
--- a/car-app/app/api/public_plus_experimental_current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 3.0
diff --git a/car-app/app/api/restricted_1.0.0-alpha01.txt b/car-app/app/api/restricted_1.0.0-alpha01.txt
deleted file mode 100644
index da4f6cc..0000000
--- a/car-app/app/api/restricted_1.0.0-alpha01.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 3.0
diff --git a/car-app/app/api/restricted_current.txt b/car-app/app/api/restricted_current.txt
deleted file mode 100644
index da4f6cc..0000000
--- a/car-app/app/api/restricted_current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 3.0
diff --git a/car-app/app/build.gradle b/car-app/app/build.gradle
deleted file mode 100644
index a02915c..0000000
--- a/car-app/app/build.gradle
+++ /dev/null
@@ -1,22 +0,0 @@
-import static androidx.build.dependencies.DependenciesKt.*
-import androidx.build.LibraryGroups
-import androidx.build.LibraryVersions
-import androidx.build.Publish
-
-plugins {
- id("AndroidXPlugin")
- id("com.android.library")
-}
-
-dependencies {
- /* Add dependencies here */
-}
-
-androidx {
- name = "AndroidX Car App"
- publish = Publish.SNAPSHOT_ONLY
- mavenVersion = LibraryVersions.CAR_APP
- mavenGroup = LibraryGroups.CAR_APP
- inceptionYear = "2019"
- description = "Library for building navigation apps for Android Auto"
-}
diff --git a/car-app/app/src/androidTest/AndroidManifest.xml b/car-app/app/src/androidTest/AndroidManifest.xml
deleted file mode 100644
index c3e6f73..0000000
--- a/car-app/app/src/androidTest/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.car.app.test">
-</manifest>
\ No newline at end of file
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractCodegenSignatureTest.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractCodegenSignatureTest.kt
new file mode 100644
index 0000000..b4ee9fc
--- /dev/null
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractCodegenSignatureTest.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright 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 androidx.compose.plugins.kotlin
+
+import org.jetbrains.kotlin.backend.common.output.OutputFile
+
+abstract class AbstractCodegenSignatureTest : AbstractCodegenTest() {
+
+ private var isSetup = false
+ override fun setUp() {
+ isSetup = true
+ super.setUp()
+ }
+
+ private fun <T> ensureSetup(block: () -> T): T {
+ if (!isSetup) setUp()
+ return block()
+ }
+
+ private fun OutputFile.printApi(): String {
+ val text = asText()
+ return text
+ .splitToSequence("\n")
+ .filter {
+ if (it.startsWith(" ")) {
+ if (it.startsWith(" ")) false
+ else it[2] != '/' && it[2] != '@'
+ } else {
+ it == "}" || it.endsWith("{")
+ }
+ }
+ .joinToString(separator = "\n")
+ }
+
+ fun checkApi(src: String, expected: String, dumpClasses: Boolean = false): Unit = ensureSetup {
+ val className = "Test_REPLACEME_${uniqueNumber++}"
+ val fileName = "$className.kt"
+
+ val loader = classLoader("""
+ import androidx.compose.*
+
+ $src
+ """, fileName, dumpClasses)
+
+ val apiString = loader
+ .allGeneratedFiles
+ .filter { it.relativePath.endsWith(".class") }
+ .map { it.printApi() }
+ .map { it.replace('$', '%') }
+ .joinToString(separator = "\n")
+ .replace(className, "Test")
+
+ val expectedApiString = expected
+ .trimIndent()
+ .split("\n")
+ .filter { it.isNotBlank() }
+ .joinToString("\n")
+
+ assertEquals(expectedApiString, apiString)
+ }
+
+ fun checkComposerParam(src: String, dumpClasses: Boolean = false) = ensureSetup {
+ testFile(
+ """
+ import androidx.compose.*
+
+ class FakeNode
+ object FakeNodeApplierAdapter :
+ ApplyAdapter<FakeNode> {
+ override fun FakeNode.start(instance: FakeNode) {}
+ override fun FakeNode.insertAt(index: Int, instance: FakeNode) {}
+ override fun FakeNode.removeAt(index: Int, count: Int) {}
+ override fun FakeNode.move(from: Int, to: Int, count: Int) {}
+ override fun FakeNode.end(instance: FakeNode, parent: FakeNode) {}
+ }
+
+ class FakeComposer(
+ val root: FakeNode
+ ) : Composer<FakeNode>(
+ SlotTable(),
+ Applier(root, FakeNodeApplierAdapter),
+ Recomposer.current()
+ )
+
+ fun makeComposer(): Composer<*> {
+ return FakeComposer(FakeNode())
+ }
+
+ fun invokeComposable(composer: Composer<*>, fn: @Composable() () -> Unit) {
+ val realFn = fn as Function1<Composer<*>, Unit>
+ realFn(composer)
+ }
+
+ @Composable fun assertComposer(expected: Composer<*>) {
+ val actual = currentComposerIntrinsic
+ assert(expected === actual)
+ }
+
+ class Test {
+ fun test() { run() }
+ }
+ $src
+ """,
+ dumpClasses
+ )
+ }
+
+ fun codegen(text: String, dumpClasses: Boolean = false): Unit = ensureSetup {
+ codegenNoImports(
+ """
+ import android.content.Context
+ import android.widget.*
+ import androidx.compose.*
+
+ $text
+
+ """, dumpClasses)
+ }
+
+ fun codegenNoImports(text: String, dumpClasses: Boolean = false): Unit = ensureSetup {
+ val className = "Test_${uniqueNumber++}"
+ val fileName = "$className.kt"
+
+ classLoader(text, fileName, dumpClasses)
+ }
+}
\ No newline at end of file
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposeCallLoweringTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposeCallLoweringTests.kt
index 723f700..e6f151a 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposeCallLoweringTests.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposeCallLoweringTests.kt
@@ -827,7 +827,7 @@
fun testComposeWithResult(): Unit = ensureSetup {
compose(
"""
- fun <T> identity(block: @Composable() ()->T): T = block()
+ @Composable fun <T> identity(block: @Composable() ()->T): T = block()
@Composable
fun TestCall() {
@@ -1342,7 +1342,7 @@
@Test
fun testInline_NonComposable_Identity(): Unit = ensureSetup {
compose("""
- inline fun InlineWrapper(base: Int, children: @Composable() ()->Unit) {
+ @Composable inline fun InlineWrapper(base: Int, children: @Composable() ()->Unit) {
children()
}
""",
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposerParamSignatureTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposerParamSignatureTests.kt
new file mode 100644
index 0000000..faba47d
--- /dev/null
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposerParamSignatureTests.kt
@@ -0,0 +1,454 @@
+/*
+ * Copyright 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 androidx.compose.plugins.kotlin
+
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.annotation.Config
+
+@RunWith(ComposeRobolectricTestRunner::class)
+@Config(
+ manifest = Config.NONE,
+ minSdk = 23,
+ maxSdk = 23
+)
+class ComposerParamSignatureTests : AbstractCodegenSignatureTest() {
+
+ @Test
+ fun testCorrectComposerPassed1(): Unit = checkComposerParam(
+ """
+ val a = makeComposer()
+ fun run() {
+ invokeComposable(a) {
+ assertComposer(a)
+ }
+ }
+ """
+ )
+
+ @Test
+ fun testCorrectComposerPassed2(): Unit = checkComposerParam(
+ """
+ val a = makeComposer()
+ @Composable fun Foo() {
+ assertComposer(a)
+ }
+ fun run() {
+ invokeComposable(a) {
+ Foo()
+ }
+ }
+ """
+ )
+
+ @Test
+ fun testCorrectComposerPassed3(): Unit = checkComposerParam(
+ """
+ val a = makeComposer()
+ val b = makeComposer()
+ @Composable fun Callback(fn: () -> Unit) {
+ fn()
+ }
+ fun run() {
+ invokeComposable(a) {
+ assertComposer(a)
+ Callback {
+ invokeComposable(b) {
+ assertComposer(b)
+ }
+ }
+ }
+ }
+ """
+ )
+
+ @Test
+ fun testCorrectComposerPassed4(): Unit = checkComposerParam(
+ """
+ val a = makeComposer()
+ val b = makeComposer()
+ @Composable fun makeInt(): Int {
+ assertComposer(a)
+ return 10
+ }
+ @Composable fun WithDefault(x: Int = makeInt()) {}
+ fun run() {
+ invokeComposable(a) {
+ assertComposer(a)
+ WithDefault()
+ WithDefault(10)
+ }
+ invokeComposable(b) {
+ assertComposer(b)
+ WithDefault(10)
+ }
+ }
+ """
+ )
+
+ @Test
+ fun testCorrectComposerPassed5(): Unit = checkComposerParam(
+ """
+ val a = makeComposer()
+ @Composable fun Wrap(children: @Composable() () -> Unit) {
+ children()
+ }
+ fun run() {
+ invokeComposable(a) {
+ assertComposer(a)
+ Wrap {
+ assertComposer(a)
+ Wrap {
+ assertComposer(a)
+ Wrap {
+ assertComposer(a)
+ }
+ }
+ }
+ }
+ }
+ """
+ )
+
+ @Test
+ fun testDefaultParameters(): Unit = checkApi(
+ """
+ @Composable fun Foo(x: Int = 0) {
+
+ }
+ """,
+ """
+ public final class TestKt {
+ public final static Foo(ILandroidx/compose/Composer;)V
+ public static synthetic Foo%default(ILandroidx/compose/Composer;ILjava/lang/Object;)V
+ }
+ """
+ )
+
+ @Test
+ fun testDefaultExpressionsWithComposableCall(): Unit = checkApi(
+ """
+ @Composable fun <T> identity(value: T): T = value
+ @Composable fun Foo(x: Int = identity(20)) {
+
+ }
+ @Composable fun test() {
+ Foo()
+ Foo(10)
+ }
+ """,
+ """
+ public final class TestKt {
+ public final static identity(Ljava/lang/Object;Landroidx/compose/Composer;)Ljava/lang/Object;
+ public final static Foo(ILandroidx/compose/Composer;)V
+ public static synthetic Foo%default(ILandroidx/compose/Composer;ILjava/lang/Object;)V
+ public final static test(Landroidx/compose/Composer;)V
+ }
+ """
+ )
+
+ @Test
+ fun testBasicCallAndParameterUsage(): Unit = checkApi(
+ """
+ @Composable fun Foo(a: Int, b: String) {
+ print(a)
+ print(b)
+ Bar(a, b)
+ }
+
+ @Composable fun Bar(a: Int, b: String) {
+ print(a)
+ print(b)
+ }
+ """,
+ """
+ public final class TestKt {
+ public final static Foo(ILjava/lang/String;Landroidx/compose/Composer;)V
+ public final static Bar(ILjava/lang/String;Landroidx/compose/Composer;)V
+ }
+ """
+ )
+
+ @Test
+ fun testCallFromInlinedLambda(): Unit = checkApi(
+ """
+ @Composable fun Foo() {
+ listOf(1, 2, 3).forEach { Bar(it) }
+ }
+
+ @Composable fun Bar(a: Int) {}
+ """,
+ """
+ public final class TestKt {
+ public final static Foo(Landroidx/compose/Composer;)V
+ public final static Bar(ILandroidx/compose/Composer;)V
+ }
+ """
+ )
+
+ @Test
+ fun testBasicLambda(): Unit = checkApi(
+ """
+ val foo = @Composable { x: Int -> print(x) }
+ @Composable fun Bar() {
+ foo(123)
+ }
+ """,
+ """
+ public final class TestKt {
+ private final static Lkotlin/jvm/functions/Function2; foo
+ public final static getFoo()Lkotlin/jvm/functions/Function2;
+ public final static Bar(Landroidx/compose/Composer;)V
+ public final static <clinit>()V
+ final static INNERCLASS TestKt%foo%1 null null
+ }
+ final class TestKt%foo%1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function2 {
+ synthetic <init>()V
+ public final invoke(ILandroidx/compose/Composer;)V
+ public synthetic bridge invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+ final static INNERCLASS TestKt%foo%1 null null
+ OUTERCLASS TestKt <clinit> ()V
+ }
+ """
+ )
+
+ @Test
+ fun testLocalLambda(): Unit = checkApi(
+ """
+ @Composable fun Bar(children: @Composable() () -> Unit) {
+ val foo = @Composable { x: Int -> print(x) }
+ foo(123)
+ children()
+ }
+ """,
+ """
+ public final class TestKt {
+ public final static Bar(Lkotlin/jvm/functions/Function1;Landroidx/compose/Composer;)V
+ final static INNERCLASS TestKt%Bar%foo%1 null null
+ }
+ final class TestKt%Bar%foo%1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function2 {
+ synthetic <init>()V
+ public final invoke(ILandroidx/compose/Composer;)V
+ public synthetic bridge invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+ final static INNERCLASS TestKt%Bar%foo%1 null null
+ OUTERCLASS TestKt Bar (Lkotlin/jvm/functions/Function1;Landroidx/compose/Composer;)V
+ }
+ """
+ )
+
+ @Test
+ fun testNesting(): Unit = checkApi(
+ """
+ @Composable fun Wrap(children: @Composable() (x: Int) -> Unit) {
+ children(123)
+ }
+ @Composable fun App(x: Int) {
+ print(x)
+ Wrap { a ->
+ print(a)
+ print(x)
+ Wrap { b ->
+ print(x)
+ print(a)
+ print(b)
+ }
+ }
+ }
+ """,
+ """
+ public final class TestKt {
+ public final static Wrap(Lkotlin/jvm/functions/Function2;Landroidx/compose/Composer;)V
+ public final static App(ILandroidx/compose/Composer;)V
+ final static INNERCLASS TestKt%App%1 null null
+ }
+ final class TestKt%App%1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function2 {
+ synthetic <init>(I)V
+ public final invoke(ILandroidx/compose/Composer;)V
+ private final synthetic I %x
+ public synthetic bridge invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+ final static INNERCLASS TestKt%App%1%1 null null
+ final static INNERCLASS TestKt%App%1 null null
+ OUTERCLASS TestKt App (ILandroidx/compose/Composer;)V
+ }
+ final class TestKt%App%1%1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function2 {
+ synthetic <init>(II)V
+ public final invoke(ILandroidx/compose/Composer;)V
+ private final synthetic I %x
+ private final synthetic I %a
+ public synthetic bridge invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+ final static INNERCLASS TestKt%App%1%1 null null
+ final static INNERCLASS TestKt%App%1 null null
+ OUTERCLASS TestKt%App%1 invoke (ILandroidx/compose/Composer;)V
+ }
+ """
+ )
+
+ @Test
+ fun testComposableInterface(): Unit = checkApi(
+ """
+ interface Foo {
+ @Composable fun bar()
+ }
+
+ class FooImpl : Foo {
+ @Composable override fun bar() {}
+ }
+ """,
+ """
+ public abstract interface Foo {
+ public abstract bar(Landroidx/compose/Composer;)V
+ }
+ public final class FooImpl implements Foo {
+ public <init>()V
+ public bar(Landroidx/compose/Composer;)V
+ }
+ """
+ )
+
+ @Test
+ fun testAbstractComposable(): Unit = checkApi(
+ """
+ abstract class BaseFoo {
+ @Composable abstract fun bar()
+ }
+
+ class FooImpl : BaseFoo() {
+ @Composable override fun bar() {}
+ }
+ """,
+ """
+ public abstract class BaseFoo {
+ public <init>()V
+ public abstract bar(Landroidx/compose/Composer;)V
+ }
+ public final class FooImpl extends BaseFoo {
+ public <init>()V
+ public bar(Landroidx/compose/Composer;)V
+ }
+ """
+ )
+
+ @Test
+ fun testLocalClassAndObjectLiterals(): Unit = checkApi(
+ """
+ @Composable
+ fun Wat() {}
+
+ @Composable
+ fun Foo(x: Int) {
+ Wat()
+ @Composable fun goo() { Wat() }
+ class Bar {
+ @Composable fun baz() { Wat() }
+ }
+ goo()
+ Bar().baz()
+ }
+ """,
+ """
+ public final class TestKt {
+ public final static Wat(Landroidx/compose/Composer;)V
+ public final static Foo(ILandroidx/compose/Composer;)V
+ private final static Foo%goo(Landroidx/compose/Composer;)V
+ public final static INNERCLASS TestKt%Foo%Bar null Bar
+ }
+ public final class TestKt%Foo%Bar {
+ <init>()V
+ public final baz(Landroidx/compose/Composer;)V
+ public final static INNERCLASS TestKt%Foo%Bar null Bar
+ OUTERCLASS TestKt Foo (ILandroidx/compose/Composer;)V
+ }
+ """
+ )
+
+ @Test
+ fun testNonComposableCode(): Unit = checkApi(
+ """
+ fun A() {}
+ val b: Int get() = 123
+ fun C(x: Int) {
+ var x = 0
+ x++
+
+ class D {
+ fun E() { A() }
+ val F: Int get() = 123
+ }
+ val g = object { fun H() {} }
+ }
+ fun I(block: () -> Unit) { block() }
+ fun J() {
+ I {
+ I {
+ A()
+ }
+ }
+ }
+ """,
+ """
+ public final class TestKt {
+ public final static A()V
+ public final static getB()I
+ public final static C(I)V
+ public final static I(Lkotlin/jvm/functions/Function0;)V
+ public final static J()V
+ public final static INNERCLASS TestKt%C%D null D
+ public final static INNERCLASS TestKt%C%g%1 null null
+ final static INNERCLASS TestKt%J%1 null null
+ }
+ public final class TestKt%C%D {
+ <init>()V
+ public final E()V
+ public final getF()I
+ public final static INNERCLASS TestKt%C%D null D
+ OUTERCLASS TestKt C (I)V
+ }
+ public final class TestKt%C%g%1 {
+ <init>()V
+ public final H()V
+ public final static INNERCLASS TestKt%C%g%1 null null
+ OUTERCLASS TestKt C (I)V
+ }
+ final class TestKt%J%1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function0 {
+ synthetic <init>()V
+ public final invoke()V
+ public synthetic bridge invoke()Ljava/lang/Object;
+ final static INNERCLASS TestKt%J%1%1 null null
+ final static INNERCLASS TestKt%J%1 null null
+ OUTERCLASS TestKt J ()V
+ }
+ final class TestKt%J%1%1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function0 {
+ synthetic <init>()V
+ public final invoke()V
+ public synthetic bridge invoke()Ljava/lang/Object;
+ final static INNERCLASS TestKt%J%1%1 null null
+ final static INNERCLASS TestKt%J%1 null null
+ OUTERCLASS TestKt%J%1 invoke ()V
+ }
+ """
+ )
+
+ override fun setUp() {
+ ComposeFlags.COMPOSER_PARAM = true
+ super.setUp()
+ }
+
+ override fun tearDown() {
+ super.tearDown()
+ ComposeFlags.COMPOSER_PARAM = false
+ }
+}
\ No newline at end of file
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/FcsCodegenTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/FcsCodegenTests.kt
index 16289bc..b3645e7 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/FcsCodegenTests.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/FcsCodegenTests.kt
@@ -236,7 +236,7 @@
fun testComposeWithResult(): Unit = ensureSetup {
compose(
"""
- fun <T> identity(block: @Composable() ()->T): T = block()
+ @Composable fun <T> identity(block: @Composable() ()->T): T = block()
@Composable
fun TestCall() {
@@ -793,7 +793,7 @@
@Test
fun testInline_NonComposable_Identity(): Unit = ensureSetup {
compose("""
- inline fun InlineWrapper(base: Int, children: @Composable() ()->Unit) {
+ @Composable inline fun InlineWrapper(base: Int, children: @Composable() ()->Unit) {
children()
}
""",
@@ -1659,7 +1659,7 @@
fun testImplicitReceiverPassing1(): Unit = ensureSetup {
compose(
"""
- fun Int.Foo(x: @Composable() Int.() -> Unit) {
+ @Composable fun Int.Foo(x: @Composable() Int.() -> Unit) {
x()
}
""",
@@ -1681,16 +1681,20 @@
fun testImplicitReceiverPassing2(): Unit = ensureSetup {
compose(
"""
- fun Int.Foo(x: @Composable() Int.(text: String) -> Unit, text: String) {
+ @Composable fun Int.Foo(x: @Composable() Int.(text: String) -> Unit, text: String) {
x(text=text)
}
+
+ @Composable fun MyText(text: String, id: Int) {
+ TextView(text=text, id=id)
+ }
""",
{ mapOf<String, String>() },
"""
val id = 42
id.Foo(text="Hello, world!", x={ text ->
- TextView(text=text, id=this)
+ MyText(text=text, id=this)
})
"""
).then { activity ->
@@ -2332,7 +2336,7 @@
var output = ArrayList<String>()
class NotStable { val value = 10 }
-
+
@Stable
class StableClass {
override fun equals(other: Any?) = true
@@ -2343,6 +2347,9 @@
Two
}
+ val mutableStateType = mutableStateOf(1)
+ val stateType: State<Int> = mutableStateType
+
@Composable
fun MemoInt(a: Int) {
output.add("MemoInt a=${'$'}a")
@@ -2378,7 +2385,7 @@
output.add("MemoEnum")
Button(text="memo ${'$'}{a}")
}
-
+
@Composable
fun MemoStable(a: StableClass) {
output.add("MemoStable")
@@ -2386,6 +2393,18 @@
}
@Composable
+ fun MemoMutableState(a: MutableState<Int>) {
+ output.add("MemoMutableState")
+ Button(text="memo ${'$'}{a.value}")
+ }
+
+ @Composable
+ fun MemoState(a: State<Int>) {
+ output.add("MemoState")
+ Button(text="memo ${'$'}{a.value}")
+ }
+
+ @Composable
fun TestSkipping(
a: Int,
b: Float,
@@ -2393,7 +2412,9 @@
d: NotStable,
e: ValueHolder,
f: EnumState,
- g: StableClass
+ g: StableClass,
+ h: MutableState<Int>,
+ i: State<Int>
) {
val am = a + m.count
output.add("TestSkipping a=${'$'}a am=${'$'}am")
@@ -2404,11 +2425,23 @@
MemoModel(a=e)
MemoEnum(a=f)
MemoStable(a=g)
+ MemoMutableState(h)
+ MemoState(i)
}
@Composable
fun Main(v: ValueHolder, n: NotStable) {
- TestSkipping(a=1, b=1f, c=2.0, d=NotStable(), e=v, f=EnumState.One, g=StableClass())
+ TestSkipping(
+ a=1,
+ b=1f,
+ c=2.0,
+ d=NotStable(),
+ e=v,
+ f=EnumState.One,
+ g=StableClass(),
+ h=mutableStateType,
+ i=stateType
+ )
}
""", {
mapOf(
@@ -2422,7 +2455,8 @@
// Expect that all the methods are called in order
assertEquals(
"TestSkipping a=1 am=1, MemoInt a=1, MemoFloat, " +
- "MemoDouble, MemoNotStable, MemoModelHolder, MemoEnum, MemoStable",
+ "MemoDouble, MemoNotStable, MemoModelHolder, MemoEnum, MemoStable, " +
+ "MemoMutableState, MemoState",
output.joinToString()
)
output.clear()
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxModelCodeGenTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxModelCodeGenTests.kt
index b031da3..69db8df 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxModelCodeGenTests.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxModelCodeGenTests.kt
@@ -306,6 +306,7 @@
class $className {
+ @Composable
fun compose() {
$composition
}
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxTransformationTest.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxTransformationTest.kt
index f4a2054..c6839f1 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxTransformationTest.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxTransformationTest.kt
@@ -234,6 +234,7 @@
"""
)
+ // NOTE(lmr): I'm not sure this is a pattern we can support long term...
fun testFunctionInstanceZeroArgs() = testCompile(
"""
import androidx.compose.*
@@ -245,6 +246,7 @@
@Composable
operator fun invoke() {
val foo = object: Function0<Unit> {
+ @Composable
override fun invoke() {
Bar()
}
@@ -422,6 +424,7 @@
}
}
+ @Composable
fun doStuff() {
val a = A(123)
@@ -506,6 +509,7 @@
@Composable
fun Simple() {}
+ @Composable
fun run() {
val foo = @Composable { Simple() }
foo()
@@ -564,6 +568,7 @@
}
+ @Composable
fun run(text: String) {
Example {
println("hello ${"$"}text")
@@ -609,6 +614,7 @@
import androidx.compose.*
import android.widget.TextView
+ @Composable
fun foo() {
val lambda = @Composable { }
for(x in 1..5) {
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ScopeComposabilityTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ScopeComposabilityTests.kt
new file mode 100644
index 0000000..5f640a82
--- /dev/null
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ScopeComposabilityTests.kt
@@ -0,0 +1,227 @@
+/*
+ * Copyright 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 androidx.compose.plugins.kotlin
+
+import androidx.compose.plugins.kotlin.analysis.ComposeWritableSlices
+import androidx.compose.plugins.kotlin.ComposableAnnotationChecker.Composability
+import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.psi.KtElement
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.psi.KtFunction
+import org.jetbrains.kotlin.psi.KtFunctionLiteral
+import org.jetbrains.kotlin.psi.KtLambdaExpression
+import org.jetbrains.kotlin.psi.KtProperty
+import org.jetbrains.kotlin.psi.KtPropertyAccessor
+import org.jetbrains.kotlin.psi.KtPsiFactory
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
+import org.junit.Ignore
+
+class ScopeComposabilityTests : AbstractCodegenTest() {
+
+ fun testNormalFunctions() = assertComposability(
+ """
+ import androidx.compose.*
+
+ fun Foo() {
+ <normal>
+ }
+ class Bar {
+ fun bam() { <normal> }
+ val baz: Int get() { <normal>return 123 }
+ }
+ """
+ )
+
+ fun testPropGetter() = assertComposability(
+ """
+ import androidx.compose.*
+
+ val baz: Int get() { <normal>return 123 }
+ """
+ )
+
+ fun testBasicComposable() = assertComposability(
+ """
+ import androidx.compose.*
+
+ @Composable
+ fun Foo() {
+ <marked>
+ }
+ """
+ )
+
+ fun testBasicComposable2() = assertComposability(
+ """
+ import androidx.compose.*
+
+ val foo = @Composable { <marked> }
+
+ @Composable
+ fun Bar() {
+ <marked>
+ fun bam() { <normal> }
+ val x = { <normal> }
+ val y = @Composable { <marked> }
+ @Composable fun z() { <marked> }
+ }
+ """
+ )
+
+ // TODO(b/147250515): get inlined lambdas to analyze correctly
+ fun xtestBasicComposable3() = assertComposability(
+ """
+ import androidx.compose.*
+
+ @Composable
+ fun Bar() {
+ <marked>
+ listOf(1, 2, 3).forEach {
+ <inferred> // should be inferred, but is normal
+ }
+ }
+ """
+ )
+
+ fun testBasicComposable4() = assertComposability(
+ """
+ import androidx.compose.*
+
+ @Composable fun Wrap(block: @Composable() () -> Unit) { block() }
+
+ @Composable
+ fun Bar() {
+ <marked>
+ Wrap {
+ <marked>
+ Wrap {
+ <marked>
+ }
+ }
+ }
+ """
+ )
+
+ fun testBasicComposable5() = assertComposability(
+ """
+ import androidx.compose.*
+
+ @Composable fun Callback(block: () -> Unit) { block() }
+
+ @Composable
+ fun Bar() {
+ <marked>
+ Callback {
+ <normal>
+ }
+ }
+ """
+ )
+
+ fun testBasicComposable6() = assertComposability(
+ """
+ import androidx.compose.*
+
+ fun kickOff(block: @Composable() () -> Unit) { }
+
+ fun Bar() {
+ <normal>
+ kickOff {
+ <marked>
+ }
+ }
+ """
+ )
+
+ private fun <T> setup(block: () -> T): T {
+ return block()
+ }
+
+ fun assertComposability(srcText: String) = setup {
+ val (text, carets) = extractCarets(srcText)
+
+ val environment = myEnvironment ?: error("Environment not initialized")
+
+ val ktFile = KtPsiFactory(environment.project).createFile(text)
+ val bindingContext = JvmResolveUtil.analyze(
+ ktFile,
+ environment
+ ).bindingContext
+
+ carets.forEachIndexed { index, (offset, marking) ->
+ val composability = composabiliityAtOffset(bindingContext, ktFile, offset)
+ ?: error("composability not found for index: $index, offset: $offset. Expected " +
+ "$marking.")
+
+ when (marking) {
+ "<marked>" -> assertEquals("index: $index", Composability.MARKED, composability)
+ "<inferred>" -> assertEquals("index: $index", Composability.INFERRED, composability)
+ "<normal>" -> assertEquals(
+ "index: $index",
+ Composability.NOT_COMPOSABLE,
+ composability
+ )
+ else -> error("Composability of $marking not recognized.")
+ }
+ }
+ }
+
+ private val callPattern = Regex("(<marked>)|(<inferred>)|(<normal>)")
+ private fun extractCarets(text: String): Pair<String, List<Pair<Int, String>>> {
+ val indices = mutableListOf<Pair<Int, String>>()
+ var offset = 0
+ val src = callPattern.replace(text) {
+ indices.add(it.range.first - offset to it.value)
+ offset += it.range.last - it.range.first + 1
+ ""
+ }
+ return src to indices
+ }
+
+ private fun composabiliityAtOffset(
+ bindingContext: BindingContext,
+ jetFile: KtFile,
+ index: Int
+ ): Composability? {
+ val element = jetFile.findElementAt(index)!!
+ return element.getNearestComposability(bindingContext)
+ }
+}
+
+fun PsiElement?.getNearestComposability(
+ bindingContext: BindingContext
+): Composability? {
+ var node: PsiElement? = this
+ while (node != null) {
+ when (node) {
+ is KtFunctionLiteral -> {
+ // keep going, as this is a "KtFunction", but we actually want the
+ // KtLambdaExpression
+ }
+ is KtLambdaExpression,
+ is KtFunction,
+ is KtPropertyAccessor,
+ is KtProperty -> {
+ val el = node as KtElement
+ return bindingContext.get(ComposeWritableSlices.COMPOSABLE_ANALYSIS, el)
+ }
+ }
+ node = node.parent as? KtElement
+ }
+ return null
+}
\ No newline at end of file
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/frames/FrameDiagnosticTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/frames/FrameDiagnosticTests.kt
index a6d667a..5153f6c 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/frames/FrameDiagnosticTests.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/frames/FrameDiagnosticTests.kt
@@ -53,4 +53,19 @@
}
"""
)
+
+ fun testModel_Report_Nested_Inheritance() = doTest(
+ """
+ import androidx.compose.Model
+
+ open class NonModel { }
+
+ class Tests {
+ @Model
+ class <!UNSUPPORTED_MODEL_INHERITANCE!>MyModel<!> : NonModel() {
+ var strValue = "default"
+ }
+ }
+ """
+ )
}
\ No newline at end of file
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/frames/FrameTransformExtensionTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/frames/FrameTransformExtensionTests.kt
index 32ab859..1d8a038 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/frames/FrameTransformExtensionTests.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/frames/FrameTransformExtensionTests.kt
@@ -309,6 +309,33 @@
}
""")
+ fun testModel_NestedClass() = testFile("""
+ import androidx.compose.Model
+
+ class Test {
+ @Model
+ class MyModel {
+ var value: String = "default"
+ }
+
+ fun test() {
+ val instance = frame { MyModel() }
+ val frame1 = suspended {
+ instance.value = "new value"
+ }
+ frame {
+ instance.value.expectEqual("default")
+ }
+ restored(frame1) {
+ instance.value.expectEqual("new value")
+ }
+ frame {
+ instance.value.expectEqual("new value")
+ }
+ }
+ }
+ """)
+
override fun helperFiles(): List<KtFile> = listOf(sourceFile("Helpers.kt",
HELPERS
))
@@ -349,11 +376,11 @@
}
fun Any.expectEqual(expected: Any) {
- expect(this, expected)
+ expect(expected, this)
}
fun expect(expected: Any, received: Any) {
if (expected != received) {
- throw Exception("Expected ${'$'}expected but received ${'$'}received")
+ throw Exception("Expected \"${'$'}expected\" but received \"${'$'}received\"")
}
}"""
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposableAnnotationChecker.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposableAnnotationChecker.kt
index cb431f7..90495b6 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposableAnnotationChecker.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposableAnnotationChecker.kt
@@ -128,8 +128,7 @@
return candidateDescriptor.type.hasComposableAnnotation()
}
if (candidateDescriptor is PropertyDescriptor) {
- return candidateDescriptor.hasComposableAnnotation() ||
- candidateDescriptor.type.hasComposableAnnotation()
+ return candidateDescriptor.hasComposableAnnotation()
}
return candidateDescriptor.hasComposableAnnotation()
}
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeFlags.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeFlags.kt
index ac6a98f..075eeed 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeFlags.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeFlags.kt
@@ -19,4 +19,5 @@
object ComposeFlags {
var FRAMED_COMPONENTS = false
var FRAMED_MODEL_CLASSES = true
+ var COMPOSER_PARAM = false
}
\ No newline at end of file
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeFqNames.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeFqNames.kt
index 1d30be4..436bc43 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeFqNames.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeFqNames.kt
@@ -34,9 +34,11 @@
object ComposeFqNames {
val Composable = ComposeUtils.composeFqName("Composable")
+ val CurrentComposerIntrinsic = ComposeUtils.composeFqName("<get-currentComposerIntrinsic>")
val Pivotal = ComposeUtils.composeFqName("Pivotal")
val StableMarker = ComposeUtils.composeFqName("StableMarker")
val HiddenAttribute = ComposeUtils.composeFqName("HiddenAttribute")
+ val Composer = ComposeUtils.composeFqName("Composer")
val Package = FqName.fromSegments(listOf("androidx", "compose"))
val Function0 = FqName.fromSegments(listOf("kotlin", "jvm", "functions", "Function0"))
fun makeComposableAnnotation(module: ModuleDescriptor): AnnotationDescriptor =
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeIrLoweringExtension.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeIrLoweringExtension.kt
index c766875..8713ad9 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeIrLoweringExtension.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeIrLoweringExtension.kt
@@ -22,6 +22,8 @@
import org.jetbrains.kotlin.backend.jvm.extensions.IrLoweringExtension
import androidx.compose.plugins.kotlin.compiler.lower.ComposableCallTransformer
import androidx.compose.plugins.kotlin.compiler.lower.ComposeObservePatcher
+import androidx.compose.plugins.kotlin.compiler.lower.ComposerIntrinsicTransformer
+import androidx.compose.plugins.kotlin.compiler.lower.ComposerParamTransformer
import androidx.compose.plugins.kotlin.frames.FrameIrTransformer
import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
@@ -44,10 +46,27 @@
description = "Rewrite FCS descriptors to IR bytecode"
)
+val ComposerParameterPhase = makeIrModulePhase(
+ ::ComposerParamTransformer,
+ name = "ComposerParameterPhase",
+ description = "Transform @Composable functions to have extra Composer parameter"
+)
+
+val ComposerIntrinsicPhase = makeIrModulePhase(
+ ::ComposerIntrinsicTransformer,
+ name = "ComposerIntrinsicPhase",
+ description = "Replace @Composable intrinsics with their correct values"
+)
+
class ComposeIrLoweringExtension : IrLoweringExtension {
override fun interceptLoweringPhases(
phases: CompilerPhase<JvmBackendContext, IrModuleFragment, IrModuleFragment>
): CompilerPhase<JvmBackendContext, IrModuleFragment, IrModuleFragment> {
+ if (ComposeFlags.COMPOSER_PARAM) {
+ return ComposerParameterPhase then
+ ComposerIntrinsicPhase then
+ phases
+ }
return FrameClassGenPhase then
ComposeCallPhase then
ComposeObservePhase then
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeSyntheticIrExtension.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeSyntheticIrExtension.kt
index dcbb51d..92fc9fe 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeSyntheticIrExtension.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeSyntheticIrExtension.kt
@@ -84,6 +84,7 @@
statementGenerator: StatementGenerator,
element: KtCallExpression
): IrExpression? {
+ if (ComposeFlags.COMPOSER_PARAM) return null
val resolvedCall = statementGenerator.getResolvedCall(element)
?: return ErrorExpressionGenerator(statementGenerator).generateErrorCall(element)
@@ -113,6 +114,7 @@
statementGenerator: StatementGenerator,
element: KtSimpleNameExpression
): IrExpression? {
+ if (ComposeFlags.COMPOSER_PARAM) return null
val resolvedCall = statementGenerator.getResolvedCall(element)
?: return super.visitSimpleNameExpression(statementGenerator, element)
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/KtxNameConventions.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/KtxNameConventions.kt
index 832b72c..7ce6d4dc 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/KtxNameConventions.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/KtxNameConventions.kt
@@ -4,6 +4,8 @@
object KtxNameConventions {
val COMPOSER = Name.identifier("composer")
+ val COMPOSER_PARAMETER = Name.identifier("\$composer")
+ val CURRENT_COMPOSER_INTRINSIC = Name.special("<get-currentComposerIntrinsic>")
val EMIT = Name.identifier("emit")
val CALL = Name.identifier("call")
val START_EXPR = Name.identifier("startExpr")
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeErrors.java b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeErrors.java
index 1c6b1a5..5ac1306 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeErrors.java
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeErrors.java
@@ -39,7 +39,7 @@
DiagnosticFactory0<KtElement>
SUSPEND_FUNCTION_USED_AS_SFC = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement>
- COMPOSABLE_INVOCATION_IN_NON_COMPOSABLE = DiagnosticFactory0.create(WARNING);
+ COMPOSABLE_INVOCATION_IN_NON_COMPOSABLE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtElement>
INVALID_TYPE_SIGNATURE_SFC = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtElement>
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposerIntrinsicTransformer.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposerIntrinsicTransformer.kt
new file mode 100644
index 0000000..3783949
--- /dev/null
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposerIntrinsicTransformer.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 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 androidx.compose.plugins.kotlin.compiler.lower
+
+import androidx.compose.plugins.kotlin.ComposeFqNames
+import org.jetbrains.kotlin.backend.common.FileLoweringPass
+import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
+import org.jetbrains.kotlin.ir.declarations.IrFile
+import org.jetbrains.kotlin.ir.expressions.IrCall
+import org.jetbrains.kotlin.ir.expressions.IrExpression
+import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
+
+class ComposerIntrinsicTransformer(val context: JvmBackendContext) :
+ IrElementTransformerVoid(),
+ FileLoweringPass {
+
+ override fun lower(irFile: IrFile) {
+ irFile.transformChildrenVoid(this)
+ }
+
+ override fun visitCall(expression: IrCall): IrExpression {
+ if (expression.descriptor.fqNameSafe == ComposeFqNames.CurrentComposerIntrinsic) {
+ // since this call was transformed by the ComposerParamTransformer, the first argument
+ // to this call is the composer itself. We just replace this expression with the
+ // argument expression and we are good.
+ assert(expression.valueArgumentsCount == 1)
+ val composerExpr = expression.getValueArgument(0)
+ if (composerExpr == null) error("Expected non-null composer argument")
+ return composerExpr
+ }
+ return super.visitCall(expression)
+ }
+}
\ No newline at end of file
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposerParamTransformer.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposerParamTransformer.kt
new file mode 100644
index 0000000..c4f8080
--- /dev/null
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposerParamTransformer.kt
@@ -0,0 +1,425 @@
+/*
+ * Copyright 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 androidx.compose.plugins.kotlin.compiler.lower
+
+import androidx.compose.plugins.kotlin.ComposableAnnotationChecker
+import androidx.compose.plugins.kotlin.ComposeFqNames
+import androidx.compose.plugins.kotlin.KtxNameConventions
+import org.jetbrains.kotlin.backend.common.FileLoweringPass
+import org.jetbrains.kotlin.backend.common.descriptors.WrappedFunctionDescriptorWithContainerSource
+import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
+import org.jetbrains.kotlin.backend.common.ir.copyTo
+import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
+import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
+import org.jetbrains.kotlin.ir.IrStatement
+import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
+import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
+import org.jetbrains.kotlin.ir.declarations.IrDeclaration
+import org.jetbrains.kotlin.ir.declarations.IrFile
+import org.jetbrains.kotlin.ir.declarations.IrFunction
+import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
+import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer
+import org.jetbrains.kotlin.ir.declarations.IrValueParameter
+import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
+import org.jetbrains.kotlin.ir.expressions.IrCall
+import org.jetbrains.kotlin.ir.expressions.IrExpression
+import org.jetbrains.kotlin.ir.expressions.IrGetValue
+import org.jetbrains.kotlin.ir.expressions.IrReturn
+import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
+import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
+import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
+import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
+import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
+import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
+import org.jetbrains.kotlin.ir.types.IrSimpleType
+import org.jetbrains.kotlin.ir.types.IrType
+import org.jetbrains.kotlin.ir.types.toKotlinType
+import org.jetbrains.kotlin.ir.util.ConstantValueGenerator
+import org.jetbrains.kotlin.ir.util.DeepCopyIrTreeWithSymbols
+import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper
+import org.jetbrains.kotlin.ir.util.TypeRemapper
+import org.jetbrains.kotlin.ir.util.TypeTranslator
+import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
+import org.jetbrains.kotlin.ir.util.dump
+import org.jetbrains.kotlin.ir.util.explicitParameters
+import org.jetbrains.kotlin.ir.util.hasAnnotation
+import org.jetbrains.kotlin.ir.util.isFunction
+import org.jetbrains.kotlin.ir.util.patchDeclarationParents
+import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.acceptVoid
+import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
+import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.psi.KtFunctionLiteral
+import org.jetbrains.kotlin.psi2ir.findFirstFunction
+import org.jetbrains.kotlin.resolve.inline.InlineUtil
+import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.TypeProjectionImpl
+import org.jetbrains.kotlin.types.replace
+import org.jetbrains.kotlin.util.OperatorNameConventions
+
+private const val DEBUG_LOG = false
+
+class ComposerParamTransformer(val context: JvmBackendContext) :
+ IrElementTransformerVoid(),
+ FileLoweringPass {
+
+ private val transformedFunctions: MutableMap<IrFunction, IrFunction>
+ get() = context.suspendFunctionViews
+
+ private val transformedFunctionSet = mutableSetOf<IrFunction>()
+
+ private val composableChecker = ComposableAnnotationChecker()
+
+ private val typeTranslator =
+ TypeTranslator(
+ context.ir.symbols.externalSymbolTable,
+ context.state.languageVersionSettings,
+ context.builtIns
+ ).apply {
+ constantValueGenerator = ConstantValueGenerator(
+ context.state.module,
+ context.ir.symbols.externalSymbolTable
+ )
+ constantValueGenerator.typeTranslator = this
+ }
+
+ private val builtIns = context.irBuiltIns
+
+ private fun KotlinType.toIrType(): IrType = typeTranslator.translateType(this)
+
+ private val composerTypeDescriptor = context.state.module.findClassAcrossModuleDependencies(
+ ClassId.topLevel(ComposeFqNames.Composer)
+ ) ?: error("Cannot find the Composer class")
+
+ private val composerType = composerTypeDescriptor.defaultType.toIrType()
+
+ override fun lower(irFile: IrFile) {
+ if (DEBUG_LOG) {
+ println("""
+ =========
+ BEFORE
+ =========
+ """.trimIndent())
+ println(irFile.dump())
+ }
+ irFile.transformChildrenVoid(this)
+ if (DEBUG_LOG) {
+ println("""
+ =========
+ AFTER TRANSFORM
+ =========
+ """.trimIndent())
+ println(irFile.dump())
+ }
+ val symbolRemapper = DeepCopySymbolRemapper()
+ irFile.acceptVoid(symbolRemapper)
+ irFile.transformChildren(
+ DeepCopyIrTreeWithSymbols(
+ symbolRemapper,
+ ComposerTypeRemapper(context, typeTranslator, composerTypeDescriptor)
+ ),
+ null
+ )
+ irFile.patchDeclarationParents()
+ if (DEBUG_LOG) {
+ println("""
+ =========
+ AFTER TYPE REMAPPING
+ =========
+ """.trimIndent())
+ println(irFile.dump())
+ }
+ }
+
+ override fun visitFunction(declaration: IrFunction): IrStatement {
+ return super.visitFunction(declaration.withComposerParamIfNeeded())
+ }
+
+ fun IrCall.withComposerParamIfNeeded(composerParam: IrValueParameter): IrCall {
+ val isComposableLambda = isComposableLambdaInvoke()
+ if (!descriptor.isComposable() && !isComposableLambda)
+ return this
+ val ownerFn = when {
+ isComposableLambda ->
+ (symbol.owner as IrSimpleFunction).lambdaInvokeWithComposerParamIfNeeded()
+ else -> (symbol.owner as IrSimpleFunction).withComposerParamIfNeeded()
+ }
+ if (!transformedFunctionSet.contains(ownerFn))
+ return this
+ if (symbol.owner == ownerFn)
+ return this
+ return IrCallImpl(
+ startOffset,
+ endOffset,
+ type,
+ ownerFn.symbol
+ ).also {
+ it.copyTypeArgumentsFrom(this)
+ it.dispatchReceiver = dispatchReceiver
+ it.extensionReceiver = extensionReceiver
+ for (i in 0 until valueArgumentsCount) {
+ it.putValueArgument(i, getValueArgument(i))
+ }
+ it.putValueArgument(
+ valueArgumentsCount,
+ IrGetValueImpl(
+ UNDEFINED_OFFSET,
+ UNDEFINED_OFFSET,
+ composerParam.symbol
+ )
+ )
+ }
+ }
+
+ // Transform `@Composable fun foo(params): RetType` into `fun foo(params, $composer: Composer): RetType`
+ fun IrFunction.withComposerParamIfNeeded(): IrFunction {
+ // don't transform functions that themselves were produced by this function. (ie, if we
+ // call this with a function that has the synthetic composer parameter, we don't want to
+ // transform it further).
+ if (transformedFunctionSet.contains(this)) return this
+
+ // if not a composable fn, nothing we need to do
+ if (!descriptor.isComposable()) return this
+
+ // TODO(lmr): it looks like inlined non-composable lambdas are getting marked as
+ // composable by the ComposableAnnotationChecker. This makes this line a requirement for
+ // two reasons instead of one. We should fix this.
+ if (isInlinedLambda()) return this
+
+ // cache the transformed function with composer parameter
+ return transformedFunctions.getOrPut(this) {
+ copyWithComposerParam().also { transformedFunctionSet.add(it) }
+ }
+ }
+
+ fun IrFunction.lambdaInvokeWithComposerParamIfNeeded(): IrFunction {
+ if (transformedFunctionSet.contains(this)) return this
+ return transformedFunctions.getOrPut(this) {
+ lambdaInvokeWithComposerParam().also { transformedFunctionSet.add(it) }
+ }
+ }
+
+ fun IrFunction.lambdaInvokeWithComposerParam(): IrFunction {
+ val descriptor = descriptor
+ val argCount = descriptor.valueParameters.size
+ val newFnClass = context.irIntrinsics.symbols.getFunction(argCount + 1)
+ val newDescriptor = newFnClass.descriptor.unsubstitutedMemberScope.findFirstFunction(
+ OperatorNameConventions.INVOKE.identifier
+ ) { true }
+
+ return IrFunctionImpl(
+ startOffset,
+ endOffset,
+ origin,
+ newDescriptor,
+ newDescriptor.returnType?.toIrType()!!
+ ).also { fn ->
+ fn.parent = newFnClass.owner
+
+ fn.copyTypeParametersFrom(this)
+ fn.dispatchReceiverParameter = dispatchReceiverParameter?.copyTo(fn)
+ fn.extensionReceiverParameter = extensionReceiverParameter?.copyTo(fn)
+ newDescriptor.valueParameters.forEach { p ->
+ fn.addValueParameter(p.name.identifier, p.type.toIrType())
+ }
+ assert(fn.body == null) { "expected body to be null" }
+ }
+ }
+
+ private fun IrFunction.copy(): IrFunction {
+ // TODO(lmr): use deepCopy instead?
+ val descriptor = descriptor
+
+ val containerSource = (descriptor as? DescriptorWithContainerSource)?.containerSource
+ val newDescriptor = if (containerSource != null)
+ WrappedFunctionDescriptorWithContainerSource(containerSource)
+ else
+ WrappedSimpleFunctionDescriptor(sourceElement = descriptor.source)
+
+ return IrFunctionImpl(
+ startOffset,
+ endOffset,
+ origin,
+ IrSimpleFunctionSymbolImpl(newDescriptor),
+ name,
+ visibility,
+ descriptor.modality,
+ returnType,
+ isInline,
+ isExternal,
+ descriptor.isTailrec,
+ descriptor.isSuspend
+ ).also { fn ->
+ newDescriptor.bind(fn)
+ fn.parent = parent
+ fn.copyTypeParametersFrom(this)
+ fn.dispatchReceiverParameter = dispatchReceiverParameter?.copyTo(fn)
+ fn.extensionReceiverParameter = extensionReceiverParameter?.copyTo(fn)
+ valueParameters.mapTo(fn.valueParameters) { p -> p.copyTo(fn) }
+ fn.body = body?.deepCopyWithSymbols(this)
+ }
+ }
+
+ private fun IrFunction.copyWithComposerParam(): IrFunction {
+ assert(explicitParameters.lastOrNull()?.name != KtxNameConventions.COMPOSER_PARAMETER) {
+ "Attempted to add composer param to $this, but it has already been added."
+ }
+ return copy().also { fn ->
+ val oldFn = this
+ val valueParametersMapping = explicitParameters
+ .zip(fn.explicitParameters)
+ .toMap()
+
+ val composerParam = fn.addValueParameter(
+ KtxNameConventions.COMPOSER_PARAMETER.identifier,
+ composerType
+ )
+ fn.transformChildrenVoid(object : IrElementTransformerVoid() {
+ var isNestedScope = false
+ override fun visitGetValue(expression: IrGetValue): IrGetValue {
+ val newParam = valueParametersMapping[expression.symbol.owner]
+ return if (newParam != null) {
+ IrGetValueImpl(
+ expression.startOffset,
+ expression.endOffset,
+ expression.type,
+ newParam.symbol,
+ expression.origin
+ )
+ } else expression
+ }
+
+ override fun visitReturn(expression: IrReturn): IrExpression {
+ if (expression.returnTargetSymbol == oldFn.symbol) {
+ // update the return statement to point to the new function, or else
+ // it will be interpreted as a non-local return
+ return super.visitReturn(IrReturnImpl(
+ expression.startOffset,
+ expression.endOffset,
+ expression.type,
+ fn.symbol,
+ expression.value
+ ))
+ }
+ return super.visitReturn(expression)
+ }
+
+ override fun visitFunction(declaration: IrFunction): IrStatement {
+ val wasNested = isNestedScope
+ try {
+ // we don't want to pass the composer parameter in to composable calls
+ // inside of nested scopes.... *unless* the scope was inlined.
+ isNestedScope = if (declaration.isInlinedLambda()) wasNested else true
+ return super.visitFunction(declaration)
+ } finally {
+ isNestedScope = wasNested
+ }
+ }
+
+ override fun visitDeclaration(declaration: IrDeclaration): IrStatement {
+ if (declaration.parent == oldFn) {
+ declaration.parent = fn
+ }
+ return super.visitDeclaration(declaration)
+ }
+
+ override fun visitCall(expression: IrCall): IrExpression {
+ val expr = if (!isNestedScope)
+ expression.withComposerParamIfNeeded(composerParam)
+ else
+ expression
+ return super.visitCall(expr)
+ }
+ })
+ }
+ }
+
+ fun IrCall.isComposableLambdaInvoke(): Boolean {
+ return origin == IrStatementOrigin.INVOKE && dispatchReceiver?.type?.isComposable() == true
+ }
+
+ fun IrFunction.isInlinedLambda(): Boolean {
+ descriptor.findPsi()?.let { psi ->
+ (psi as? KtFunctionLiteral)?.let {
+ if (InlineUtil.isInlinedArgument(
+ it,
+ context.state.bindingContext,
+ false
+ )
+ )
+ return true
+ }
+ }
+ return false
+ }
+
+ fun FunctionDescriptor.isComposable(): Boolean {
+ val composability = composableChecker.analyze(context.state.bindingTrace, this)
+ return when (composability) {
+ ComposableAnnotationChecker.Composability.NOT_COMPOSABLE -> false
+ ComposableAnnotationChecker.Composability.MARKED -> true
+ ComposableAnnotationChecker.Composability.INFERRED -> true
+ }
+ }
+
+ fun IrType.isComposable(): Boolean {
+ return annotations.hasAnnotation(ComposeFqNames.Composable)
+ }
+}
+
+class ComposerTypeRemapper(
+ private val context: JvmBackendContext,
+ private val typeTranslator: TypeTranslator,
+ private val composerTypeDescriptor: ClassDescriptor
+) : TypeRemapper {
+ override fun enterScope(irTypeParametersContainer: IrTypeParametersContainer) {}
+
+ override fun leaveScope() {}
+
+ private fun IrType.isComposable(): Boolean {
+ return annotations.hasAnnotation(ComposeFqNames.Composable)
+ }
+
+ private fun KotlinType.toIrType(): IrType = typeTranslator.translateType(this)
+
+ override fun remapType(type: IrType): IrType {
+ // TODO(lmr):
+ // This is basically creating the KotlinType and then converting to an IrType. Consider
+ // rewriting to just create the IrType directly, which would probably be more efficient.
+ if (type !is IrSimpleType) return type
+ if (!type.isFunction()) return type
+ if (!type.isComposable()) return type
+ val oldArguments = type.toKotlinType().arguments
+ val newArguments =
+ oldArguments.subList(0, oldArguments.size - 1) +
+ TypeProjectionImpl(composerTypeDescriptor.defaultType) +
+ oldArguments.last()
+
+ return context
+ .irBuiltIns
+ .builtIns
+ .getFunction(oldArguments.size) // return type is an argument, so this is n + 1
+ .defaultType
+ .replace(newArguments)
+ .toIrType()
+ }
+}
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/frames/analysis/FramePackageAnalysisHandlerExtension.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/frames/analysis/FramePackageAnalysisHandlerExtension.kt
index 9b70b31..7f4de3e 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/frames/analysis/FramePackageAnalysisHandlerExtension.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/frames/analysis/FramePackageAnalysisHandlerExtension.kt
@@ -8,76 +8,82 @@
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotated
-import org.jetbrains.kotlin.diagnostics.reportFromPlugin
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import androidx.compose.plugins.kotlin.ComposeFlags
-import androidx.compose.plugins.kotlin.analysis.ComposeDefaultErrorMessages
-import androidx.compose.plugins.kotlin.analysis.ComposeErrors
import androidx.compose.plugins.kotlin.frames.FrameRecordClassDescriptor
import androidx.compose.plugins.kotlin.frames.SyntheticFramePackageDescriptor
import androidx.compose.plugins.kotlin.frames.abstractRecordClassName
import androidx.compose.plugins.kotlin.frames.findTopLevel
import androidx.compose.plugins.kotlin.frames.modelClassName
import androidx.compose.plugins.kotlin.frames.recordClassName
+import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
-import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
-import org.jetbrains.kotlin.types.typeUtil.isInterface
+
+private fun doAnalysis(
+ module: ModuleDescriptor,
+ bindingTrace: BindingTrace,
+ files: Collection<KtFile>,
+ resolveSession: ResolveSession
+) {
+ if (!ComposeFlags.FRAMED_MODEL_CLASSES) return
+ for (file in files) {
+ analyseDeclarations(module, bindingTrace, file.declarations, resolveSession)
+ }
+}
+
+private fun analyseDeclarations(
+ module: ModuleDescriptor,
+ bindingTrace: BindingTrace,
+ declarations: List<KtDeclaration>,
+ resolveSession: ResolveSession
+) {
+ for (declaration in declarations) {
+ val ktClass = declaration as? KtClassOrObject ?: continue
+
+ analyseDeclarations(module, bindingTrace, ktClass.declarations, resolveSession)
+
+ val framedDescriptor = resolveSession.resolveToDescriptor(declaration) as?
+ ClassDescriptor ?: continue
+ if (!framedDescriptor.hasModelAnnotation()) continue
+
+ val classFqName = ktClass.fqName!!
+ val recordFqName = classFqName.parent().child(Name.identifier(
+ "${classFqName.shortName()}\$Record")
+ )
+ val recordSimpleName = recordFqName.shortName()
+ val recordPackage =
+ SyntheticFramePackageDescriptor(
+ module,
+ recordFqName.parent()
+ )
+ val baseTypeDescriptor = module.findTopLevel(abstractRecordClassName)
+ val recordDescriptor = module.findTopLevel(recordClassName)
+ val baseType = baseTypeDescriptor.defaultType
+ val frameClass =
+ FrameRecordClassDescriptor(
+ recordSimpleName,
+ recordPackage,
+ recordDescriptor,
+ framedDescriptor,
+ listOf(baseType),
+ bindingTrace.bindingContext
+ )
+
+ recordPackage.setClassDescriptor(frameClass)
+ bindingTrace.record(FrameWritableSlices.RECORD_CLASS, classFqName, frameClass)
+ bindingTrace.record(
+ FrameWritableSlices.FRAMED_DESCRIPTOR,
+ classFqName,
+ framedDescriptor
+ )
+ }
+}
class FramePackageAnalysisHandlerExtension : AnalysisHandlerExtension {
- companion object {
- fun doAnalysis(
- module: ModuleDescriptor,
- bindingTrace: BindingTrace,
- files: Collection<KtFile>,
- resolveSession: ResolveSession
- ) {
- if (!ComposeFlags.FRAMED_MODEL_CLASSES) return
- for (file in files) {
- for (declaration in file.declarations) {
- val ktClass = declaration as? KtClassOrObject ?: continue
- val framedDescriptor = resolveSession.resolveToDescriptor(declaration) as?
- ClassDescriptor ?: continue
- if (!framedDescriptor.hasModelAnnotation()) continue
-
- val classFqName = ktClass.fqName!!
- val recordFqName = classFqName.parent().child(Name.identifier(
- "${classFqName.shortName()}\$Record")
- )
- val recordSimpleName = recordFqName.shortName()
- val recordPackage =
- SyntheticFramePackageDescriptor(
- module,
- recordFqName.parent()
- )
- val baseTypeDescriptor = module.findTopLevel(abstractRecordClassName)
- val recordDescriptor = module.findTopLevel(recordClassName)
- val baseType = baseTypeDescriptor.defaultType
- val frameClass =
- FrameRecordClassDescriptor(
- recordSimpleName,
- recordPackage,
- recordDescriptor,
- framedDescriptor,
- listOf(baseType),
- bindingTrace.bindingContext
- )
-
- recordPackage.setClassDescriptor(frameClass)
- bindingTrace.record(FrameWritableSlices.RECORD_CLASS, classFqName, frameClass)
- bindingTrace.record(
- FrameWritableSlices.FRAMED_DESCRIPTOR,
- classFqName,
- framedDescriptor
- )
- }
- }
- }
- }
-
override fun doAnalysis(
project: Project,
module: ModuleDescriptor,
diff --git a/compose/compose-runtime/api/0.1.0-dev04.txt b/compose/compose-runtime/api/0.1.0-dev04.txt
index 26ce282..e48b293 100644
--- a/compose/compose-runtime/api/0.1.0-dev04.txt
+++ b/compose/compose-runtime/api/0.1.0-dev04.txt
@@ -126,6 +126,7 @@
public final class ComposerKt {
method public static inline <N, T> T! cache(androidx.compose.Composer<N>, boolean valid = true, kotlin.jvm.functions.Function0<? extends T> block);
method public static inline <T> T! escapeCompose(kotlin.jvm.functions.Function1<? super androidx.compose.NullCompilationScope,? extends T> block);
+ method public static androidx.compose.Composer<?> getCurrentComposerIntrinsic();
method public static <N> Object? nextValue(androidx.compose.Composer<N>);
field public static final int DEFAULT_SLOT_ACTIONS_SIZE = 16; // 0x10
field public static final int DEFAULT_SLOT_KEYS_SIZE = 8; // 0x8
@@ -248,7 +249,7 @@
@androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
}
- public interface MutableState<T> extends androidx.compose.State<T> {
+ @androidx.compose.Stable public interface MutableState<T> extends androidx.compose.State<T> {
method public operator T! component1();
method public operator kotlin.jvm.functions.Function1<T,kotlin.Unit> component2();
method public operator T! getValue(Object? thisObj, kotlin.reflect.KProperty<?> property);
@@ -424,7 +425,7 @@
@kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS}) public @interface StableMarker {
}
- public interface State<T> {
+ @androidx.compose.Stable public interface State<T> {
method public T! getValue();
property public abstract T! value;
}
diff --git a/compose/compose-runtime/api/api_lint.ignore b/compose/compose-runtime/api/api_lint.ignore
index 0d0d66e..b95542f 100644
--- a/compose/compose-runtime/api/api_lint.ignore
+++ b/compose/compose-runtime/api/api_lint.ignore
@@ -35,6 +35,8 @@
Context is distinct, so it must be the first argument (method `ViewComposer`)
+DocumentExceptions: androidx.compose.ComposerKt#getCurrentComposerIntrinsic():
+ Method ComposerKt.getCurrentComposerIntrinsic appears to be throwing kotlin.NotImplementedError; this should be listed in the documentation; see https://android.github.io/kotlin-guides/interop.html#document-exceptions
DocumentExceptions: androidx.compose.frames.FramesKt#commit(androidx.compose.frames.Frame):
Method FramesKt.commit appears to be throwing java.lang.IllegalStateException; this should be listed in the documentation; see https://android.github.io/kotlin-guides/interop.html#document-exceptions
DocumentExceptions: androidx.compose.frames.FramesKt#currentFrame():
diff --git a/compose/compose-runtime/api/current.txt b/compose/compose-runtime/api/current.txt
index 26ce282..e48b293 100644
--- a/compose/compose-runtime/api/current.txt
+++ b/compose/compose-runtime/api/current.txt
@@ -126,6 +126,7 @@
public final class ComposerKt {
method public static inline <N, T> T! cache(androidx.compose.Composer<N>, boolean valid = true, kotlin.jvm.functions.Function0<? extends T> block);
method public static inline <T> T! escapeCompose(kotlin.jvm.functions.Function1<? super androidx.compose.NullCompilationScope,? extends T> block);
+ method public static androidx.compose.Composer<?> getCurrentComposerIntrinsic();
method public static <N> Object? nextValue(androidx.compose.Composer<N>);
field public static final int DEFAULT_SLOT_ACTIONS_SIZE = 16; // 0x10
field public static final int DEFAULT_SLOT_KEYS_SIZE = 8; // 0x8
@@ -248,7 +249,7 @@
@androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
}
- public interface MutableState<T> extends androidx.compose.State<T> {
+ @androidx.compose.Stable public interface MutableState<T> extends androidx.compose.State<T> {
method public operator T! component1();
method public operator kotlin.jvm.functions.Function1<T,kotlin.Unit> component2();
method public operator T! getValue(Object? thisObj, kotlin.reflect.KProperty<?> property);
@@ -424,7 +425,7 @@
@kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS}) public @interface StableMarker {
}
- public interface State<T> {
+ @androidx.compose.Stable public interface State<T> {
method public T! getValue();
property public abstract T! value;
}
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev04.txt b/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev04.txt
index 26ce282..e48b293 100644
--- a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev04.txt
+++ b/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev04.txt
@@ -126,6 +126,7 @@
public final class ComposerKt {
method public static inline <N, T> T! cache(androidx.compose.Composer<N>, boolean valid = true, kotlin.jvm.functions.Function0<? extends T> block);
method public static inline <T> T! escapeCompose(kotlin.jvm.functions.Function1<? super androidx.compose.NullCompilationScope,? extends T> block);
+ method public static androidx.compose.Composer<?> getCurrentComposerIntrinsic();
method public static <N> Object? nextValue(androidx.compose.Composer<N>);
field public static final int DEFAULT_SLOT_ACTIONS_SIZE = 16; // 0x10
field public static final int DEFAULT_SLOT_KEYS_SIZE = 8; // 0x8
@@ -248,7 +249,7 @@
@androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
}
- public interface MutableState<T> extends androidx.compose.State<T> {
+ @androidx.compose.Stable public interface MutableState<T> extends androidx.compose.State<T> {
method public operator T! component1();
method public operator kotlin.jvm.functions.Function1<T,kotlin.Unit> component2();
method public operator T! getValue(Object? thisObj, kotlin.reflect.KProperty<?> property);
@@ -424,7 +425,7 @@
@kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS}) public @interface StableMarker {
}
- public interface State<T> {
+ @androidx.compose.Stable public interface State<T> {
method public T! getValue();
property public abstract T! value;
}
diff --git a/compose/compose-runtime/api/public_plus_experimental_current.txt b/compose/compose-runtime/api/public_plus_experimental_current.txt
index 26ce282..e48b293 100644
--- a/compose/compose-runtime/api/public_plus_experimental_current.txt
+++ b/compose/compose-runtime/api/public_plus_experimental_current.txt
@@ -126,6 +126,7 @@
public final class ComposerKt {
method public static inline <N, T> T! cache(androidx.compose.Composer<N>, boolean valid = true, kotlin.jvm.functions.Function0<? extends T> block);
method public static inline <T> T! escapeCompose(kotlin.jvm.functions.Function1<? super androidx.compose.NullCompilationScope,? extends T> block);
+ method public static androidx.compose.Composer<?> getCurrentComposerIntrinsic();
method public static <N> Object? nextValue(androidx.compose.Composer<N>);
field public static final int DEFAULT_SLOT_ACTIONS_SIZE = 16; // 0x10
field public static final int DEFAULT_SLOT_KEYS_SIZE = 8; // 0x8
@@ -248,7 +249,7 @@
@androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
}
- public interface MutableState<T> extends androidx.compose.State<T> {
+ @androidx.compose.Stable public interface MutableState<T> extends androidx.compose.State<T> {
method public operator T! component1();
method public operator kotlin.jvm.functions.Function1<T,kotlin.Unit> component2();
method public operator T! getValue(Object? thisObj, kotlin.reflect.KProperty<?> property);
@@ -424,7 +425,7 @@
@kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS}) public @interface StableMarker {
}
- public interface State<T> {
+ @androidx.compose.Stable public interface State<T> {
method public T! getValue();
property public abstract T! value;
}
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev04.txt b/compose/compose-runtime/api/restricted_0.1.0-dev04.txt
index 26ce282..e48b293 100644
--- a/compose/compose-runtime/api/restricted_0.1.0-dev04.txt
+++ b/compose/compose-runtime/api/restricted_0.1.0-dev04.txt
@@ -126,6 +126,7 @@
public final class ComposerKt {
method public static inline <N, T> T! cache(androidx.compose.Composer<N>, boolean valid = true, kotlin.jvm.functions.Function0<? extends T> block);
method public static inline <T> T! escapeCompose(kotlin.jvm.functions.Function1<? super androidx.compose.NullCompilationScope,? extends T> block);
+ method public static androidx.compose.Composer<?> getCurrentComposerIntrinsic();
method public static <N> Object? nextValue(androidx.compose.Composer<N>);
field public static final int DEFAULT_SLOT_ACTIONS_SIZE = 16; // 0x10
field public static final int DEFAULT_SLOT_KEYS_SIZE = 8; // 0x8
@@ -248,7 +249,7 @@
@androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
}
- public interface MutableState<T> extends androidx.compose.State<T> {
+ @androidx.compose.Stable public interface MutableState<T> extends androidx.compose.State<T> {
method public operator T! component1();
method public operator kotlin.jvm.functions.Function1<T,kotlin.Unit> component2();
method public operator T! getValue(Object? thisObj, kotlin.reflect.KProperty<?> property);
@@ -424,7 +425,7 @@
@kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS}) public @interface StableMarker {
}
- public interface State<T> {
+ @androidx.compose.Stable public interface State<T> {
method public T! getValue();
property public abstract T! value;
}
diff --git a/compose/compose-runtime/api/restricted_current.txt b/compose/compose-runtime/api/restricted_current.txt
index 26ce282..e48b293 100644
--- a/compose/compose-runtime/api/restricted_current.txt
+++ b/compose/compose-runtime/api/restricted_current.txt
@@ -126,6 +126,7 @@
public final class ComposerKt {
method public static inline <N, T> T! cache(androidx.compose.Composer<N>, boolean valid = true, kotlin.jvm.functions.Function0<? extends T> block);
method public static inline <T> T! escapeCompose(kotlin.jvm.functions.Function1<? super androidx.compose.NullCompilationScope,? extends T> block);
+ method public static androidx.compose.Composer<?> getCurrentComposerIntrinsic();
method public static <N> Object? nextValue(androidx.compose.Composer<N>);
field public static final int DEFAULT_SLOT_ACTIONS_SIZE = 16; // 0x10
field public static final int DEFAULT_SLOT_KEYS_SIZE = 8; // 0x8
@@ -248,7 +249,7 @@
@androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
}
- public interface MutableState<T> extends androidx.compose.State<T> {
+ @androidx.compose.Stable public interface MutableState<T> extends androidx.compose.State<T> {
method public operator T! component1();
method public operator kotlin.jvm.functions.Function1<T,kotlin.Unit> component2();
method public operator T! getValue(Object? thisObj, kotlin.reflect.KProperty<?> property);
@@ -424,7 +425,7 @@
@kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS}) public @interface StableMarker {
}
- public interface State<T> {
+ @androidx.compose.Stable public interface State<T> {
method public T! getValue();
property public abstract T! value;
}
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composer.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composer.kt
index 3d80e6d..d166ea4 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composer.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composer.kt
@@ -1748,3 +1748,8 @@
}
inline fun <T> escapeCompose(block: NullCompilationScope.() -> T) = NullCompilationScope.block()
+
+@Composable
+val currentComposerIntrinsic: Composer<*> get() {
+ throw NotImplementedError("Implemented as an intrinsic")
+}
\ No newline at end of file
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/MutableState.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/MutableState.kt
index 2c9c078..081d83e 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/MutableState.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/MutableState.kt
@@ -16,7 +16,6 @@
package androidx.compose
-import androidx.compose.annotations.Hide
import androidx.compose.frames.AbstractRecord
import androidx.compose.frames.Framed
import androidx.compose.frames.Record
@@ -132,6 +131,7 @@
* @see [MutableState]
* @see [mutableStateOf]
*/
+@Stable
interface State<T> {
val value: T
}
@@ -146,6 +146,7 @@
* @see [State]
* @see [mutableStateOf]
*/
+@Stable
interface MutableState<T> : State<T> {
override var value: T
operator fun component1(): T
diff --git a/core/OWNERS b/core/OWNERS
index 914e9ca..6a3338bc 100644
--- a/core/OWNERS
+++ b/core/OWNERS
@@ -8,6 +8,7 @@
jaggies@google.com
joshmccloskey@google.com
kchyn@google.com
+curtislb@google.com
# For text related files
nona@google.com
diff --git a/core/core/src/main/java/androidx/core/app/RemoteInput.java b/core/core/src/main/java/androidx/core/app/RemoteInput.java
index 3bf4d4d..dd01c0b 100644
--- a/core/core/src/main/java/androidx/core/app/RemoteInput.java
+++ b/core/core/src/main/java/androidx/core/app/RemoteInput.java
@@ -580,7 +580,7 @@
if (!clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)) {
return null;
}
- if (!clipDescription.getLabel().equals(RemoteInput.RESULTS_CLIP_LABEL)) {
+ if (!clipDescription.getLabel().toString().contentEquals(RemoteInput.RESULTS_CLIP_LABEL)) {
return null;
}
return clipData.getItemAt(0).getIntent();
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
index 0a8e2a9f1..421c557 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -1603,6 +1603,10 @@
* searches through fragments that are currently added to the manager's
* activity; if no such fragment is found, then all fragments currently
* on the back stack are searched.
+ * <p>
+ * If provided a {@code null} tag, this method returns null.
+ *
+ * @param tag the tag used to search for the fragment
* @return The fragment if found or null otherwise.
*/
@Nullable
diff --git a/gradle.properties b/gradle.properties
index aecea02..94c027d 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,4 @@
-org.gradle.jvmargs=-Xmx8g -XX:MaxPermSize=8g
+org.gradle.jvmargs=-Xmx8g
org.gradle.daemon=true
org.gradle.configureondemand=true
org.gradle.parallel=true
@@ -14,4 +14,4 @@
android.useNewJarCreator=false
# Workaround for b/141364941
android.forceJacocoOutOfProcess=true
-android.namespacedRClass=true
\ No newline at end of file
+android.namespacedRClass=true
diff --git a/gradlew b/gradlew
index 6233fe3..243699d 100755
--- a/gradlew
+++ b/gradlew
@@ -8,22 +8,27 @@
# --------- androidx specific code needed for build server. ------------------
+SCRIPT_PATH="$(cd $(dirname $0) && pwd)"
if [ -n "$OUT_DIR" ] ; then
mkdir -p "$OUT_DIR"
OUT_DIR="$(cd $OUT_DIR && pwd)"
export GRADLE_USER_HOME="$OUT_DIR/.gradle"
export TMPDIR=$OUT_DIR
else
- SCRIPT_PATH="$(cd $(dirname $0) && pwd)"
CHECKOUT_ROOT="$(cd $SCRIPT_PATH/../.. && pwd)"
export OUT_DIR="$CHECKOUT_ROOT/out"
fi
+XMX_ARG="$(cd $SCRIPT_PATH && grep org.gradle.jvmargs gradle.properties | sed 's/^/-D/')"
if [ -n "$DIST_DIR" ]; then
mkdir -p "$DIST_DIR"
DIST_DIR="$(cd $DIST_DIR && pwd)"
export LINT_PRINT_STACKTRACE=true
+ #Set the initial heap size to match the max heap size,
+ #by replacing a string like "-Xmx1g" with one like "-Xms1g -Xmx1g"
+ XMX_ARG="$(echo $XMX_ARG | sed 's/-Xmx\([^ ]*\)/-Xms\1 -Xmx\1/')"
+
# We don't set a default DIST_DIR in an else clause here because Studio doesn't use gradlew
# and doesn't set DIST_DIR and we want gradlew and Studio to match
fi
@@ -210,7 +215,7 @@
TMPDIR_ARG="-Djava.io.tmpdir=$TMPDIR"
fi
-if "$JAVACMD" "${JVM_OPTS[@]}" $TMPDIR_ARG -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain $HOME_SYSTEM_PROPERTY_ARGUMENT $TMPDIR_ARG "$@"; then
+if "$JAVACMD" "${JVM_OPTS[@]}" $TMPDIR_ARG -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain $HOME_SYSTEM_PROPERTY_ARGUMENT $TMPDIR_ARG "$XMX_ARG" "$@"; then
exit 0
else
# Print AndroidX-specific help message if build fails
diff --git a/interpolator/api/1.0.0.txt b/interpolator/interpolator/api/1.0.0.txt
similarity index 100%
rename from interpolator/api/1.0.0.txt
rename to interpolator/interpolator/api/1.0.0.txt
diff --git a/interpolator/api/1.1.0-alpha01.txt b/interpolator/interpolator/api/1.1.0-alpha01.txt
similarity index 100%
rename from interpolator/api/1.1.0-alpha01.txt
rename to interpolator/interpolator/api/1.1.0-alpha01.txt
diff --git a/interpolator/api/current.txt b/interpolator/interpolator/api/current.txt
similarity index 100%
rename from interpolator/api/current.txt
rename to interpolator/interpolator/api/current.txt
diff --git a/interpolator/api/public_plus_experimental_1.0.0.txt b/interpolator/interpolator/api/public_plus_experimental_1.0.0.txt
similarity index 100%
rename from interpolator/api/public_plus_experimental_1.0.0.txt
rename to interpolator/interpolator/api/public_plus_experimental_1.0.0.txt
diff --git a/interpolator/api/public_plus_experimental_1.1.0-alpha01.txt b/interpolator/interpolator/api/public_plus_experimental_1.1.0-alpha01.txt
similarity index 100%
rename from interpolator/api/public_plus_experimental_1.1.0-alpha01.txt
rename to interpolator/interpolator/api/public_plus_experimental_1.1.0-alpha01.txt
diff --git a/interpolator/api/public_plus_experimental_current.txt b/interpolator/interpolator/api/public_plus_experimental_current.txt
similarity index 100%
rename from interpolator/api/public_plus_experimental_current.txt
rename to interpolator/interpolator/api/public_plus_experimental_current.txt
diff --git a/interpolator/api/res-1.0.0.txt b/interpolator/interpolator/api/res-1.0.0.txt
similarity index 100%
rename from interpolator/api/res-1.0.0.txt
rename to interpolator/interpolator/api/res-1.0.0.txt
diff --git a/interpolator/api/res-1.1.0-alpha01.txt b/interpolator/interpolator/api/res-1.1.0-alpha01.txt
similarity index 100%
rename from interpolator/api/res-1.1.0-alpha01.txt
rename to interpolator/interpolator/api/res-1.1.0-alpha01.txt
diff --git a/interpolator/api/restricted_1.0.0.txt b/interpolator/interpolator/api/restricted_1.0.0.txt
similarity index 100%
rename from interpolator/api/restricted_1.0.0.txt
rename to interpolator/interpolator/api/restricted_1.0.0.txt
diff --git a/interpolator/api/restricted_1.1.0-alpha01.txt b/interpolator/interpolator/api/restricted_1.1.0-alpha01.txt
similarity index 100%
rename from interpolator/api/restricted_1.1.0-alpha01.txt
rename to interpolator/interpolator/api/restricted_1.1.0-alpha01.txt
diff --git a/interpolator/api/restricted_current.txt b/interpolator/interpolator/api/restricted_current.txt
similarity index 100%
rename from interpolator/api/restricted_current.txt
rename to interpolator/interpolator/api/restricted_current.txt
diff --git a/interpolator/api_legacy/0.0.0.txt b/interpolator/interpolator/api_legacy/0.0.0.txt
similarity index 100%
rename from interpolator/api_legacy/0.0.0.txt
rename to interpolator/interpolator/api_legacy/0.0.0.txt
diff --git a/interpolator/api_legacy/28.0.0-alpha1.txt b/interpolator/interpolator/api_legacy/28.0.0-alpha1.txt
similarity index 100%
rename from interpolator/api_legacy/28.0.0-alpha1.txt
rename to interpolator/interpolator/api_legacy/28.0.0-alpha1.txt
diff --git a/interpolator/api_legacy/current.txt b/interpolator/interpolator/api_legacy/current.txt
similarity index 100%
rename from interpolator/api_legacy/current.txt
rename to interpolator/interpolator/api_legacy/current.txt
diff --git a/interpolator/build.gradle b/interpolator/interpolator/build.gradle
similarity index 100%
rename from interpolator/build.gradle
rename to interpolator/interpolator/build.gradle
diff --git a/interpolator/src/main/AndroidManifest.xml b/interpolator/interpolator/src/main/AndroidManifest.xml
similarity index 100%
rename from interpolator/src/main/AndroidManifest.xml
rename to interpolator/interpolator/src/main/AndroidManifest.xml
diff --git a/interpolator/src/main/java/androidx/interpolator/view/animation/FastOutLinearInInterpolator.java b/interpolator/interpolator/src/main/java/androidx/interpolator/view/animation/FastOutLinearInInterpolator.java
similarity index 100%
rename from interpolator/src/main/java/androidx/interpolator/view/animation/FastOutLinearInInterpolator.java
rename to interpolator/interpolator/src/main/java/androidx/interpolator/view/animation/FastOutLinearInInterpolator.java
diff --git a/interpolator/src/main/java/androidx/interpolator/view/animation/FastOutSlowInInterpolator.java b/interpolator/interpolator/src/main/java/androidx/interpolator/view/animation/FastOutSlowInInterpolator.java
similarity index 100%
rename from interpolator/src/main/java/androidx/interpolator/view/animation/FastOutSlowInInterpolator.java
rename to interpolator/interpolator/src/main/java/androidx/interpolator/view/animation/FastOutSlowInInterpolator.java
diff --git a/interpolator/src/main/java/androidx/interpolator/view/animation/LinearOutSlowInInterpolator.java b/interpolator/interpolator/src/main/java/androidx/interpolator/view/animation/LinearOutSlowInInterpolator.java
similarity index 100%
rename from interpolator/src/main/java/androidx/interpolator/view/animation/LinearOutSlowInInterpolator.java
rename to interpolator/interpolator/src/main/java/androidx/interpolator/view/animation/LinearOutSlowInInterpolator.java
diff --git a/interpolator/src/main/java/androidx/interpolator/view/animation/LookupTableInterpolator.java b/interpolator/interpolator/src/main/java/androidx/interpolator/view/animation/LookupTableInterpolator.java
similarity index 100%
rename from interpolator/src/main/java/androidx/interpolator/view/animation/LookupTableInterpolator.java
rename to interpolator/interpolator/src/main/java/androidx/interpolator/view/animation/LookupTableInterpolator.java
diff --git a/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackListPreferenceDialogFragment.java b/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackListPreferenceDialogFragment.java
index 4d7e852..5f774ae 100644
--- a/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackListPreferenceDialogFragment.java
+++ b/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackListPreferenceDialogFragment.java
@@ -225,7 +225,8 @@
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
- holder.getWidgetView().setChecked(mEntryValues[position].equals(mSelectedValue));
+ holder.getWidgetView().setChecked(
+ TextUtils.equals(mEntryValues[position].toString(), mSelectedValue));
holder.getTitleView().setText(mEntries[position]);
}
diff --git a/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackListPreferenceDialogFragmentCompat.java b/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackListPreferenceDialogFragmentCompat.java
index 941587d..88fd21d 100644
--- a/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackListPreferenceDialogFragmentCompat.java
+++ b/leanback-preference/src/main/java/androidx/leanback/preference/LeanbackListPreferenceDialogFragmentCompat.java
@@ -228,7 +228,8 @@
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
- holder.getWidgetView().setChecked(mEntryValues[position].equals(mSelectedValue));
+ holder.getWidgetView().setChecked(
+ TextUtils.equals(mEntryValues[position].toString(), mSelectedValue));
holder.getTitleView().setText(mEntries[position]);
}
diff --git a/media2/player/src/main/java/androidx/media2/player/MediaPlayer.java b/media2/player/src/main/java/androidx/media2/player/MediaPlayer.java
index d150b81..dbf5514 100644
--- a/media2/player/src/main/java/androidx/media2/player/MediaPlayer.java
+++ b/media2/player/src/main/java/androidx/media2/player/MediaPlayer.java
@@ -2208,6 +2208,11 @@
@NonNull
public ListenableFuture<PlayerResult> setAuxEffectSendLevel(
@FloatRange(from = 0, to = 1) final float level) {
+ if (level < 0 || level > 1) {
+ // Returns ListenableFuture instead of throwing exception, not to newly throw an
+ // exception in existing code.
+ return createFutureForResultCode(RESULT_ERROR_BAD_VALUE);
+ }
synchronized (mStateLock) {
if (mClosed) {
return createFutureForClosed();
diff --git a/message-browser/browser/build.gradle b/message-browser/browser/build.gradle
index 03abbfe..dd0b94a4 100644
--- a/message-browser/browser/build.gradle
+++ b/message-browser/browser/build.gradle
@@ -15,6 +15,7 @@
dependencies {
implementation("androidx.core:core:1.1.0")
implementation("androidx.collection:collection:1.0.0")
+ implementation("androidx.concurrent:concurrent-futures:1.0.0")
api("androidx.annotation:annotation:1.1.0")
androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/message-browser/browser/src/androidTest/java/androidx/message/browser/MessageBrowserTest.java b/message-browser/browser/src/androidTest/java/androidx/message/browser/MessageBrowserTest.java
index 8d8763e..0281a36 100644
--- a/message-browser/browser/src/androidTest/java/androidx/message/browser/MessageBrowserTest.java
+++ b/message-browser/browser/src/androidTest/java/androidx/message/browser/MessageBrowserTest.java
@@ -16,6 +16,7 @@
package androidx.message.browser;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -26,6 +27,8 @@
import androidx.annotation.NonNull;
import androidx.test.core.app.ApplicationProvider;
+import com.google.common.util.concurrent.ListenableFuture;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -126,6 +129,59 @@
assertTrue(callback.disconnectedLatch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
}
+ @Test
+ public void testSendCustomCommand() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ MessageBrowser.BrowserCallback callback = new MessageBrowser.BrowserCallback() {
+ public void onConnected(@NonNull MessageBrowser browser,
+ @NonNull MessageCommandGroup allowedCommands) {
+ latch.countDown();
+ }
+ };
+ mMsgBrowserBuilder.setBrowserCallback(sHandlerExecutor, callback);
+ MessageBrowser browser = mMsgBrowserBuilder.build();
+ Bundle cmdExtras = new Bundle();
+ cmdExtras.putString("cmd-extra", "cmd-extra-value");
+ Bundle cmdArgs = new Bundle();
+ cmdArgs.putString("cmd-args", "cmd-args-value");
+ MessageCommand command =
+ new MessageCommand(MockMessageLibraryService.CUSTOM_COMMAND_ACCEPT, cmdExtras);
+ ListenableFuture<Bundle> resultFuture = browser.sendCustomCommand(command, cmdArgs);
+ Bundle result = resultFuture.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ assertEquals(MockMessageLibraryService.CUSTOM_COMMAND_ACCEPT,
+ result.getString(MockMessageLibraryService.KEY_CUSTOM_COMMAND_ACTION));
+ assertEquals("cmd-extra-value", result
+ .getBundle(MockMessageLibraryService.KEY_CUSTOM_COMMAND_EXTRAS)
+ .getString("cmd-extra"));
+ assertEquals("cmd-args-value", result
+ .getBundle(MockMessageLibraryService.KEY_CUSTOM_COMMAND_ARGS)
+ .getString("cmd-args"));
+ browser.close();
+ }
+
+ @Test
+ public void testSendCustomCommandDecline() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ MessageBrowser.BrowserCallback callback = new MessageBrowser.BrowserCallback() {
+ public void onConnected(@NonNull MessageBrowser browser,
+ @NonNull MessageCommandGroup allowedCommands) {
+ latch.countDown();
+ }
+ };
+ mMsgBrowserBuilder.setBrowserCallback(sHandlerExecutor, callback);
+ MessageBrowser browser = mMsgBrowserBuilder.build();
+ Bundle cmdExtras = new Bundle();
+ cmdExtras.putString("cmd-extra", "cmd-extra-value");
+ Bundle cmdArgs = new Bundle();
+ cmdArgs.putString("cmd-args", "cmd-args-value");
+ MessageCommand command =
+ new MessageCommand(MockMessageLibraryService.CUSTOM_COMMAND_DECLINE, cmdExtras);
+ ListenableFuture<Bundle> resultFuture = browser.sendCustomCommand(command, cmdArgs);
+ Bundle result = resultFuture.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ assertTrue(result.isEmpty());
+ browser.close();
+ }
+
private class BrowserCallbackForTestMultiConnection extends MessageBrowser.BrowserCallback {
public MessageBrowser browser1;
public final CountDownLatch connectedLatch1 = new CountDownLatch(1);
diff --git a/message-browser/browser/src/androidTest/java/androidx/message/browser/MockMessageLibraryService.java b/message-browser/browser/src/androidTest/java/androidx/message/browser/MockMessageLibraryService.java
index ee061d1..ebf8ba6 100644
--- a/message-browser/browser/src/androidTest/java/androidx/message/browser/MockMessageLibraryService.java
+++ b/message-browser/browser/src/androidTest/java/androidx/message/browser/MockMessageLibraryService.java
@@ -18,6 +18,9 @@
import android.os.Bundle;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
/**
* Mock implementation of {@link MessageLibraryService} for testing.
*/
@@ -28,6 +31,16 @@
"MockMessageLibraryService.KEY_REFUSE_CONNECTION";
public static final String KEY_CRASH_CONNECTION =
"MockMessageLibraryService.KEY_CRASH_CONNECTION";
+ public static final String CUSTOM_COMMAND_ACCEPT =
+ "MockMessageLibraryService.CUSTOM_COMMAND_ACCEPT";
+ public static final String CUSTOM_COMMAND_DECLINE =
+ "MockMessageLibraryService.CUSTOM_COMMAND_DECLINE";
+ public static final String KEY_CUSTOM_COMMAND_ACTION =
+ "MockMessageLibraryService.CUSTOM_COMMAND_ACTION";
+ public static final String KEY_CUSTOM_COMMAND_ARGS =
+ "MockMessageLibraryService.CUSTOM_COMMAND_ARGS";
+ public static final String KEY_CUSTOM_COMMAND_EXTRAS =
+ "MockMessageLibraryService.CUSTOM_COMMAND_EXTRAS";
public MockMessageLibraryService() {
super();
@@ -39,7 +52,7 @@
}
@Override
- public MessageCommandGroup onConnect(BrowserInfo info) {
+ public MessageCommandGroup onConnect(@NonNull BrowserInfo info) {
Bundle connectionHints = info.getConnectionHints();
if (connectionHints.getBoolean(KEY_REFUSE_CONNECTION)) {
return null;
@@ -48,4 +61,24 @@
}
return super.onConnect(info);
}
+
+ @Override
+ public boolean onCommandRequest(@NonNull BrowserInfo browserInfo,
+ @NonNull MessageCommand command) {
+ if (command.mCommandCode == MessageCommand.COMMAND_CODE_CUSTOM) {
+ return CUSTOM_COMMAND_ACCEPT.equals(command.mCustomAction);
+ }
+ return true;
+ }
+
+ @Override
+ @NonNull
+ public Bundle onCustomCommand(@NonNull BrowserInfo browserInfo,
+ @NonNull MessageCommand customCommand, @Nullable Bundle args) {
+ Bundle result = new Bundle();
+ result.putString(KEY_CUSTOM_COMMAND_ACTION, customCommand.mCustomAction);
+ result.putBundle(KEY_CUSTOM_COMMAND_EXTRAS, customCommand.mCustomExtras);
+ result.putBundle(KEY_CUSTOM_COMMAND_ARGS, args);
+ return result;
+ }
}
diff --git a/message-browser/browser/src/main/aidl/androidx/message/browser/IMessageBrowser.aidl b/message-browser/browser/src/main/aidl/androidx/message/browser/IMessageBrowser.aidl
index 1c03aa2..cdf6823 100644
--- a/message-browser/browser/src/main/aidl/androidx/message/browser/IMessageBrowser.aidl
+++ b/message-browser/browser/src/main/aidl/androidx/message/browser/IMessageBrowser.aidl
@@ -25,6 +25,7 @@
* @hide
*/
oneway interface IMessageBrowser {
- void notifyConnected(in Bundle allowedCommands) = 0;
- void notifyDisconnected() = 1;
+ void notifyConnected(int seq, in Bundle allowedCommands) = 0;
+ void notifyDisconnected(int seq) = 1;
+ void notifyCommandResult(int seq, in Bundle result) = 2;
}
diff --git a/message-browser/browser/src/main/aidl/androidx/message/browser/IMessageLibraryService.aidl b/message-browser/browser/src/main/aidl/androidx/message/browser/IMessageLibraryService.aidl
index 81fa472..227ec23 100644
--- a/message-browser/browser/src/main/aidl/androidx/message/browser/IMessageLibraryService.aidl
+++ b/message-browser/browser/src/main/aidl/androidx/message/browser/IMessageLibraryService.aidl
@@ -29,4 +29,5 @@
oneway interface IMessageLibraryService {
void connect(IMessageBrowser browser, int seq, in Bundle connectionRequest) = 0;
void disconnect(IMessageBrowser browser, int seq) = 1;
+ void sendCustomCommand(IMessageBrowser browser, int seq, in Bundle command, in Bundle args) = 2;
}
diff --git a/message-browser/browser/src/main/java/androidx/message/browser/MessageBrowser.java b/message-browser/browser/src/main/java/androidx/message/browser/MessageBrowser.java
index 0040604..2bc542f 100644
--- a/message-browser/browser/src/main/java/androidx/message/browser/MessageBrowser.java
+++ b/message-browser/browser/src/main/java/androidx/message/browser/MessageBrowser.java
@@ -33,6 +33,10 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.Executor;
/**
@@ -73,6 +77,7 @@
final BrowserCallback mBrowserCallback;
final Executor mCallbackExecutor;
+ final SequencedFutureManager mSequencedFutureManager;
private final MessageLibraryServiceConnection mServiceConnection;
@@ -84,7 +89,8 @@
final ConnectionRequest mConnectionRequest;
@GuardedBy("mLock")
@SuppressWarnings("WeakerAccess") /* synthetic access */
- int mNextSequenceNumber;
+ final List<Runnable> mPendingTasks = new ArrayList<>();
+
@GuardedBy("mLock")
@SuppressWarnings("WeakerAccess") /* synthetic access */
IMessageLibraryService mService;
@@ -105,6 +111,7 @@
mServiceComponent = serviceComponent;
mCallbackExecutor = callbackExecutor;
mBrowserCallback = callback;
+ mSequencedFutureManager = new SequencedFutureManager();
mConnectionRequest = new ConnectionRequest(mContext.getPackageName(), Process.myPid(),
connectionHints);
mBrowserStub = new BrowserStub();
@@ -124,29 +131,67 @@
if (mBrowserState == STATE_CLOSED || mBrowserState == STATE_CLOSING) return;
try {
if (mBrowserState == STATE_CONNECTING || mBrowserState == STATE_CONNECTED) {
- mService.disconnect(mBrowserStub, mNextSequenceNumber++);
+ mService.disconnect(mBrowserStub,
+ mSequencedFutureManager.obtainNextSequenceNumber());
}
} catch (RemoteException e) {
Log.w(TAG, "Service " + mServiceComponent + " has died prematurely");
}
mBrowserState = STATE_CLOSING;
+ mSequencedFutureManager.close();
}
}
- void notifyConnected(MessageCommandGroup allowedCommands) {
- if (mCallbackExecutor != null) {
- mCallbackExecutor.execute(() -> {
- mBrowserCallback.onConnected(MessageBrowser.this, allowedCommands);
- });
+ /**
+ * Sends a custom command to the library service
+ * <p>
+ * A command is not accepted if it is not a custom command.
+ *
+ * @param command custom command to be sent to the library service
+ * @param args optional argument
+ *
+ * @return a listenable future that contains a {@link Bundle} for the result.
+ */
+ @NonNull
+ public ListenableFuture<Bundle> sendCustomCommand(@NonNull MessageCommand command,
+ @Nullable Bundle args) {
+ if (command == null) {
+ throw new NullPointerException("command shouldn't be null");
}
+ if (command.getCommandCode() != MessageCommand.COMMAND_CODE_CUSTOM) {
+ throw new IllegalArgumentException("command should be a custom command");
+ }
+ final SequencedFutureManager.SequencedFuture<Bundle> result =
+ mSequencedFutureManager.createSequencedFuture(Bundle.EMPTY);
+ executeOrPendRunnable(() -> {
+ synchronized (mLock) {
+ try {
+ mService.sendCustomCommand(mBrowserStub, result.getSequenceNumber(),
+ command.toBundle(), args);
+ } catch (RemoteException e) {
+ mSequencedFutureManager.setFutureResult(result.getSequenceNumber(),
+ Bundle.EMPTY);
+ }
+ }
+ });
+ return result;
}
- void notifyDisconnected() {
- if (mCallbackExecutor != null) {
- mCallbackExecutor.execute(() -> {
- mBrowserCallback.onDisconnected(MessageBrowser.this);
- });
+ void executeOrPendRunnable(Runnable runnable) {
+ synchronized (mLock) {
+ if (mBrowserState != STATE_CONNECTED) {
+ mPendingTasks.add(runnable);
+ return;
+ }
}
+ runnable.run();
+ }
+
+ void notifyBrowserCallback(Runnable runnable) {
+ if (mCallbackExecutor != null) {
+ mCallbackExecutor.execute(() -> runnable.run());
+ }
+
}
private boolean requestConnection() {
@@ -273,23 +318,37 @@
BrowserStub() {}
@Override
- public void notifyConnected(final Bundle allowedCommands) {
+ public void notifyConnected(final int seq, final Bundle allowedCommands) {
synchronized (mLock) {
mBrowserState = STATE_CONNECTED;
}
- MessageBrowser.this.notifyConnected(MessageCommandGroup.fromBundle(allowedCommands));
+ notifyBrowserCallback(() -> mBrowserCallback.onConnected(MessageBrowser.this,
+ MessageCommandGroup.fromBundle(allowedCommands)));
+ synchronized (mLock) {
+ for (Runnable task : mPendingTasks) {
+ task.run();
+ }
+ mPendingTasks.clear();
+ }
}
@Override
- public void notifyDisconnected() {
+ public void notifyDisconnected(final int seq) {
synchronized (mLock) {
if (mBrowserState == STATE_CLOSING) {
mBrowserState = STATE_CLOSED;
} else if (mBrowserState != STATE_ERROR) {
mBrowserState = STATE_DISCONNECTED;
}
+ mPendingTasks.clear();
}
- MessageBrowser.this.notifyDisconnected();
+ mSequencedFutureManager.close();
+ notifyBrowserCallback(() -> mBrowserCallback.onDisconnected(MessageBrowser.this));
+ }
+
+ @Override
+ public void notifyCommandResult(final int seq, final Bundle result) {
+ mSequencedFutureManager.setFutureResult(seq, result);
}
}
@@ -300,6 +359,7 @@
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
// Note that it's always main-thread.
+ int browserState = STATE_IDLE;
if (DEBUG) {
Log.d(TAG, "onServiceConnected " + componentName + " " + this);
}
@@ -308,26 +368,28 @@
if (!mServiceComponent.equals(componentName)) {
Log.wtf(TAG, "Expected connection to " + mServiceComponent + " but is"
+ " connected to " + componentName);
- mBrowserState = STATE_ERROR;
- return;
+ browserState = mBrowserState = STATE_ERROR;
+ } else {
+ mService = IMessageLibraryService.Stub.asInterface(iBinder);
+ if (mService == null) {
+ Log.wtf(TAG, "Service interface is missing.");
+ browserState = mBrowserState = STATE_ERROR;
+ } else {
+ browserState = mBrowserState = STATE_CONNECTING;
+ try {
+ mService.connect(mBrowserStub,
+ mSequencedFutureManager.obtainNextSequenceNumber(),
+ mConnectionRequest.toBundle());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Service " + mServiceComponent + " has died prematurely");
+ browserState = mBrowserState = STATE_ERROR;
+ }
+ }
}
- mService = IMessageLibraryService.Stub.asInterface(iBinder);
- if (mService == null) {
- Log.wtf(TAG, "Service interface is missing.");
- mBrowserState = STATE_ERROR;
- MessageBrowser.this.notifyDisconnected();
- return;
- }
- mBrowserState = STATE_CONNECTING;
- try {
- mService.connect(mBrowserStub, mNextSequenceNumber++,
- mConnectionRequest.toBundle());
- } catch (RemoteException e) {
- Log.w(TAG, "Service " + mServiceComponent + " has died prematurely");
- mBrowserState = STATE_ERROR;
- MessageBrowser.this.notifyDisconnected();
- close();
- }
+ }
+ if (browserState == STATE_ERROR) {
+ notifyBrowserCallback(
+ () -> mBrowserCallback.onDisconnected(MessageBrowser.this));
}
}
diff --git a/message-browser/browser/src/main/java/androidx/message/browser/MessageLibraryService.java b/message-browser/browser/src/main/java/androidx/message/browser/MessageLibraryService.java
index cadfe16..7933bcc 100644
--- a/message-browser/browser/src/main/java/androidx/message/browser/MessageLibraryService.java
+++ b/message-browser/browser/src/main/java/androidx/message/browser/MessageLibraryService.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -66,11 +67,14 @@
final ArrayMap<IBinder, BrowserRecord> mBrowserRecords = new ArrayMap<>();
private ServiceStub mServiceStub;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ Handler mHandler;
@Override
public void onCreate() {
super.onCreate();
mServiceStub = new ServiceStub();
+ mHandler = new Handler();
}
@Nullable
@@ -108,6 +112,46 @@
}
/**
+ * Called when a browser sent a command which will be sent directly.
+ * <p>
+ * Return {@code true} to accept the command, {@code false} to decline the command.
+ *
+ * @param browserInfo the browser information
+ * @param command a command. This method will be called for every single command.
+ * @return {@code RESULT_SUCCESS} if you want to proceed with incoming command.
+ * Another code for ignore.
+ */
+ public boolean onCommandRequest(@NonNull BrowserInfo browserInfo,
+ @NonNull MessageCommand command) {
+ return true;
+ }
+
+ /**
+ * Called when a browser sent a custom command through
+ * {@link MessageBrowser#sendCustomCommand(MessageCommand, Bundle)}.
+ * <p>
+ * @param browserInfo the browser information
+ * @param customCommand custom command.
+ * @param args optional arguments
+ * @return result of handling custom command. A runtime exception will be thrown if
+ * {@code null} is returned.
+ * @see MessageCommand#COMMAND_CODE_CUSTOM
+ */
+ @NonNull
+ public Bundle onCustomCommand(@NonNull BrowserInfo browserInfo,
+ @NonNull MessageCommand customCommand, @Nullable Bundle args) {
+ return Bundle.EMPTY;
+ }
+
+ void releaseBrowserRecord(BrowserRecord record) {
+ IBinder browserBinder = record.browser.asBinder();
+ browserBinder.unlinkToDeath(record, 0);
+ synchronized (mLock) {
+ mBrowserRecords.remove(browserBinder);
+ }
+ }
+
+ /**
* Information of the connected browser.
* @hide
*/
@@ -167,7 +211,7 @@
final ConnectionRequest request = ConnectionRequest.fromBundle(connectionRequest);
if (request == null) {
try {
- browser.notifyDisconnected();
+ browser.notifyDisconnected(seq);
} catch (RemoteException ex) {
Log.w(TAG, "Calling notifyDisconnected() failed");
}
@@ -194,7 +238,7 @@
}
try {
browserBinder.linkToDeath(record, 0);
- browser.notifyConnected(allowedCommands.toBundle());
+ browser.notifyConnected(seq, allowedCommands.toBundle());
} catch (RemoteException ex) {
Log.w(TAG, "Calling notifyConnected() failed");
synchronized (mLock) {
@@ -203,7 +247,7 @@
}
} else {
try {
- browser.notifyDisconnected();
+ browser.notifyDisconnected(seq);
} catch (RemoteException ex) {
Log.w(TAG, "Calling notifyDisconnected() failed");
}
@@ -220,12 +264,34 @@
BrowserRecord record = mBrowserRecords.remove(browserBinder);
try {
browserBinder.unlinkToDeath(record, 0);
- browser.notifyDisconnected();
+ browser.notifyDisconnected(seq);
} catch (RemoteException e) {
Log.w(TAG, "Calling notifyDisconnected() failed");
}
}
}
+
+ @Override
+ public void sendCustomCommand(IMessageBrowser browser, int seq, Bundle command,
+ Bundle args) {
+ synchronized (mLock) {
+ BrowserRecord record = mBrowserRecords.get(browser.asBinder());
+ if (record == null) {
+ return;
+ }
+ MessageCommand customCommand = MessageCommand.fromBundle(command);
+ mHandler.post(() -> {
+ try {
+ Bundle result = onCommandRequest(record.browserInfo, customCommand)
+ ? onCustomCommand(record.browserInfo, customCommand, args)
+ : Bundle.EMPTY;
+ record.browser.notifyCommandResult(seq, result);
+ } catch (RemoteException e) {
+ releaseBrowserRecord(record);
+ }
+ });
+ }
+ }
}
private class BrowserRecord implements IBinder.DeathRecipient {
diff --git a/message-browser/browser/src/main/java/androidx/message/browser/SequencedFutureManager.java b/message-browser/browser/src/main/java/androidx/message/browser/SequencedFutureManager.java
new file mode 100644
index 0000000..038621341
--- /dev/null
+++ b/message-browser/browser/src/main/java/androidx/message/browser/SequencedFutureManager.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 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 androidx.message.browser;
+
+import android.annotation.SuppressLint;
+import android.util.Log;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.collection.ArrayMap;
+import androidx.concurrent.futures.AbstractResolvableFuture;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages {@link SequencedFuture} that contains sequence number to be shared across the process.
+ */
+class SequencedFutureManager {
+ private static final String TAG = "SequencedFutureManager";
+
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final Object mLock = new Object();
+ @GuardedBy("mLock")
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final ArrayMap<Integer, SequencedFuture<?>> mSeqToFutureMap = new ArrayMap<>();
+ @GuardedBy("mLock")
+ private int mNextSequenceNumber;
+
+ /**
+ * Obtains next sequence number without creating future. Used for methods with no return
+ * (e.g. close())
+ *
+ * @return sequence number
+ */
+ public int obtainNextSequenceNumber() {
+ synchronized (mLock) {
+ return mNextSequenceNumber++;
+ }
+ }
+
+ /**
+ * Creates {@link SequencedFuture} with sequence number. Used to return
+ * {@link ListenableFuture} for remote process call.
+ *
+ * @return AbstractFuture with sequence number
+ */
+ public <T> SequencedFuture<T> createSequencedFuture(T resultWhenClosed) {
+ synchronized (mLock) {
+ int seq = obtainNextSequenceNumber();
+ SequencedFuture<T> result = new SequencedFuture<>(seq, resultWhenClosed);
+ mSeqToFutureMap.put(seq, result);
+ return result;
+ }
+ }
+
+ /**
+ * Sets result of the {@link SequencedFuture} with the sequence id. Specified future will be
+ * removed from the manager.
+ *
+ * @param seq sequence number to find future
+ * @param result result to set
+ */
+ @SuppressWarnings("unchecked")
+ public <T> void setFutureResult(int seq, T result) {
+ synchronized (mLock) {
+ SequencedFuture<?> future = mSeqToFutureMap.remove(seq);
+ if (future != null) {
+ if (result == null
+ || future.getResultWhenClosed().getClass() == result.getClass()) {
+ ((SequencedFuture<T>) future).set(result);
+ } else {
+ Log.w(TAG, "Type mismatch, expected "
+ + future.getResultWhenClosed().getClass()
+ + ", but was " + result.getClass());
+ }
+ }
+ }
+ }
+
+ public void close() {
+ List<SequencedFuture<?>> pendingResults;
+ synchronized (mLock) {
+ pendingResults = new ArrayList<>(mSeqToFutureMap.values());
+ mSeqToFutureMap.clear();
+ }
+ for (SequencedFuture<?> result: pendingResults) {
+ result.setWithTheValueOfResultWhenClosed();
+ }
+ }
+
+ // TODO: Find a way to remove @SuppressLint
+ @SuppressLint("RestrictedApi")
+ static final class SequencedFuture<T> extends AbstractResolvableFuture<T> {
+ private final int mSequenceNumber;
+ private final T mResultWhenClosed;
+
+ SequencedFuture(int seq, @NonNull T resultWhenClosed) {
+ mSequenceNumber = seq;
+ mResultWhenClosed = resultWhenClosed;
+ }
+
+ @Override
+ public boolean set(@Nullable T value) {
+ return super.set(value);
+ }
+
+ void setWithTheValueOfResultWhenClosed() {
+ set(mResultWhenClosed);
+ }
+
+ public int getSequenceNumber() {
+ return mSequenceNumber;
+ }
+
+ public @NonNull T getResultWhenClosed() {
+ return mResultWhenClosed;
+ }
+ }
+}
diff --git a/navigation/navigation-dynamic-features-core/src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallManager.kt b/navigation/navigation-dynamic-features-core/src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallManager.kt
index 6278207..afee9f4 100644
--- a/navigation/navigation-dynamic-features-core/src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallManager.kt
+++ b/navigation/navigation-dynamic-features-core/src/main/java/androidx/navigation/dynamicfeatures/DynamicInstallManager.kt
@@ -27,6 +27,7 @@
import androidx.navigation.get
import com.google.android.play.core.splitcompat.SplitCompat
import com.google.android.play.core.splitinstall.SplitInstallException
+import com.google.android.play.core.splitinstall.SplitInstallHelper
import com.google.android.play.core.splitinstall.SplitInstallManager
import com.google.android.play.core.splitinstall.SplitInstallRequest
import com.google.android.play.core.splitinstall.SplitInstallSessionState
@@ -37,7 +38,7 @@
/**
* Install manager for dynamic features.
*
- * Enables installation of dynamic features.
+ * Enables installation of dynamic features for both installed and instant apps.
*/
open class DynamicInstallManager(
private val context: Context,
@@ -172,6 +173,8 @@
if (splitInstallSessionState.sessionId() == installMonitor.sessionId) {
if (splitInstallSessionState.status() == SplitInstallSessionStatus.INSTALLED) {
SplitCompat.install(context)
+ // Enable immediate usage of dynamic feature modules in an instant app context.
+ SplitInstallHelper.updateAppInfo(context)
}
status.value = splitInstallSessionState
if (splitInstallSessionState.hasTerminalStatus()) {
diff --git a/navigation/navigation-dynamic-features-fragment/src/main/res/values-ar/strings.xml b/navigation/navigation-dynamic-features-fragment/src/main/res/values-ar/strings.xml
index cb7c90e..fb5161a 100644
--- a/navigation/navigation-dynamic-features-fragment/src/main/res/values-ar/strings.xml
+++ b/navigation/navigation-dynamic-features-fragment/src/main/res/values-ar/strings.xml
@@ -21,8 +21,6 @@
<string name="installation_cancelled" msgid="475402237100444685">"تم إلغاء التثبيت."</string>
<string name="installing_module" msgid="5968445461040787716">"جارٍ تثبيت الوحدة:"</string>
<string name="progress" msgid="8366783942222789124">"التقدم:"</string>
- <!-- no translation found for retry (1065327189183624288) -->
- <skip />
- <!-- no translation found for ok (4702104660890557116) -->
- <skip />
+ <string name="retry" msgid="1065327189183624288">"إعادة المحاولة"</string>
+ <string name="ok" msgid="4702104660890557116">"حسنًا"</string>
</resources>
diff --git a/navigation/navigation-dynamic-features-fragment/src/main/res/values-eu/strings.xml b/navigation/navigation-dynamic-features-fragment/src/main/res/values-eu/strings.xml
index d570108..01caed0 100644
--- a/navigation/navigation-dynamic-features-fragment/src/main/res/values-eu/strings.xml
+++ b/navigation/navigation-dynamic-features-fragment/src/main/res/values-eu/strings.xml
@@ -21,8 +21,6 @@
<string name="installation_cancelled" msgid="475402237100444685">"Bertan behera utzi da instalazioa."</string>
<string name="installing_module" msgid="5968445461040787716">"Modulua instalatzen:"</string>
<string name="progress" msgid="8366783942222789124">"Garapena:"</string>
- <!-- no translation found for retry (1065327189183624288) -->
- <skip />
- <!-- no translation found for ok (4702104660890557116) -->
- <skip />
+ <string name="retry" msgid="1065327189183624288">"Saiatu berriro"</string>
+ <string name="ok" msgid="4702104660890557116">"Ados"</string>
</resources>
diff --git a/navigation/navigation-dynamic-features-fragment/src/main/res/values-hi/strings.xml b/navigation/navigation-dynamic-features-fragment/src/main/res/values-hi/strings.xml
index c49ed96..cb05acf 100644
--- a/navigation/navigation-dynamic-features-fragment/src/main/res/values-hi/strings.xml
+++ b/navigation/navigation-dynamic-features-fragment/src/main/res/values-hi/strings.xml
@@ -21,8 +21,6 @@
<string name="installation_cancelled" msgid="475402237100444685">"इंस्टॉल करना रद्द किया गया"</string>
<string name="installing_module" msgid="5968445461040787716">"इंस्टॉल किया जा रहा मॉड्यूल:"</string>
<string name="progress" msgid="8366783942222789124">"प्रगति:"</string>
- <!-- no translation found for retry (1065327189183624288) -->
- <skip />
- <!-- no translation found for ok (4702104660890557116) -->
- <skip />
+ <string name="retry" msgid="1065327189183624288">"फिर कोशिश करें"</string>
+ <string name="ok" msgid="4702104660890557116">"ठीक है"</string>
</resources>
diff --git a/navigation/navigation-safe-args-gradle-plugin/build.gradle b/navigation/navigation-safe-args-gradle-plugin/build.gradle
index b5bc170..7d62068 100644
--- a/navigation/navigation-safe-args-gradle-plugin/build.gradle
+++ b/navigation/navigation-safe-args-gradle-plugin/build.gradle
@@ -35,6 +35,7 @@
api(gradleApi())
implementation(GSON)
testImplementation(gradleTestKit())
+ testImplementation(project(":internal-testutils-gradle-plugin"))
testImplementation(JUNIT)
}
diff --git a/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/BasePluginTest.kt b/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/BasePluginTest.kt
index fc9ef2a..9b3c06c 100644
--- a/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/BasePluginTest.kt
+++ b/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/BasePluginTest.kt
@@ -16,17 +16,14 @@
package androidx.navigation.safeargs.gradle
+import androidx.testutils.gradle.ProjectSetupRule
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome
import org.hamcrest.CoreMatchers
-import org.hamcrest.MatcherAssert
import org.hamcrest.MatcherAssert.assertThat
-import org.junit.Before
import org.junit.Rule
-import org.junit.rules.TemporaryFolder
import java.io.File
-import java.util.Properties
internal const val MAIN_DIR = "androidx/navigation/testapp"
@@ -46,20 +43,10 @@
internal const val SEC = 1000L
abstract class BasePluginTest {
- @Suppress("MemberVisibilityCanBePrivate")
@get:Rule
- val testProjectDir = TemporaryFolder()
+ val projectSetup = ProjectSetupRule()
- internal var buildFile: File = File("")
- internal var prebuiltsRoot = ""
- internal var compileSdkVersion = ""
- internal var buildToolsVersion = ""
- internal var minSdkVersion = ""
- internal var debugKeystore = ""
- internal var navigationCommon = ""
- internal var kotlinStblib = ""
-
- internal fun projectRoot(): File = testProjectDir.root
+ internal fun projectRoot(): File = projectSetup.rootDir
internal fun assertGenerated(name: String, prefix: String? = null): File {
return prefix?.let { assertExists(name, true, it) } ?: assertExists(name, true)
@@ -74,7 +61,7 @@
projectRoot(),
"${prefix}build/$GENERATED_PATH/$name"
)
- MatcherAssert.assertThat(
+ assertThat(
generatedFile.exists(),
CoreMatchers.`is`(ex)
)
@@ -90,92 +77,40 @@
internal fun runGradle(vararg args: String) = gradleBuilder(*args).build()
internal fun runAndFailGradle(vararg args: String) = gradleBuilder(*args).buildAndFail()
- @Before
- fun setup() {
- projectRoot().mkdirs()
- buildFile = File(projectRoot(), "build.gradle")
- buildFile.createNewFile()
- // copy local.properties
- val appToolkitProperties = File("../../local.properties")
- if (appToolkitProperties.exists()) {
- appToolkitProperties.copyTo(
- File(projectRoot(), "local.properties"),
- overwrite = true
- )
- } else {
- File("../../local.properties").copyTo(
- File(projectRoot(), "local.properties"), overwrite = true
- )
- }
- val stream = BasePluginTest::class.java.classLoader.getResourceAsStream("sdk.prop")
- val properties = Properties()
- properties.load(stream)
- prebuiltsRoot = properties.getProperty("prebuiltsRoot")
- compileSdkVersion = properties.getProperty("compileSdkVersion")
- buildToolsVersion = properties.getProperty("buildToolsVersion")
- minSdkVersion = properties.getProperty("minSdkVersion")
- debugKeystore = properties.getProperty("debugKeystore")
- navigationCommon = properties.getProperty("navigationCommon")
- kotlinStblib = properties.getProperty("kotlinStdlib")
-
- val propertiesFile = File(projectRoot(), "gradle.properties")
- propertiesFile.writer().use {
- val props = Properties()
- props.setProperty("android.useAndroidX", "true")
- props.store(it, null)
- }
- }
-
internal fun setupSimpleBuildGradle() {
testData("app-project").copyRecursively(projectRoot())
- buildFile.writeText("""
- plugins {
- id('com.android.application')
- id('androidx.navigation.safeargs')
- }
-
- repositories {
- maven { url "$prebuiltsRoot/androidx/external" }
- maven { url "$prebuiltsRoot/androidx/internal" }
- }
-
- android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
-
- defaultConfig {
- minSdkVersion $minSdkVersion
+ projectSetup.writeDefaultBuildGradle(
+ prefix = """
+ plugins {
+ id('com.android.application')
+ id('androidx.navigation.safeargs')
}
-
- signingConfigs {
- debug {
- storeFile file("$debugKeystore")
- }
+ """.trimIndent(),
+ suffix = """
+ dependencies {
+ implementation "${projectSetup.props.navigationCommon}"
}
- }
-
- dependencies {
- implementation "$navigationCommon"
- }
- """.trimIndent()
+ """.trimIndent()
)
}
internal fun setupMultiModuleBuildGradle() {
testData("multimodule-project").copyRecursively(projectRoot())
- buildFile.writeText("""
+ val props = projectSetup.props
+ projectSetup.buildFile.writeText(
+ """
buildscript {
- ext.compileSdk = $compileSdkVersion
- ext.buildTools = "$buildToolsVersion"
- ext.minSdk = $minSdkVersion
- ext.debugKeystoreFile = "$debugKeystore"
- ext.navigationCommonDep = "$navigationCommon"
+ ext.compileSdk = ${props.compileSdkVersion}
+ ext.buildTools = "${props.buildToolsVersion}"
+ ext.minSdk = ${props.minSdkVersion}
+ ext.debugKeystoreFile = "${props.debugKeystore}"
+ ext.navigationCommonDep = "${props.navigationCommon}"
}
allprojects {
repositories {
- maven { url "$prebuiltsRoot/androidx/external" }
- maven { url "$prebuiltsRoot/androidx/internal" }
+ maven { url "${props.prebuiltsRoot}/androidx/external" }
+ maven { url "${props.prebuiltsRoot}/androidx/internal" }
}
}
""".trimIndent()
@@ -184,38 +119,20 @@
internal fun setupSimpleKotlinBuildGradle() {
testData("app-project-kotlin").copyRecursively(projectRoot())
- buildFile.writeText("""
- plugins {
- id('com.android.application')
- id('kotlin-android')
- id('androidx.navigation.safeargs.kotlin')
- }
-
- repositories {
- maven { url "$prebuiltsRoot/androidx/external" }
- maven { url "$prebuiltsRoot/androidx/internal" }
- }
-
- android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
-
- defaultConfig {
- minSdkVersion $minSdkVersion
+ projectSetup.writeDefaultBuildGradle(
+ prefix = """
+ plugins {
+ id('com.android.application')
+ id('kotlin-android')
+ id('androidx.navigation.safeargs.kotlin')
}
-
- signingConfigs {
- debug {
- storeFile file("$debugKeystore")
- }
+ """.trimIndent(),
+ suffix = """
+ dependencies {
+ implementation "${projectSetup.props.kotlinStblib}"
+ implementation "${projectSetup.props.navigationCommon}"
}
- }
-
- dependencies {
- implementation "$kotlinStblib"
- implementation "$navigationCommon"
- }
- """.trimIndent()
+ """.trimIndent()
)
}
}
diff --git a/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/JavaPluginTest.kt b/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/JavaPluginTest.kt
index 114186e..9398dcdb4 100644
--- a/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/JavaPluginTest.kt
+++ b/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/JavaPluginTest.kt
@@ -27,49 +27,32 @@
@Test
fun runGenerateTask() {
testData("app-project").copyRecursively(projectRoot())
- buildFile.writeText("""
- plugins {
- id('com.android.application')
- id('androidx.navigation.safeargs')
- }
-
- repositories {
- maven { url "$prebuiltsRoot/androidx/external" }
- maven { url "$prebuiltsRoot/androidx/internal" }
- }
-
- android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
- flavorDimensions "mode"
- productFlavors {
- foo {
- dimension "mode"
- applicationIdSuffix ".foo"
- }
- notfoo {
- dimension "mode"
- }
-
+ projectSetup.writeDefaultBuildGradle(
+ prefix = """
+ plugins {
+ id('com.android.application')
+ id('androidx.navigation.safeargs')
}
-
- defaultConfig {
- minSdkVersion $minSdkVersion
- }
-
- signingConfigs {
- debug {
- storeFile file("$debugKeystore")
+ """.trimIndent(),
+ suffix = """
+ android {
+ flavorDimensions "mode"
+ productFlavors {
+ foo {
+ dimension "mode"
+ applicationIdSuffix ".foo"
+ }
+ notfoo {
+ dimension "mode"
+ }
}
}
- }
- dependencies {
- implementation "$navigationCommon"
- }
- """.trimIndent()
+ dependencies {
+ implementation "${projectSetup.props.navigationCommon}"
+ }
+ """.trimIndent()
)
-
runGradle("assembleNotfooDebug", "assembleFooDebug")
.assertSuccessfulTask("assembleNotfooDebug")
.assertSuccessfulTask("assembleFooDebug")
diff --git a/paging/common/api/3.0.0-alpha01.txt b/paging/common/api/3.0.0-alpha01.txt
index 4ef6eae..9dab050 100644
--- a/paging/common/api/3.0.0-alpha01.txt
+++ b/paging/common/api/3.0.0-alpha01.txt
@@ -143,8 +143,8 @@
}
public final class PagedDataFlowBuilder<Key, Value> {
- ctor public PagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagedList.Config config);
- ctor @Deprecated public PagedDataFlowBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagedList.Config config);
+ ctor public PagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagingConfig config);
+ ctor @Deprecated public PagedDataFlowBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagingConfig config);
method public kotlinx.coroutines.flow.Flow<androidx.paging.PagedData<Value>> build();
method public androidx.paging.PagedDataFlowBuilder<Key,Value> setInitialKey(Key? initialKey);
}
@@ -292,6 +292,29 @@
public final class PagedSourceKt {
}
+ public final class PagingConfig {
+ ctor public PagingConfig(int pageSize, int prefetchDistance, boolean enablePlaceholders, int initialLoadSize, int maxSize);
+ field public static final androidx.paging.PagingConfig.Companion! Companion;
+ field public static final int MAX_SIZE_UNBOUNDED = 2147483647; // 0x7fffffff
+ field public final boolean enablePlaceholders;
+ field public final int initialLoadSize;
+ field public final int maxSize;
+ field public final int pageSize;
+ field public final int prefetchDistance;
+ }
+
+ public static final class PagingConfig.Builder {
+ ctor public PagingConfig.Builder(int pageSize);
+ method public androidx.paging.PagingConfig build();
+ method public androidx.paging.PagingConfig.Builder setEnablePlaceholders(boolean enablePlaceholders);
+ method public androidx.paging.PagingConfig.Builder setInitialLoadSizeHint(@IntRange(from=1) int initialLoadSizeHint);
+ method public androidx.paging.PagingConfig.Builder setMaxSize(@IntRange(from=2) int maxSize);
+ method public androidx.paging.PagingConfig.Builder setPrefetchDistance(@IntRange(from=0) int prefetchDistance);
+ }
+
+ public static final class PagingConfig.Companion {
+ }
+
public abstract class PositionalDataSource<T> extends androidx.paging.DataSource<java.lang.Integer,T> {
ctor public PositionalDataSource();
method public static final int computeInitialLoadPosition(androidx.paging.PositionalDataSource.LoadInitialParams params, int totalCount);
diff --git a/paging/common/api/api_lint.ignore b/paging/common/api/api_lint.ignore
index 7a58a78..e6f73d2 100644
--- a/paging/common/api/api_lint.ignore
+++ b/paging/common/api/api_lint.ignore
@@ -9,6 +9,8 @@
MinMaxConstant: androidx.paging.PagedList.Config#MAX_SIZE_UNBOUNDED:
If min/max could change in future, make them dynamic methods: androidx.paging.PagedList.Config#MAX_SIZE_UNBOUNDED
+MinMaxConstant: androidx.paging.PagingConfig#MAX_SIZE_UNBOUNDED:
+ If min/max could change in future, make them dynamic methods: androidx.paging.PagingConfig#MAX_SIZE_UNBOUNDED
RegistrationName: androidx.paging.DataSource#addInvalidatedCallback(androidx.paging.DataSource.InvalidatedCallback):
diff --git a/paging/common/api/current.txt b/paging/common/api/current.txt
index 4ef6eae..9dab050 100644
--- a/paging/common/api/current.txt
+++ b/paging/common/api/current.txt
@@ -143,8 +143,8 @@
}
public final class PagedDataFlowBuilder<Key, Value> {
- ctor public PagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagedList.Config config);
- ctor @Deprecated public PagedDataFlowBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagedList.Config config);
+ ctor public PagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagingConfig config);
+ ctor @Deprecated public PagedDataFlowBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagingConfig config);
method public kotlinx.coroutines.flow.Flow<androidx.paging.PagedData<Value>> build();
method public androidx.paging.PagedDataFlowBuilder<Key,Value> setInitialKey(Key? initialKey);
}
@@ -292,6 +292,29 @@
public final class PagedSourceKt {
}
+ public final class PagingConfig {
+ ctor public PagingConfig(int pageSize, int prefetchDistance, boolean enablePlaceholders, int initialLoadSize, int maxSize);
+ field public static final androidx.paging.PagingConfig.Companion! Companion;
+ field public static final int MAX_SIZE_UNBOUNDED = 2147483647; // 0x7fffffff
+ field public final boolean enablePlaceholders;
+ field public final int initialLoadSize;
+ field public final int maxSize;
+ field public final int pageSize;
+ field public final int prefetchDistance;
+ }
+
+ public static final class PagingConfig.Builder {
+ ctor public PagingConfig.Builder(int pageSize);
+ method public androidx.paging.PagingConfig build();
+ method public androidx.paging.PagingConfig.Builder setEnablePlaceholders(boolean enablePlaceholders);
+ method public androidx.paging.PagingConfig.Builder setInitialLoadSizeHint(@IntRange(from=1) int initialLoadSizeHint);
+ method public androidx.paging.PagingConfig.Builder setMaxSize(@IntRange(from=2) int maxSize);
+ method public androidx.paging.PagingConfig.Builder setPrefetchDistance(@IntRange(from=0) int prefetchDistance);
+ }
+
+ public static final class PagingConfig.Companion {
+ }
+
public abstract class PositionalDataSource<T> extends androidx.paging.DataSource<java.lang.Integer,T> {
ctor public PositionalDataSource();
method public static final int computeInitialLoadPosition(androidx.paging.PositionalDataSource.LoadInitialParams params, int totalCount);
diff --git a/paging/common/api/public_plus_experimental_3.0.0-alpha01.txt b/paging/common/api/public_plus_experimental_3.0.0-alpha01.txt
index 4ef6eae..9dab050 100644
--- a/paging/common/api/public_plus_experimental_3.0.0-alpha01.txt
+++ b/paging/common/api/public_plus_experimental_3.0.0-alpha01.txt
@@ -143,8 +143,8 @@
}
public final class PagedDataFlowBuilder<Key, Value> {
- ctor public PagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagedList.Config config);
- ctor @Deprecated public PagedDataFlowBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagedList.Config config);
+ ctor public PagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagingConfig config);
+ ctor @Deprecated public PagedDataFlowBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagingConfig config);
method public kotlinx.coroutines.flow.Flow<androidx.paging.PagedData<Value>> build();
method public androidx.paging.PagedDataFlowBuilder<Key,Value> setInitialKey(Key? initialKey);
}
@@ -292,6 +292,29 @@
public final class PagedSourceKt {
}
+ public final class PagingConfig {
+ ctor public PagingConfig(int pageSize, int prefetchDistance, boolean enablePlaceholders, int initialLoadSize, int maxSize);
+ field public static final androidx.paging.PagingConfig.Companion! Companion;
+ field public static final int MAX_SIZE_UNBOUNDED = 2147483647; // 0x7fffffff
+ field public final boolean enablePlaceholders;
+ field public final int initialLoadSize;
+ field public final int maxSize;
+ field public final int pageSize;
+ field public final int prefetchDistance;
+ }
+
+ public static final class PagingConfig.Builder {
+ ctor public PagingConfig.Builder(int pageSize);
+ method public androidx.paging.PagingConfig build();
+ method public androidx.paging.PagingConfig.Builder setEnablePlaceholders(boolean enablePlaceholders);
+ method public androidx.paging.PagingConfig.Builder setInitialLoadSizeHint(@IntRange(from=1) int initialLoadSizeHint);
+ method public androidx.paging.PagingConfig.Builder setMaxSize(@IntRange(from=2) int maxSize);
+ method public androidx.paging.PagingConfig.Builder setPrefetchDistance(@IntRange(from=0) int prefetchDistance);
+ }
+
+ public static final class PagingConfig.Companion {
+ }
+
public abstract class PositionalDataSource<T> extends androidx.paging.DataSource<java.lang.Integer,T> {
ctor public PositionalDataSource();
method public static final int computeInitialLoadPosition(androidx.paging.PositionalDataSource.LoadInitialParams params, int totalCount);
diff --git a/paging/common/api/public_plus_experimental_current.txt b/paging/common/api/public_plus_experimental_current.txt
index 4ef6eae..9dab050 100644
--- a/paging/common/api/public_plus_experimental_current.txt
+++ b/paging/common/api/public_plus_experimental_current.txt
@@ -143,8 +143,8 @@
}
public final class PagedDataFlowBuilder<Key, Value> {
- ctor public PagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagedList.Config config);
- ctor @Deprecated public PagedDataFlowBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagedList.Config config);
+ ctor public PagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagingConfig config);
+ ctor @Deprecated public PagedDataFlowBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagingConfig config);
method public kotlinx.coroutines.flow.Flow<androidx.paging.PagedData<Value>> build();
method public androidx.paging.PagedDataFlowBuilder<Key,Value> setInitialKey(Key? initialKey);
}
@@ -292,6 +292,29 @@
public final class PagedSourceKt {
}
+ public final class PagingConfig {
+ ctor public PagingConfig(int pageSize, int prefetchDistance, boolean enablePlaceholders, int initialLoadSize, int maxSize);
+ field public static final androidx.paging.PagingConfig.Companion! Companion;
+ field public static final int MAX_SIZE_UNBOUNDED = 2147483647; // 0x7fffffff
+ field public final boolean enablePlaceholders;
+ field public final int initialLoadSize;
+ field public final int maxSize;
+ field public final int pageSize;
+ field public final int prefetchDistance;
+ }
+
+ public static final class PagingConfig.Builder {
+ ctor public PagingConfig.Builder(int pageSize);
+ method public androidx.paging.PagingConfig build();
+ method public androidx.paging.PagingConfig.Builder setEnablePlaceholders(boolean enablePlaceholders);
+ method public androidx.paging.PagingConfig.Builder setInitialLoadSizeHint(@IntRange(from=1) int initialLoadSizeHint);
+ method public androidx.paging.PagingConfig.Builder setMaxSize(@IntRange(from=2) int maxSize);
+ method public androidx.paging.PagingConfig.Builder setPrefetchDistance(@IntRange(from=0) int prefetchDistance);
+ }
+
+ public static final class PagingConfig.Companion {
+ }
+
public abstract class PositionalDataSource<T> extends androidx.paging.DataSource<java.lang.Integer,T> {
ctor public PositionalDataSource();
method public static final int computeInitialLoadPosition(androidx.paging.PositionalDataSource.LoadInitialParams params, int totalCount);
diff --git a/paging/common/api/restricted_3.0.0-alpha01.txt b/paging/common/api/restricted_3.0.0-alpha01.txt
index c8fbb86..2b8b961 100644
--- a/paging/common/api/restricted_3.0.0-alpha01.txt
+++ b/paging/common/api/restricted_3.0.0-alpha01.txt
@@ -166,14 +166,14 @@
method public final void connect(kotlinx.coroutines.flow.Flow<androidx.paging.PagedData<T>> flow, kotlinx.coroutines.CoroutineScope scope, androidx.paging.PresenterCallback callback);
method public final operator T? get(int index);
method public final int getSize();
- method public abstract suspend Object! performDiff(androidx.paging.NullPaddedList<T> previous, androidx.paging.NullPaddedList<T> p, kotlin.coroutines.Continuation<? super kotlin.Unit> p1);
+ method public abstract suspend Object! performDiff(androidx.paging.NullPaddedList<T> previousList, androidx.paging.NullPaddedList<T> newList, java.util.Map<androidx.paging.LoadType,? extends androidx.paging.LoadState> newLoadStates, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
method public final void retry();
property public final int size;
}
public final class PagedDataFlowBuilder<Key, Value> {
- ctor public PagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagedList.Config config);
- ctor @Deprecated public PagedDataFlowBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagedList.Config config);
+ ctor public PagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagingConfig config);
+ ctor @Deprecated public PagedDataFlowBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagingConfig config);
method public kotlinx.coroutines.flow.Flow<androidx.paging.PagedData<Value>> build();
method public androidx.paging.PagedDataFlowBuilder<Key,Value> setInitialKey(Key? initialKey);
}
@@ -345,6 +345,29 @@
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static <Key> androidx.paging.PagedSource.LoadParams<Key> toRefreshLoadParams(androidx.paging.PagedList.Config, Key? key);
}
+ public final class PagingConfig {
+ ctor public PagingConfig(int pageSize, int prefetchDistance, boolean enablePlaceholders, int initialLoadSize, int maxSize);
+ field public static final androidx.paging.PagingConfig.Companion! Companion;
+ field public static final int MAX_SIZE_UNBOUNDED = 2147483647; // 0x7fffffff
+ field public final boolean enablePlaceholders;
+ field public final int initialLoadSize;
+ field public final int maxSize;
+ field public final int pageSize;
+ field public final int prefetchDistance;
+ }
+
+ public static final class PagingConfig.Builder {
+ ctor public PagingConfig.Builder(int pageSize);
+ method public androidx.paging.PagingConfig build();
+ method public androidx.paging.PagingConfig.Builder setEnablePlaceholders(boolean enablePlaceholders);
+ method public androidx.paging.PagingConfig.Builder setInitialLoadSizeHint(@IntRange(from=1) int initialLoadSizeHint);
+ method public androidx.paging.PagingConfig.Builder setMaxSize(@IntRange(from=2) int maxSize);
+ method public androidx.paging.PagingConfig.Builder setPrefetchDistance(@IntRange(from=0) int prefetchDistance);
+ }
+
+ public static final class PagingConfig.Companion {
+ }
+
public abstract class PositionalDataSource<T> extends androidx.paging.DataSource<java.lang.Integer,T> {
ctor public PositionalDataSource();
method public static final int computeInitialLoadPosition(androidx.paging.PositionalDataSource.LoadInitialParams params, int totalCount);
@@ -384,7 +407,7 @@
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public interface PresenterCallback {
method public void onChanged(int position, int count);
- method public void onInserted(int position, int count, java.util.Map<androidx.paging.LoadType,? extends androidx.paging.LoadState>? loadStates);
+ method public void onInserted(int position, int count);
method public void onRemoved(int position, int count);
method public void onStateUpdate(androidx.paging.LoadType loadType, androidx.paging.LoadState loadState);
}
diff --git a/paging/common/api/restricted_current.txt b/paging/common/api/restricted_current.txt
index c8fbb86..2b8b961 100644
--- a/paging/common/api/restricted_current.txt
+++ b/paging/common/api/restricted_current.txt
@@ -166,14 +166,14 @@
method public final void connect(kotlinx.coroutines.flow.Flow<androidx.paging.PagedData<T>> flow, kotlinx.coroutines.CoroutineScope scope, androidx.paging.PresenterCallback callback);
method public final operator T? get(int index);
method public final int getSize();
- method public abstract suspend Object! performDiff(androidx.paging.NullPaddedList<T> previous, androidx.paging.NullPaddedList<T> p, kotlin.coroutines.Continuation<? super kotlin.Unit> p1);
+ method public abstract suspend Object! performDiff(androidx.paging.NullPaddedList<T> previousList, androidx.paging.NullPaddedList<T> newList, java.util.Map<androidx.paging.LoadType,? extends androidx.paging.LoadState> newLoadStates, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
method public final void retry();
property public final int size;
}
public final class PagedDataFlowBuilder<Key, Value> {
- ctor public PagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagedList.Config config);
- ctor @Deprecated public PagedDataFlowBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagedList.Config config);
+ ctor public PagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagingConfig config);
+ ctor @Deprecated public PagedDataFlowBuilder(androidx.paging.DataSource.Factory<Key,Value> dataSourceFactory, androidx.paging.PagingConfig config);
method public kotlinx.coroutines.flow.Flow<androidx.paging.PagedData<Value>> build();
method public androidx.paging.PagedDataFlowBuilder<Key,Value> setInitialKey(Key? initialKey);
}
@@ -345,6 +345,29 @@
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static <Key> androidx.paging.PagedSource.LoadParams<Key> toRefreshLoadParams(androidx.paging.PagedList.Config, Key? key);
}
+ public final class PagingConfig {
+ ctor public PagingConfig(int pageSize, int prefetchDistance, boolean enablePlaceholders, int initialLoadSize, int maxSize);
+ field public static final androidx.paging.PagingConfig.Companion! Companion;
+ field public static final int MAX_SIZE_UNBOUNDED = 2147483647; // 0x7fffffff
+ field public final boolean enablePlaceholders;
+ field public final int initialLoadSize;
+ field public final int maxSize;
+ field public final int pageSize;
+ field public final int prefetchDistance;
+ }
+
+ public static final class PagingConfig.Builder {
+ ctor public PagingConfig.Builder(int pageSize);
+ method public androidx.paging.PagingConfig build();
+ method public androidx.paging.PagingConfig.Builder setEnablePlaceholders(boolean enablePlaceholders);
+ method public androidx.paging.PagingConfig.Builder setInitialLoadSizeHint(@IntRange(from=1) int initialLoadSizeHint);
+ method public androidx.paging.PagingConfig.Builder setMaxSize(@IntRange(from=2) int maxSize);
+ method public androidx.paging.PagingConfig.Builder setPrefetchDistance(@IntRange(from=0) int prefetchDistance);
+ }
+
+ public static final class PagingConfig.Companion {
+ }
+
public abstract class PositionalDataSource<T> extends androidx.paging.DataSource<java.lang.Integer,T> {
ctor public PositionalDataSource();
method public static final int computeInitialLoadPosition(androidx.paging.PositionalDataSource.LoadInitialParams params, int totalCount);
@@ -384,7 +407,7 @@
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public interface PresenterCallback {
method public void onChanged(int position, int count);
- method public void onInserted(int position, int count, java.util.Map<androidx.paging.LoadType,? extends androidx.paging.LoadState>? loadStates);
+ method public void onInserted(int position, int count);
method public void onRemoved(int position, int count);
method public void onStateUpdate(androidx.paging.LoadType loadType, androidx.paging.LoadState loadState);
}
diff --git a/paging/common/build.gradle b/paging/common/build.gradle
index 39ea933..831d468 100644
--- a/paging/common/build.gradle
+++ b/paging/common/build.gradle
@@ -38,6 +38,7 @@
testImplementation MOCKITO_KOTLIN, {
exclude group: 'org.mockito' // to keep control on the mockito version
}
+ testImplementation project(':paging:paging-testutils')
testImplementation project(':internal-testutils-common')
testImplementation project(':internal-testutils-ktx')
testImplementation(KOTLIN_TEST)
diff --git a/paging/common/src/main/kotlin/androidx/paging/PageFetcher.kt b/paging/common/src/main/kotlin/androidx/paging/PageFetcher.kt
index f44ac5b..1bc88cb 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PageFetcher.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PageFetcher.kt
@@ -29,7 +29,7 @@
internal class PageFetcher<Key : Any, Value : Any>(
private val pagedSourceFactory: () -> PagedSource<Key, Value>,
private val initialKey: Key?,
- private val config: PagedList.Config
+ private val config: PagingConfig
) {
// NOTE: This channel is conflated, which means it has a buffer size of 1, and will always
// broadcast the latest value received.
diff --git a/paging/common/src/main/kotlin/androidx/paging/PagePresenter.kt b/paging/common/src/main/kotlin/androidx/paging/PagePresenter.kt
index aecb2cb..e3b0b8b 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PagePresenter.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PagePresenter.kt
@@ -23,11 +23,19 @@
import androidx.paging.LoadType.START
import androidx.paging.PageEvent.Insert.Companion.Refresh
-/** @hide */
+/**
+ * Callbacks for the presenter/adapter to listen to the state of pagination data.
+ *
+ * Note that these won't map directly to PageEvents, since PageEvents can cause several adapter
+ * events that should all be dispatched to the presentation layer at once - as part of the same
+ * frame.
+ *
+ * @hide
+ */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface PresenterCallback {
fun onChanged(position: Int, count: Int)
- fun onInserted(position: Int, count: Int, loadStates: Map<LoadType, LoadState>?)
+ fun onInserted(position: Int, count: Int)
fun onRemoved(position: Int, count: Int)
fun onStateUpdate(loadType: LoadType, loadState: LoadState)
}
@@ -153,10 +161,10 @@
// ... then trigger callbacks, so callbacks won't see inconsistent state
callback.onChanged(placeholdersChangedPos, placeholdersChangedCount)
- callback.onInserted(itemsInsertedPos, itemsInsertedCount, insert.loadStates)
+ callback.onInserted(itemsInsertedPos, itemsInsertedCount)
val placeholderInsertedCount = size - oldSize - itemsInsertedCount
if (placeholderInsertedCount > 0) {
- callback.onInserted(0, placeholderInsertedCount, insert.loadStates)
+ callback.onInserted(0, placeholderInsertedCount)
} else if (placeholderInsertedCount < 0) {
callback.onRemoved(0, -placeholderInsertedCount)
}
@@ -175,19 +183,19 @@
// ... then trigger callbacks, so callbacks won't see inconsistent state
callback.onChanged(placeholdersChangedPos, placeholdersChangedCount)
- callback.onInserted(itemsInsertedPos, itemsInsertedCount, insert.loadStates)
+ callback.onInserted(itemsInsertedPos, itemsInsertedCount)
val placeholderInsertedCount = size - oldSize - itemsInsertedCount
if (placeholderInsertedCount > 0) {
callback.onInserted(
position = size - placeholderInsertedCount,
- count = placeholderInsertedCount,
- loadStates = insert.loadStates
+ count = placeholderInsertedCount
)
} else if (placeholderInsertedCount < 0) {
callback.onRemoved(size, -placeholderInsertedCount)
}
}
}
+ insert.loadStates.entries.forEach { callback.onStateUpdate(it.key, it.value) }
}
private fun dropPages(drop: PageEvent.Drop<T>, callback: PresenterCallback) {
@@ -213,10 +221,13 @@
callback.onRemoved(itemsRemovedPos, itemsRemovedCount)
val placeholderInsertedCount = size - oldSize + itemsRemovedCount
if (placeholderInsertedCount > 0) {
- callback.onInserted(0, placeholderInsertedCount, null)
+ callback.onInserted(0, placeholderInsertedCount)
} else if (placeholderInsertedCount < 0) {
callback.onRemoved(0, -placeholderInsertedCount)
}
+
+ // dropping from start implies start is idle
+ callback.onStateUpdate(START, Idle)
} else {
val removeCount = pages.takeLast(drop.count).fullCount()
@@ -238,10 +249,13 @@
callback.onRemoved(itemsRemovedPos, itemsRemovedCount)
val placeholderInsertedCount = size - oldSize + itemsRemovedCount
if (placeholderInsertedCount > 0) {
- callback.onInserted(size, placeholderInsertedCount, null)
+ callback.onInserted(size, placeholderInsertedCount)
} else if (placeholderInsertedCount < 0) {
callback.onRemoved(size, -placeholderInsertedCount)
}
+
+ // dropping from end implies end is idle
+ callback.onStateUpdate(END, Idle)
}
}
diff --git a/paging/common/src/main/kotlin/androidx/paging/PagedDataDiffer.kt b/paging/common/src/main/kotlin/androidx/paging/PagedDataDiffer.kt
index 5bc3457..1be1bbf 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PagedDataDiffer.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PagedDataDiffer.kt
@@ -39,7 +39,11 @@
private var presenter: PagePresenter<T> = PagePresenter.initial()
private var receiver: UiReceiver? = null
- abstract suspend fun performDiff(previous: NullPaddedList<T>, new: NullPaddedList<T>)
+ abstract suspend fun performDiff(
+ previousList: NullPaddedList<T>,
+ newList: NullPaddedList<T>,
+ newLoadStates: Map<LoadType, LoadState>
+ )
@UseExperimental(ExperimentalCoroutinesApi::class)
fun connect(flow: Flow<PagedData<T>>, scope: CoroutineScope, callback: PresenterCallback) {
@@ -54,7 +58,11 @@
val event = pair.second
if (event is PageEvent.Insert && event.loadType == LoadType.REFRESH) {
val newPresenter = PagePresenter(event)
- performDiff(previous = presenter, new = newPresenter)
+ performDiff(
+ previousList = presenter,
+ newList = newPresenter,
+ newLoadStates = event.loadStates
+ )
presenter = newPresenter
receiver = pair.first.receiver
} else {
diff --git a/paging/common/src/main/kotlin/androidx/paging/PagedDataFlowBuilder.kt b/paging/common/src/main/kotlin/androidx/paging/PagedDataFlowBuilder.kt
index dfba9f2..7a57944 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PagedDataFlowBuilder.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PagedDataFlowBuilder.kt
@@ -26,12 +26,12 @@
*/
class PagedDataFlowBuilder<Key : Any, Value : Any>(
private val pagedSourceFactory: () -> PagedSource<Key, Value>,
- private val config: PagedList.Config
+ private val config: PagingConfig
) {
@Deprecated("DataSource is deprecated and has been replaced by PagedSource")
constructor(
dataSourceFactory: DataSource.Factory<Key, Value>,
- config: PagedList.Config
+ config: PagingConfig
) : this(dataSourceFactory.asPagedSourceFactory(), config)
private var initialKey: Key? = null
diff --git a/paging/common/src/main/kotlin/androidx/paging/PagedList.kt b/paging/common/src/main/kotlin/androidx/paging/PagedList.kt
index 3352168..2cffd56 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PagedList.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PagedList.kt
@@ -366,7 +366,7 @@
) : this(
pagedSource = pagedSource,
initialPage = initialPage,
- config = PagedList.Config.Builder().setPageSize(pageSize).build()
+ config = Builder().setPageSize(pageSize).build()
)
/**
@@ -553,7 +553,7 @@
* Configures how a [PagedList] loads content from its [PagedSource].
*
* Use [Config.Builder] to construct and define custom loading behavior, such as
- * [Builder.setPageSize], which defines number of items loaded at a time}.
+ * [Builder.setPageSize], which defines number of items loaded at a time.
*/
class Config internal constructor(
/**
diff --git a/paging/common/src/main/kotlin/androidx/paging/Pager.kt b/paging/common/src/main/kotlin/androidx/paging/Pager.kt
index a49c962..0bf290f 100644
--- a/paging/common/src/main/kotlin/androidx/paging/Pager.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/Pager.kt
@@ -59,7 +59,7 @@
internal class Pager<Key : Any, Value : Any>(
internal val initialKey: Key?,
internal val pagedSource: PagedSource<Key, Value>,
- private val config: PagedList.Config
+ private val config: PagingConfig
) {
private val retryChannel = Channel<Unit>(CONFLATED)
private val hintChannel = BroadcastChannel<ViewportHint>(CONFLATED)
@@ -203,7 +203,7 @@
LoadParams(
loadType = loadType,
key = key,
- loadSize = if (loadType == REFRESH) config.initialLoadSizeHint else config.pageSize,
+ loadSize = if (loadType == REFRESH) config.initialLoadSize else config.pageSize,
placeholdersEnabled = config.enablePlaceholders,
pageSize = config.pageSize
)
diff --git a/paging/common/src/main/kotlin/androidx/paging/PagingConfig.kt b/paging/common/src/main/kotlin/androidx/paging/PagingConfig.kt
new file mode 100644
index 0000000..de4ee7a
--- /dev/null
+++ b/paging/common/src/main/kotlin/androidx/paging/PagingConfig.kt
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2020 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.paging
+
+import androidx.annotation.IntRange
+
+/**
+ * Configures how to load content from a [PagedSource].
+ *
+ * Use [PagingConfig.Builder] to construct and define custom loading behavior, such as
+ * [pageSize], which defines number of items loaded at a time.
+ */
+class PagingConfig(
+ /**
+ * Defines the number of items loaded at once from the [PagedSource].
+ *
+ * Should be several times the number of visible items onscreen.
+ *
+ * Configuring your page size depends on how your data is being loaded and used. Smaller
+ * page sizes improve memory usage, latency, and avoid GC churn. Larger pages generally
+ * improve loading throughput, to a point (avoid loading more than 2MB from SQLite at
+ * once, since it incurs extra cost).
+ *
+ * If you're loading data for very large, social-media style cards that take up most of
+ * a screen, and your database isn't a bottleneck, 10-20 may make sense. If you're
+ * displaying dozens of items in a tiled grid, which can present items during a scroll
+ * much more quickly, consider closer to 100.
+ */
+ @JvmField
+ val pageSize: Int,
+ /**
+ * Prefetch distance which defines how far ahead to load.
+ *
+ * If this value is set to 50, the paged list will attempt to load 50 items in advance of
+ * data that's already been accessed.
+ *
+ * @see PagedList.loadAround
+ */
+ @JvmField
+ val prefetchDistance: Int = pageSize,
+ /**
+ * Defines whether the [PagedList] may display null placeholders, if the [PagedSource]
+ * provides them.
+ */
+ @JvmField
+ val enablePlaceholders: Boolean = true,
+
+ /**
+ * Size requested size for initial load of from [PagedSource], generally larger than a regular
+ * page.
+ */
+ @JvmField
+ val initialLoadSize: Int = pageSize * DEFAULT_INITIAL_PAGE_MULTIPLIER,
+ /**
+ * Defines the maximum number of items that may be loaded into this pagedList before pages
+ * should be dropped.
+ *
+ * If set to [MAX_SIZE_UNBOUNDED], pages will never be dropped.
+ *
+ * @see MAX_SIZE_UNBOUNDED
+ * @see Builder.setMaxSize
+ */
+ @JvmField
+ val maxSize: Int = MAX_SIZE_UNBOUNDED
+) {
+ init {
+ if (!enablePlaceholders && prefetchDistance == 0) {
+ throw IllegalArgumentException(
+ "Placeholders and prefetch are the only ways" +
+ " to trigger loading of more data in the PagedList, so either" +
+ " placeholders must be enabled, or prefetch distance must be > 0."
+ )
+ }
+ if (maxSize != MAX_SIZE_UNBOUNDED && maxSize < pageSize + prefetchDistance * 2) {
+ throw IllegalArgumentException(
+ "Maximum size must be at least pageSize + 2*prefetchDist" +
+ ", pageSize=$pageSize, prefetchDist=$prefetchDistance" +
+ ", maxSize=$maxSize"
+ )
+ }
+ }
+ companion object {
+ /**
+ * When [maxSize] is set to [MAX_SIZE_UNBOUNDED], the maximum number of items loaded is
+ * unbounded, and pages will never be dropped.
+ */
+ const val MAX_SIZE_UNBOUNDED = Int.MAX_VALUE
+ internal const val DEFAULT_INITIAL_PAGE_MULTIPLIER = 3
+ }
+
+ /**
+ * Builder class for [PagingConfig] for Java callers.
+ *
+ * Kotlin callers should use the Config constructor directly.
+ */
+ class Builder(
+ private val pageSize: Int
+ ) {
+ private var prefetchDistance = -1
+ private var initialLoadSizeHint = -1
+ private var enablePlaceholders = true
+ private var maxSize = MAX_SIZE_UNBOUNDED
+
+ /**
+ * Defines how far from the edge of loaded content an access must be to trigger further
+ * loading.
+ *
+ * Should be several times the number of visible items onscreen.
+ *
+ * If not set, defaults to page size.
+ *
+ * A value of 0 indicates that no list items will be loaded until they are specifically
+ * requested. This is generally not recommended, so that users don't observe a
+ * placeholder item (with placeholders) or end of list (without) while scrolling.
+ *
+ * @param prefetchDistance Distance the [PagedList] should prefetch.
+ * @return this
+ */
+ fun setPrefetchDistance(@IntRange(from = 0) prefetchDistance: Int) = apply {
+ this.prefetchDistance = prefetchDistance
+ }
+
+ /**
+ * Pass false to disable null placeholders in [PagedList]s using this [PagingConfig].
+ *
+ * If not set, defaults to true.
+ *
+ * A [PagedList] will present null placeholders for not-yet-loaded content if two
+ * conditions are met:
+ *
+ * 1) Its [PagedSource] can count all unloaded items (so that the number of nulls to
+ * present is known).
+ *
+ * 2) placeholders are not disabled on the [PagingConfig].
+ *
+ * Call `setEnablePlaceholders(false)` to ensure the receiver of the PagedList
+ * (often a [androidx.paging.PagedDataAdapter]) doesn't need to account for null items.
+ *
+ * If placeholders are disabled, not-yet-loaded content will not be present in the list.
+ * Paging will still occur, but as items are loaded or removed, they will be signaled
+ * as inserts to the [PagedList.Callback].
+ *
+ * [PagedList.Callback.onChanged] will not be issued as part of loading, though a
+ * [androidx.paging.PagedDataAdapter] may still receive change events as a result of
+ * [PagedList] diffing.
+ *
+ * @param enablePlaceholders `false` if null placeholders should be disabled.
+ * @return this
+ */
+ fun setEnablePlaceholders(enablePlaceholders: Boolean) = apply {
+ this.enablePlaceholders = enablePlaceholders
+ }
+
+ /**
+ * Defines how many items to load when first load occurs.
+ *
+ * This value is typically larger than page size, so on first load data there's a large
+ * enough range of content loaded to cover small scrolls.
+ *
+ * If not set, defaults to three times page size.
+ *
+ * @param initialLoadSizeHint Number of items to load while initializing the [PagedList]
+ * @return this
+ */
+ fun setInitialLoadSizeHint(@IntRange(from = 1) initialLoadSizeHint: Int) = apply {
+ this.initialLoadSizeHint = initialLoadSizeHint
+ }
+
+ /**
+ * Defines how many items to keep loaded at once.
+ *
+ * This can be used to cap the number of items kept in memory by dropping pages. This
+ * value is typically many pages so old pages are cached in case the user scrolls back.
+ *
+ * This value must be at least two times the [prefetchDistance] plus the [pageSize]).
+ * This constraint prevent loads from being continuously fetched and discarded due to
+ * prefetching.
+ *
+ * The max size specified here best effort, not a guarantee. In practice, if [maxSize]
+ * is many times the page size, the number of items held by the [PagedList] will not
+ * grow above this number. Exceptions are made as necessary to guarantee:
+ * * Pages are never dropped until there are more than two pages loaded. Note that
+ * a [PagedSource] may not be held strictly to [requested pageSize][PagingConfig.pageSize], so
+ * two pages may be larger than expected.
+ * * Pages are never dropped if they are within a prefetch window (defined to be
+ * `pageSize + (2 * prefetchDistance)`) of the most recent load.
+ *
+ * If not set, defaults to [MAX_SIZE_UNBOUNDED], which disables page dropping.
+ *
+ * @param maxSize Maximum number of items to keep in memory, or [MAX_SIZE_UNBOUNDED] to
+ * disable page dropping.
+ * @return this
+ *
+ * @see PagingConfig.MAX_SIZE_UNBOUNDED
+ * @see PagingConfig.maxSize
+ */
+ fun setMaxSize(@IntRange(from = 2) maxSize: Int) = apply {
+ this.maxSize = maxSize
+ }
+
+ /**
+ * Creates a [PagingConfig] with the given parameters.
+ *
+ * @return A new [PagingConfig].
+ */
+ fun build(): PagingConfig {
+ if (prefetchDistance < 0) {
+ prefetchDistance = pageSize
+ }
+ if (initialLoadSizeHint < 0) {
+ initialLoadSizeHint = pageSize * DEFAULT_INITIAL_PAGE_MULTIPLIER
+ }
+
+ return PagingConfig(
+ pageSize,
+ prefetchDistance,
+ enablePlaceholders,
+ initialLoadSizeHint,
+ maxSize
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/paging/common/src/test/kotlin/androidx/paging/CachingTest.kt b/paging/common/src/test/kotlin/androidx/paging/CachingTest.kt
index 7c4f3a5..46f3798 100644
--- a/paging/common/src/test/kotlin/androidx/paging/CachingTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/CachingTest.kt
@@ -292,11 +292,11 @@
private fun buildPageFlow(): Flow<PagedData<Item>> {
return PagedDataFlowBuilder(
pagedSourceFactory = StringPagedSource.VersionedFactory()::create,
- config = PagedList.Config(
+ config = PagingConfig(
pageSize = 3,
prefetchDistance = 1,
enablePlaceholders = false,
- initialLoadSizeHint = 3,
+ initialLoadSize = 3,
maxSize = 1000
)
).build()
diff --git a/paging/common/src/test/kotlin/androidx/paging/PageFetcherTest.kt b/paging/common/src/test/kotlin/androidx/paging/PageFetcherTest.kt
index fa23d76..43339e9 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PageFetcherTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PageFetcherTest.kt
@@ -41,11 +41,11 @@
class PageFetcherTest {
private val testScope = TestCoroutineScope()
private val pagedSourceFactory = { TestPagedSource() }
- private val config = PagedList.Config(
+ private val config = PagingConfig(
pageSize = 1,
prefetchDistance = 1,
enablePlaceholders = true,
- initialLoadSizeHint = 2,
+ initialLoadSize = 2,
maxSize = 3
)
@@ -168,29 +168,3 @@
return FetcherState(pagedDataList, pageEventLists, job)
}
-
-internal fun assertEvents(expected: List<PageEvent<Int>>, actual: List<PageEvent<Int>>) {
- try {
- assertEquals(expected, actual)
- } catch (e: Throwable) {
- val msg = e.localizedMessage
- .replace("),", "),\n")
- .replace("<[", "<[\n ")
- .replace("actual", "\nactual")
- .lines()
- .toMutableList()
-
- if (expected.count() != actual.count()) throw AssertionError(msg.joinToString("\n"))
-
- var index = 0
- for (i in 0 until expected.count()) {
- if (expected[i] != actual[i]) {
- index = i
- break
- }
- }
- msg[index + 1] = msg[index + 1].prependIndent(" >")
- msg[msg.count() / 2 + index + 1] = msg[msg.count() / 2 + index + 1].prependIndent(" >")
- throw AssertionError(msg.joinToString("\n"))
- }
-}
diff --git a/paging/common/src/test/kotlin/androidx/paging/PagePresenterTest.kt b/paging/common/src/test/kotlin/androidx/paging/PagePresenterTest.kt
index 8e22b85..6a1547f 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PagePresenterTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PagePresenterTest.kt
@@ -118,7 +118,7 @@
assertEquals(expectedData, data.asList())
// ... then assert events
- assertEquals(events, callback.getAllAndClear())
+ assertEquals(events + IDLE_EVENTS, callback.getAllAndClear())
}
private fun verifyPrepend(
@@ -155,7 +155,7 @@
assertEquals(expectedData, data.asList())
// ... then assert events
- assertEquals(events, callback.getAllAndClear())
+ assertEquals(events + IDLE_EVENTS, callback.getAllAndClear())
}
private fun verifyPrependAppend(
@@ -310,7 +310,7 @@
val callback = PresenterCallbackCapture()
data.dropPages(false, pagesToDrop, newNulls, callback)
- assertEquals(events, callback.getAllAndClear())
+ assertEquals(events + listOf(StateEvent(END, Idle)), callback.getAllAndClear())
// assert final list state
val finalData = initialPages.subList(0, initialPages.size - pagesToDrop).flatten()
@@ -343,7 +343,7 @@
val callback = PresenterCallbackCapture()
data.dropPages(true, pagesToDrop, newNulls, callback)
- assertEquals(events, callback.getAllAndClear())
+ assertEquals(events + listOf(StateEvent(START, Idle)), callback.getAllAndClear())
// assert final list state
val finalData = initialPages.take(initialPages.size - pagesToDrop).reversed().flatten()
@@ -544,4 +544,12 @@
assertEquals(ViewportHint(1, 1), pagePresenter.loadAround(5))
assertEquals(ViewportHint(1, 2), pagePresenter.loadAround(6))
}
+
+ companion object {
+ val IDLE_EVENTS = listOf<PresenterEvent>(
+ StateEvent(REFRESH, Idle),
+ StateEvent(START, Idle),
+ StateEvent(END, Idle)
+ )
+ }
}
\ No newline at end of file
diff --git a/paging/common/src/test/kotlin/androidx/paging/PagerTest.kt b/paging/common/src/test/kotlin/androidx/paging/PagerTest.kt
index 65a1a98..5179687 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PagerTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PagerTest.kt
@@ -48,11 +48,11 @@
class PagerTest {
private val testScope = TestCoroutineScope()
private val pagedSourceFactory = { TestPagedSource() }
- private val config = PagedList.Config(
+ private val config = PagingConfig(
pageSize = 1,
prefetchDistance = 1,
enablePlaceholders = true,
- initialLoadSizeHint = 2,
+ initialLoadSize = 2,
maxSize = 3
)
@@ -301,11 +301,11 @@
@Test
fun prependMultiplePages() = testScope.runBlockingTest {
- val config = PagedList.Config(
+ val config = PagingConfig(
pageSize = 1,
prefetchDistance = 2,
enablePlaceholders = true,
- initialLoadSizeHint = 3,
+ initialLoadSize = 3,
maxSize = 5
)
val pageFetcher = PageFetcher(pagedSourceFactory, 50, config)
@@ -353,11 +353,11 @@
@Test
fun appendMultiplePages() = testScope.runBlockingTest {
- val config = PagedList.Config(
+ val config = PagingConfig(
pageSize = 1,
prefetchDistance = 2,
enablePlaceholders = true,
- initialLoadSizeHint = 3,
+ initialLoadSize = 3,
maxSize = 5
)
val pageFetcher = PageFetcher(pagedSourceFactory, 50, config)
@@ -444,46 +444,6 @@
}
@Test
- fun competingPrependAndAppendWithDropping() = testScope.runBlockingTest {
- pauseDispatcher {
- val config = PagedList.Config(
- pageSize = 1,
- prefetchDistance = 2,
- enablePlaceholders = true,
- initialLoadSizeHint = 1,
- maxSize = 3
- )
- val pageFetcher = PageFetcher(pagedSourceFactory, 50, config)
- val fetcherState = collectFetcherState(pageFetcher)
-
- advanceUntilIdle()
- fetcherState.pagedDataList[0].receiver.addHint(ViewportHint(0, 0))
- advanceUntilIdle()
-
- val expected: List<PageEvent<Int>> = listOf(
- StateUpdate(REFRESH, Loading),
- StateUpdate(REFRESH, Done),
- createRefresh(range = 50..50),
- StateUpdate(START, Loading),
- StateUpdate(END, Loading),
- createPrepend(
- pageOffset = -1, range = 49..49, startState = Loading, endState = Loading
- ),
- createAppend(
- pageOffset = 1, range = 51..51, startState = Loading, endState = Loading
- ),
- StateUpdate(END, Idle),
- Drop(END, 1, 49),
- StateUpdate(START, Idle),
- createPrepend(pageOffset = -2, range = 48..48, startState = Idle, endState = Idle)
- )
-
- assertEvents(expected, fetcherState.pageEventLists[0])
- fetcherState.job.cancel()
- }
- }
-
- @Test
fun invalidateNoScroll() = testScope.runBlockingTest {
val pageFetcher = PageFetcher(pagedSourceFactory, 50, config)
val fetcherState = collectFetcherState(pageFetcher)
diff --git a/paging/common/src/test/kotlin/androidx/paging/PagingConfigTest.kt b/paging/common/src/test/kotlin/androidx/paging/PagingConfigTest.kt
new file mode 100644
index 0000000..bcae8c8
--- /dev/null
+++ b/paging/common/src/test/kotlin/androidx/paging/PagingConfigTest.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2020 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.paging
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import kotlin.test.assertFailsWith
+
+@RunWith(JUnit4::class)
+class PagingConfigTest {
+ @Test
+ fun defaults() {
+ val config = PagingConfig(10)
+ assertEquals(10, config.pageSize)
+ assertEquals(30, config.initialLoadSize)
+ assertEquals(true, config.enablePlaceholders)
+ assertEquals(10, config.prefetchDistance)
+ assertEquals(PagedList.Config.MAX_SIZE_UNBOUNDED, config.maxSize)
+ }
+
+ @Test
+ fun requirePlaceholdersOrPrefetch() {
+ assertFailsWith<IllegalArgumentException> {
+ PagingConfig(
+ pageSize = 10,
+ enablePlaceholders = false,
+ prefetchDistance = 0
+ )
+ }
+ }
+
+ @Test
+ fun prefetchWindowMustFitInMaxSize() {
+ assertFailsWith<IllegalArgumentException> {
+ PagingConfig(
+ pageSize = 3,
+ prefetchDistance = 4,
+ maxSize = 10
+ )
+ }
+ }
+}
diff --git a/paging/common/src/test/kotlin/androidx/paging/PresenterCallbackCapture.kt b/paging/common/src/test/kotlin/androidx/paging/PresenterCallbackCapture.kt
index cb0ff04..ff7bf16 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PresenterCallbackCapture.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PresenterCallbackCapture.kt
@@ -32,7 +32,7 @@
}
}
- override fun onInserted(position: Int, count: Int, loadStates: Map<LoadType, LoadState>?) {
+ override fun onInserted(position: Int, count: Int) {
if (count != 0) {
list.add(InsertEvent(position, count))
}
diff --git a/paging/integration-tests/testapp/build.gradle b/paging/integration-tests/testapp/build.gradle
index f99f782..ae3c6f0 100644
--- a/paging/integration-tests/testapp/build.gradle
+++ b/paging/integration-tests/testapp/build.gradle
@@ -17,13 +17,6 @@
import static androidx.build.dependencies.DependenciesKt.MULTIDEX
import static androidx.build.dependencies.DependenciesKt.getKOTLIN_STDLIB
-buildscript {
- // TODO: Remove this when this test app no longer depends on 1.0.0 of vectordrawable-animated.
- // vectordrawable and vectordrawable-animated were accidentally using the same package name
- // which is no longer valid in namespaced resource world.
- project.ext['android.uniquePackageNames'] = false
-}
-
plugins {
id("AndroidXPlugin")
id("com.android.application")
@@ -32,18 +25,18 @@
}
dependencies {
- implementation("androidx.arch.core:core-runtime:2.0.1")
- implementation("androidx.room:room-runtime:2.0.0")
- implementation("androidx.room:room-rxjava2:2.0.0")
+ implementation("androidx.arch.core:core-runtime:2.1.0")
+ implementation("androidx.room:room-runtime:2.2.3")
+ implementation("androidx.room:room-rxjava2:2.2.3")
implementation(project(":paging:paging-common-ktx"))
implementation(project(":paging:paging-runtime"))
implementation(project(":paging:paging-rxjava2"))
- kapt("androidx.room:room-compiler:2.0.0")
+ kapt("androidx.room:room-compiler:2.2.3")
implementation(MULTIDEX)
- implementation("androidx.recyclerview:recyclerview:1.0.0")
+ implementation("androidx.recyclerview:recyclerview:1.1.0")
implementation(project(":fragment:fragment-ktx"))
implementation("androidx.appcompat:appcompat:1.1.0")
implementation(KOTLIN_STDLIB)
diff --git a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3/V3ViewModel.kt b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3/V3ViewModel.kt
index 75b7a97..6ddad40 100644
--- a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3/V3ViewModel.kt
+++ b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3/V3ViewModel.kt
@@ -19,8 +19,8 @@
import android.graphics.Color
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
-import androidx.paging.Config
import androidx.paging.PagedDataFlowBuilder
+import androidx.paging.PagingConfig
import androidx.paging.cachedIn
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
@@ -30,7 +30,7 @@
class V3ViewModel : ViewModel() {
@FlowPreview
val flow =
- PagedDataFlowBuilder(ItemPagedSource.Factory, Config(pageSize = 10))
+ PagedDataFlowBuilder(ItemPagedSource.Factory, PagingConfig(pageSize = 10))
.build()
.map {
it.insertSeparators { before: Item?, after: Item? ->
diff --git a/paging/runtime/api/3.0.0-alpha01.txt b/paging/runtime/api/3.0.0-alpha01.txt
index 37e07ce..2e8c621 100644
--- a/paging/runtime/api/3.0.0-alpha01.txt
+++ b/paging/runtime/api/3.0.0-alpha01.txt
@@ -61,26 +61,24 @@
public abstract class PagedDataAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
ctor public PagedDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, kotlinx.coroutines.CoroutineDispatcher mainDispatcher);
- method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public final void connect(kotlinx.coroutines.flow.Flow<androidx.paging.PagedData<T>> flow, kotlinx.coroutines.CoroutineScope scope);
method protected T? getItem(int position);
method public int getItemCount();
- method public void onLoadStateChanged(androidx.paging.LoadType type, androidx.paging.LoadState state);
- method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public final void retry();
}
public abstract class PagedListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
ctor protected PagedListAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback);
ctor protected PagedListAdapter(androidx.recyclerview.widget.AsyncDifferConfig<T> config);
- method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public androidx.paging.PagedList<T>? getCurrentList();
method protected T? getItem(int position);
method public int getItemCount();
method @Deprecated public void onCurrentListChanged(androidx.paging.PagedList<T>? currentList);
method public void onCurrentListChanged(androidx.paging.PagedList<T>? previousList, androidx.paging.PagedList<T>? currentList);
- method public void onLoadStateChanged(androidx.paging.LoadType type, androidx.paging.LoadState state);
- method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public void submitList(androidx.paging.PagedList<T>? pagedList);
method public void submitList(androidx.paging.PagedList<T>? pagedList, Runnable? commitCallback);
property public androidx.paging.PagedList<T>? currentList;
diff --git a/paging/runtime/api/current.txt b/paging/runtime/api/current.txt
index 37e07ce..2e8c621 100644
--- a/paging/runtime/api/current.txt
+++ b/paging/runtime/api/current.txt
@@ -61,26 +61,24 @@
public abstract class PagedDataAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
ctor public PagedDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, kotlinx.coroutines.CoroutineDispatcher mainDispatcher);
- method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public final void connect(kotlinx.coroutines.flow.Flow<androidx.paging.PagedData<T>> flow, kotlinx.coroutines.CoroutineScope scope);
method protected T? getItem(int position);
method public int getItemCount();
- method public void onLoadStateChanged(androidx.paging.LoadType type, androidx.paging.LoadState state);
- method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public final void retry();
}
public abstract class PagedListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
ctor protected PagedListAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback);
ctor protected PagedListAdapter(androidx.recyclerview.widget.AsyncDifferConfig<T> config);
- method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public androidx.paging.PagedList<T>? getCurrentList();
method protected T? getItem(int position);
method public int getItemCount();
method @Deprecated public void onCurrentListChanged(androidx.paging.PagedList<T>? currentList);
method public void onCurrentListChanged(androidx.paging.PagedList<T>? previousList, androidx.paging.PagedList<T>? currentList);
- method public void onLoadStateChanged(androidx.paging.LoadType type, androidx.paging.LoadState state);
- method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public void submitList(androidx.paging.PagedList<T>? pagedList);
method public void submitList(androidx.paging.PagedList<T>? pagedList, Runnable? commitCallback);
property public androidx.paging.PagedList<T>? currentList;
diff --git a/paging/runtime/api/public_plus_experimental_3.0.0-alpha01.txt b/paging/runtime/api/public_plus_experimental_3.0.0-alpha01.txt
index 37e07ce..2e8c621 100644
--- a/paging/runtime/api/public_plus_experimental_3.0.0-alpha01.txt
+++ b/paging/runtime/api/public_plus_experimental_3.0.0-alpha01.txt
@@ -61,26 +61,24 @@
public abstract class PagedDataAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
ctor public PagedDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, kotlinx.coroutines.CoroutineDispatcher mainDispatcher);
- method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public final void connect(kotlinx.coroutines.flow.Flow<androidx.paging.PagedData<T>> flow, kotlinx.coroutines.CoroutineScope scope);
method protected T? getItem(int position);
method public int getItemCount();
- method public void onLoadStateChanged(androidx.paging.LoadType type, androidx.paging.LoadState state);
- method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public final void retry();
}
public abstract class PagedListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
ctor protected PagedListAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback);
ctor protected PagedListAdapter(androidx.recyclerview.widget.AsyncDifferConfig<T> config);
- method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public androidx.paging.PagedList<T>? getCurrentList();
method protected T? getItem(int position);
method public int getItemCount();
method @Deprecated public void onCurrentListChanged(androidx.paging.PagedList<T>? currentList);
method public void onCurrentListChanged(androidx.paging.PagedList<T>? previousList, androidx.paging.PagedList<T>? currentList);
- method public void onLoadStateChanged(androidx.paging.LoadType type, androidx.paging.LoadState state);
- method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public void submitList(androidx.paging.PagedList<T>? pagedList);
method public void submitList(androidx.paging.PagedList<T>? pagedList, Runnable? commitCallback);
property public androidx.paging.PagedList<T>? currentList;
diff --git a/paging/runtime/api/public_plus_experimental_current.txt b/paging/runtime/api/public_plus_experimental_current.txt
index 37e07ce..2e8c621 100644
--- a/paging/runtime/api/public_plus_experimental_current.txt
+++ b/paging/runtime/api/public_plus_experimental_current.txt
@@ -61,26 +61,24 @@
public abstract class PagedDataAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
ctor public PagedDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, kotlinx.coroutines.CoroutineDispatcher mainDispatcher);
- method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public final void connect(kotlinx.coroutines.flow.Flow<androidx.paging.PagedData<T>> flow, kotlinx.coroutines.CoroutineScope scope);
method protected T? getItem(int position);
method public int getItemCount();
- method public void onLoadStateChanged(androidx.paging.LoadType type, androidx.paging.LoadState state);
- method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public final void retry();
}
public abstract class PagedListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
ctor protected PagedListAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback);
ctor protected PagedListAdapter(androidx.recyclerview.widget.AsyncDifferConfig<T> config);
- method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public androidx.paging.PagedList<T>? getCurrentList();
method protected T? getItem(int position);
method public int getItemCount();
method @Deprecated public void onCurrentListChanged(androidx.paging.PagedList<T>? currentList);
method public void onCurrentListChanged(androidx.paging.PagedList<T>? previousList, androidx.paging.PagedList<T>? currentList);
- method public void onLoadStateChanged(androidx.paging.LoadType type, androidx.paging.LoadState state);
- method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public void submitList(androidx.paging.PagedList<T>? pagedList);
method public void submitList(androidx.paging.PagedList<T>? pagedList, Runnable? commitCallback);
property public androidx.paging.PagedList<T>? currentList;
diff --git a/paging/runtime/api/restricted_3.0.0-alpha01.txt b/paging/runtime/api/restricted_3.0.0-alpha01.txt
index 37e07ce..2e8c621 100644
--- a/paging/runtime/api/restricted_3.0.0-alpha01.txt
+++ b/paging/runtime/api/restricted_3.0.0-alpha01.txt
@@ -61,26 +61,24 @@
public abstract class PagedDataAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
ctor public PagedDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, kotlinx.coroutines.CoroutineDispatcher mainDispatcher);
- method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public final void connect(kotlinx.coroutines.flow.Flow<androidx.paging.PagedData<T>> flow, kotlinx.coroutines.CoroutineScope scope);
method protected T? getItem(int position);
method public int getItemCount();
- method public void onLoadStateChanged(androidx.paging.LoadType type, androidx.paging.LoadState state);
- method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public final void retry();
}
public abstract class PagedListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
ctor protected PagedListAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback);
ctor protected PagedListAdapter(androidx.recyclerview.widget.AsyncDifferConfig<T> config);
- method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public androidx.paging.PagedList<T>? getCurrentList();
method protected T? getItem(int position);
method public int getItemCount();
method @Deprecated public void onCurrentListChanged(androidx.paging.PagedList<T>? currentList);
method public void onCurrentListChanged(androidx.paging.PagedList<T>? previousList, androidx.paging.PagedList<T>? currentList);
- method public void onLoadStateChanged(androidx.paging.LoadType type, androidx.paging.LoadState state);
- method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public void submitList(androidx.paging.PagedList<T>? pagedList);
method public void submitList(androidx.paging.PagedList<T>? pagedList, Runnable? commitCallback);
property public androidx.paging.PagedList<T>? currentList;
diff --git a/paging/runtime/api/restricted_current.txt b/paging/runtime/api/restricted_current.txt
index 37e07ce..2e8c621 100644
--- a/paging/runtime/api/restricted_current.txt
+++ b/paging/runtime/api/restricted_current.txt
@@ -61,26 +61,24 @@
public abstract class PagedDataAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
ctor public PagedDataAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback, kotlinx.coroutines.CoroutineDispatcher mainDispatcher);
- method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public final void connect(kotlinx.coroutines.flow.Flow<androidx.paging.PagedData<T>> flow, kotlinx.coroutines.CoroutineScope scope);
method protected T? getItem(int position);
method public int getItemCount();
- method public void onLoadStateChanged(androidx.paging.LoadType type, androidx.paging.LoadState state);
- method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public final void retry();
}
public abstract class PagedListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
ctor protected PagedListAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T> diffCallback);
ctor protected PagedListAdapter(androidx.recyclerview.widget.AsyncDifferConfig<T> config);
- method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void addLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public androidx.paging.PagedList<T>? getCurrentList();
method protected T? getItem(int position);
method public int getItemCount();
method @Deprecated public void onCurrentListChanged(androidx.paging.PagedList<T>? currentList);
method public void onCurrentListChanged(androidx.paging.PagedList<T>? previousList, androidx.paging.PagedList<T>? currentList);
- method public void onLoadStateChanged(androidx.paging.LoadType type, androidx.paging.LoadState state);
- method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> callback);
+ method public void removeLoadStateListener(kotlin.jvm.functions.Function2<? super androidx.paging.LoadType,? super androidx.paging.LoadState,kotlin.Unit> listener);
method public void submitList(androidx.paging.PagedList<T>? pagedList);
method public void submitList(androidx.paging.PagedList<T>? pagedList, Runnable? commitCallback);
property public androidx.paging.PagedList<T>? currentList;
diff --git a/paging/runtime/src/main/java/androidx/paging/AsyncPagedDataDiffer.kt b/paging/runtime/src/main/java/androidx/paging/AsyncPagedDataDiffer.kt
index ef8d7be..40e68ee 100644
--- a/paging/runtime/src/main/java/androidx/paging/AsyncPagedDataDiffer.kt
+++ b/paging/runtime/src/main/java/androidx/paging/AsyncPagedDataDiffer.kt
@@ -35,9 +35,8 @@
private val updateCallback: ListUpdateCallback
) {
internal val callback = object : PresenterCallback {
- override fun onInserted(position: Int, count: Int, loadStates: Map<LoadType, LoadState>?) {
+ override fun onInserted(position: Int, count: Int) {
updateCallback.onInserted(position, count)
- loadStates?.entries?.forEach { onStateUpdate(it.key, it.value) }
}
override fun onRemoved(position: Int, count: Int) =
@@ -77,18 +76,23 @@
}
private val differBase = object : PagedDataDiffer<T>(mainDispatcher, workerDispatcher) {
- override suspend fun performDiff(previous: NullPaddedList<T>, new: NullPaddedList<T>) {
+ override suspend fun performDiff(
+ previousList: NullPaddedList<T>,
+ newList: NullPaddedList<T>,
+ newLoadStates: Map<LoadType, LoadState>
+ ) {
withContext(mainDispatcher) {
when {
- previous.size == 0 -> // fast path for no items -> some items
- callback.onInserted(0, new.size, null)
- new.size == 0 -> // fast path for some items -> no items
- callback.onRemoved(0, previous.size)
+ previousList.size == 0 -> // fast path for no items -> some items
+ callback.onInserted(0, newList.size)
+ newList.size == 0 -> // fast path for some items -> no items
+ callback.onRemoved(0, previousList.size)
else -> { // full diff
val diffResult = withContext(workerDispatcher) {
- previous.computeDiff(new, diffCallback)
+ previousList.computeDiff(newList, diffCallback)
}
- previous.dispatchDiff(updateCallback, new, diffResult)
+ previousList.dispatchDiff(updateCallback, newList, diffResult)
+ newLoadStates.entries.forEach { callback.onStateUpdate(it.key, it.value) }
}
}
}
@@ -134,8 +138,8 @@
/**
* Add a listener to observe the loading state.
*
- * As new PagedLists are submitted and displayed, the listener will be notified to reflect
- * current REFRESH, START, and END states.
+ * As new PagedData generations are submitted and displayed, the listener will be notified to
+ * reflect current [LoadType.REFRESH], [LoadType.START], and [LoadType.END] states.
*
* @param listener [LoadStateListener] to receive updates.
*
@@ -155,7 +159,6 @@
* Remove a previously registered load state listener.
*
* @param listener Previously registered listener.
- *
* @see addLoadStateListener
*/
open fun removeLoadStateListener(listener: (LoadType, LoadState) -> Unit) {
diff --git a/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.kt b/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.kt
index 055874f..afac8b5 100644
--- a/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.kt
+++ b/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.kt
@@ -472,16 +472,16 @@
}
/**
- * Add a [LoadStateListener] to observe the loading state of the current [PagedList].
+ * Add a [LoadState] listener to observe the loading state of the current [PagedList].
*
* As new PagedLists are submitted and displayed, the listener will be notified to reflect
- * current REFRESH, START, and END states.
+ * current [LoadType.REFRESH], [LoadType.START], and [LoadType.END] states.
*
- * @param listener [LoadStateListener] to receive updates.
+ * @param listener [LoadState] listener to receive updates.
*
* @see removeLoadStateListener
*/
- open fun addLoadStateListener(listener: LoadStateListener) {
+ open fun addLoadStateListener(listener: (type: LoadType, state: LoadState) -> Unit) {
val pagedList = this.pagedList
if (pagedList != null) {
pagedList.addWeakLoadStateListener(listener)
@@ -492,14 +492,14 @@
}
/**
- * Remove a previously registered [LoadStateListener].
+ * Remove a previously registered [LoadState] listener.
*
* @param listener Previously registered listener.
*
* @see currentList
* @see addPagedListListener
*/
- open fun removeLoadStateListener(listener: LoadStateListener) {
+ open fun removeLoadStateListener(listener: (type: LoadType, state: LoadState) -> Unit) {
loadStateListeners.remove(listener)
pagedList?.removeWeakLoadStateListener(listener)
}
diff --git a/paging/runtime/src/main/java/androidx/paging/PagedDataAdapter.kt b/paging/runtime/src/main/java/androidx/paging/PagedDataAdapter.kt
index 285319e..0c5a1a9 100644
--- a/paging/runtime/src/main/java/androidx/paging/PagedDataAdapter.kt
+++ b/paging/runtime/src/main/java/androidx/paging/PagedDataAdapter.kt
@@ -32,11 +32,7 @@
mainDispatcher = mainDispatcher,
diffCallback = diffCallback,
updateCallback = AdapterListUpdateCallback(this)
- ).also {
- it.addLoadStateListener { loadType, loadState ->
- onLoadStateChanged(loadType, loadState)
- }
- }
+ )
fun connect(flow: Flow<PagedData<T>>, scope: CoroutineScope) {
differ.connect(flow, scope)
@@ -51,39 +47,26 @@
override fun getItemCount() = differ.itemCount
/**
- * Called when the [LoadState] for a particular type of load (START, END, REFRESH) has
- * changed.
+ * Add a [LoadState] listener to observe the loading state of the current [PagedData].
*
- * REFRESH events can be used to drive a `SwipeRefreshLayout`, or START/END events
- * can be used to drive loading spinner items in the Adapter.
+ * As new PagedData generations are submitted and displayed, the listener will be notified to
+ * reflect current [LoadType.REFRESH], [LoadType.START], and [LoadType.END] states.
*
- * @param type [LoadType] Can be START, END, or REFRESH
- * @param state [LoadState] Idle, Loading, Done, or Error.
- */
- open fun onLoadStateChanged(type: LoadType, state: LoadState) {
- }
-
- /**
- * Add a [LoadStateListener] to observe the loading state of the current [PagedList].
- *
- * As new PagedLists are submitted and displayed, the callback will be notified to reflect
- * current REFRESH, START, and END states.
- *
- * @param callback [LoadStateListener] to receive updates.
+ * @param listener [LoadState] listener to receive updates.
*
* @see removeLoadStateListener
*/
- open fun addLoadStateListener(callback: (LoadType, LoadState) -> Unit) {
- differ.addLoadStateListener(callback)
+ open fun addLoadStateListener(listener: (LoadType, LoadState) -> Unit) {
+ differ.addLoadStateListener(listener)
}
/**
- * Remove a previously registered [LoadStateListener].
+ * Remove a previously registered [LoadState] listener.
*
- * @param callback Previously registered callback.
+ * @param listener Previously registered listener.
* @see addLoadStateListener
*/
- open fun removeLoadStateListener(callback: (LoadType, LoadState) -> Unit) {
- differ.removeLoadStateListener(callback)
+ open fun removeLoadStateListener(listener: (LoadType, LoadState) -> Unit) {
+ differ.removeLoadStateListener(listener)
}
}
diff --git a/paging/runtime/src/main/java/androidx/paging/PagedListAdapter.kt b/paging/runtime/src/main/java/androidx/paging/PagedListAdapter.kt
index b1aaa50..a8b1eabe 100644
--- a/paging/runtime/src/main/java/androidx/paging/PagedListAdapter.kt
+++ b/paging/runtime/src/main/java/androidx/paging/PagedListAdapter.kt
@@ -111,8 +111,6 @@
this@PagedListAdapter.onCurrentListChanged(currentList)
this@PagedListAdapter.onCurrentListChanged(previousList, currentList)
}
- private val loadStateListener
- get() = this::onLoadStateChanged
/**
* Returns the [PagedList] currently being displayed by the [PagedListAdapter].
@@ -140,13 +138,11 @@
protected constructor(diffCallback: DiffUtil.ItemCallback<T>) {
differ = AsyncPagedListDiffer(this, diffCallback)
differ.addPagedListListener(listener)
- differ.addLoadStateListener(loadStateListener)
}
protected constructor(config: AsyncDifferConfig<T>) {
differ = AsyncPagedListDiffer(AdapterListUpdateCallback(this), config)
differ.addPagedListListener(listener)
- differ.addLoadStateListener(loadStateListener)
}
/**
@@ -224,39 +220,26 @@
}
/**
- * Called when the [LoadState] for a particular type of load (START, END, REFRESH) has
- * changed.
+ * Add a [LoadState] listener to observe the loading state of the current [PagedList].
*
- * REFRESH events can be used to drive a `SwipeRefreshLayout`, or START/END events
- * can be used to drive loading spinner items in the Adapter.
+ * As new PagedLists are submitted and displayed, the listener will be notified to reflect
+ * current [LoadType.REFRESH], [LoadType.START], and [LoadType.END] states.
*
- * @param type [LoadType] Can be START, END, or REFRESH
- * @param state [LoadState] Idle, Loading, Done, or Error.
- */
- open fun onLoadStateChanged(type: LoadType, state: LoadState) {
- }
-
- /**
- * Add a [LoadStateListener] to observe the loading state of the current [PagedList].
- *
- * As new PagedLists are submitted and displayed, the callback will be notified to reflect
- * current REFRESH, START, and END states.
- *
- * @param callback [LoadStateListener] to receive updates.
+ * @param listener [LoadStateListener] to receive updates.
*
* @see removeLoadStateListener
*/
- open fun addLoadStateListener(callback: LoadStateListener) {
- differ.addLoadStateListener(callback)
+ open fun addLoadStateListener(listener: (type: LoadType, state: LoadState) -> Unit) {
+ differ.addLoadStateListener(listener)
}
/**
- * Remove a previously registered [LoadStateListener].
+ * Remove a previously registered [LoadState] listener.
*
- * @param callback Previously registered callback.
+ * @param listener Previously registered listener.
* @see addLoadStateListener
*/
- open fun removeLoadStateListener(callback: LoadStateListener) {
- differ.removeLoadStateListener(callback)
+ open fun removeLoadStateListener(listener: (type: LoadType, state: LoadState) -> Unit) {
+ differ.removeLoadStateListener(listener)
}
}
diff --git a/paging/rxjava2/api/3.0.0-alpha01.txt b/paging/rxjava2/api/3.0.0-alpha01.txt
index c963f93..0059dfe 100644
--- a/paging/rxjava2/api/3.0.0-alpha01.txt
+++ b/paging/rxjava2/api/3.0.0-alpha01.txt
@@ -2,7 +2,7 @@
package androidx.paging {
public final class RxPagedDataFlowBuilder<Key, Value> {
- ctor public RxPagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagedList.Config config);
+ ctor public RxPagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagingConfig config);
method public io.reactivex.Observable<androidx.paging.PagedData<Value>> build();
method public androidx.paging.RxPagedDataFlowBuilder<Key,Value> setInitialKey(Key? initialKey);
}
diff --git a/paging/rxjava2/api/current.txt b/paging/rxjava2/api/current.txt
index c963f93..0059dfe 100644
--- a/paging/rxjava2/api/current.txt
+++ b/paging/rxjava2/api/current.txt
@@ -2,7 +2,7 @@
package androidx.paging {
public final class RxPagedDataFlowBuilder<Key, Value> {
- ctor public RxPagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagedList.Config config);
+ ctor public RxPagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagingConfig config);
method public io.reactivex.Observable<androidx.paging.PagedData<Value>> build();
method public androidx.paging.RxPagedDataFlowBuilder<Key,Value> setInitialKey(Key? initialKey);
}
diff --git a/paging/rxjava2/api/public_plus_experimental_3.0.0-alpha01.txt b/paging/rxjava2/api/public_plus_experimental_3.0.0-alpha01.txt
index c963f93..0059dfe 100644
--- a/paging/rxjava2/api/public_plus_experimental_3.0.0-alpha01.txt
+++ b/paging/rxjava2/api/public_plus_experimental_3.0.0-alpha01.txt
@@ -2,7 +2,7 @@
package androidx.paging {
public final class RxPagedDataFlowBuilder<Key, Value> {
- ctor public RxPagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagedList.Config config);
+ ctor public RxPagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagingConfig config);
method public io.reactivex.Observable<androidx.paging.PagedData<Value>> build();
method public androidx.paging.RxPagedDataFlowBuilder<Key,Value> setInitialKey(Key? initialKey);
}
diff --git a/paging/rxjava2/api/public_plus_experimental_current.txt b/paging/rxjava2/api/public_plus_experimental_current.txt
index c963f93..0059dfe 100644
--- a/paging/rxjava2/api/public_plus_experimental_current.txt
+++ b/paging/rxjava2/api/public_plus_experimental_current.txt
@@ -2,7 +2,7 @@
package androidx.paging {
public final class RxPagedDataFlowBuilder<Key, Value> {
- ctor public RxPagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagedList.Config config);
+ ctor public RxPagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagingConfig config);
method public io.reactivex.Observable<androidx.paging.PagedData<Value>> build();
method public androidx.paging.RxPagedDataFlowBuilder<Key,Value> setInitialKey(Key? initialKey);
}
diff --git a/paging/rxjava2/api/restricted_3.0.0-alpha01.txt b/paging/rxjava2/api/restricted_3.0.0-alpha01.txt
index c963f93..0059dfe 100644
--- a/paging/rxjava2/api/restricted_3.0.0-alpha01.txt
+++ b/paging/rxjava2/api/restricted_3.0.0-alpha01.txt
@@ -2,7 +2,7 @@
package androidx.paging {
public final class RxPagedDataFlowBuilder<Key, Value> {
- ctor public RxPagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagedList.Config config);
+ ctor public RxPagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagingConfig config);
method public io.reactivex.Observable<androidx.paging.PagedData<Value>> build();
method public androidx.paging.RxPagedDataFlowBuilder<Key,Value> setInitialKey(Key? initialKey);
}
diff --git a/paging/rxjava2/api/restricted_current.txt b/paging/rxjava2/api/restricted_current.txt
index c963f93..0059dfe 100644
--- a/paging/rxjava2/api/restricted_current.txt
+++ b/paging/rxjava2/api/restricted_current.txt
@@ -2,7 +2,7 @@
package androidx.paging {
public final class RxPagedDataFlowBuilder<Key, Value> {
- ctor public RxPagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagedList.Config config);
+ ctor public RxPagedDataFlowBuilder(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>> pagedSourceFactory, androidx.paging.PagingConfig config);
method public io.reactivex.Observable<androidx.paging.PagedData<Value>> build();
method public androidx.paging.RxPagedDataFlowBuilder<Key,Value> setInitialKey(Key? initialKey);
}
diff --git a/paging/rxjava2/src/main/java/androidx/paging/RxPagedDataFlowBuilder.kt b/paging/rxjava2/src/main/java/androidx/paging/RxPagedDataFlowBuilder.kt
index 73a0f8e..9050696 100644
--- a/paging/rxjava2/src/main/java/androidx/paging/RxPagedDataFlowBuilder.kt
+++ b/paging/rxjava2/src/main/java/androidx/paging/RxPagedDataFlowBuilder.kt
@@ -30,7 +30,7 @@
*/
class RxPagedDataFlowBuilder<Key : Any, Value : Any>(
pagedSourceFactory: () -> PagedSource<Key, Value>,
- config: PagedList.Config
+ config: PagingConfig
) {
private val baseBuilder = PagedDataFlowBuilder(pagedSourceFactory, config)
diff --git a/paging/testutils/build.gradle b/paging/testutils/build.gradle
new file mode 100644
index 0000000..1bc3e5b
--- /dev/null
+++ b/paging/testutils/build.gradle
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 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.
+ */
+
+
+import androidx.build.AndroidXExtension
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.Publish
+
+import static androidx.build.dependencies.DependenciesKt.*
+
+plugins {
+ id("AndroidXPlugin")
+ id("kotlin")
+}
+
+dependencies {
+ api(KOTLIN_STDLIB)
+ implementation(project(":paging:paging-common"))
+ implementation(KOTLIN_TEST)
+}
+
+androidx {
+ name = "Android Paging Internal Test Utils"
+ publish = Publish.SNAPSHOT_AND_RELEASE
+ mavenVersion = LibraryVersions.PAGING
+ mavenGroup = LibraryGroups.PAGING
+ inceptionYear = "2020"
+ description = "Android Paging Internal Test Utils"
+ url = AndroidXExtension.ARCHITECTURE_URL
+}
diff --git a/paging/testutils/src/main/java/androidx/paging/PageEventUtils.kt b/paging/testutils/src/main/java/androidx/paging/PageEventUtils.kt
new file mode 100644
index 0000000..006e366
--- /dev/null
+++ b/paging/testutils/src/main/java/androidx/paging/PageEventUtils.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 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.paging
+
+import kotlin.test.assertEquals
+
+fun <T> assertEvents(expected: List<T>, actual: List<T>) {
+ try {
+ assertEquals(expected, actual)
+ } catch (e: Throwable) {
+ val msg = e.localizedMessage
+ .replace("),", "),\n")
+ .replace("<[", "<[\n ")
+ .replace("actual", "\nactual")
+ .lines()
+ .toMutableList()
+
+ if (expected.count() != actual.count()) throw AssertionError(msg.joinToString("\n"))
+
+ var index = 0
+ for (i in 0 until expected.count()) {
+ if (expected[i] != actual[i]) {
+ index = i
+ break
+ }
+ }
+ msg[index + 1] = msg[index + 1].prependIndent(" >")
+ msg[msg.count() / 2 + index + 1] = msg[msg.count() / 2 + index + 1].prependIndent(" >")
+ throw AssertionError(msg.joinToString("\n"))
+ }
+}
diff --git a/paging/common/src/test/kotlin/androidx/paging/TestPagedSource.kt b/paging/testutils/src/main/java/androidx/paging/TestPagedSource.kt
similarity index 97%
rename from paging/common/src/test/kotlin/androidx/paging/TestPagedSource.kt
rename to paging/testutils/src/main/java/androidx/paging/TestPagedSource.kt
index bae6e86..5a2027a 100644
--- a/paging/common/src/test/kotlin/androidx/paging/TestPagedSource.kt
+++ b/paging/testutils/src/main/java/androidx/paging/TestPagedSource.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 The Android Open Source Project
+ * Copyright 2020 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.
@@ -69,4 +69,4 @@
val items = List(100) { it }
val LOAD_ERROR = Exception("Exception from TestPagedSource.errorNextLoad")
}
-}
\ No newline at end of file
+}
diff --git a/percentlayout/percentlayout/src/main/java/androidx/percentlayout/widget/PercentRelativeLayout.java b/percentlayout/percentlayout/src/main/java/androidx/percentlayout/widget/PercentRelativeLayout.java
index 32719c2..65bd5d7 100644
--- a/percentlayout/percentlayout/src/main/java/androidx/percentlayout/widget/PercentRelativeLayout.java
+++ b/percentlayout/percentlayout/src/main/java/androidx/percentlayout/widget/PercentRelativeLayout.java
@@ -125,6 +125,7 @@
* app:layout_constraintBottom_toBottomOf="@+id/bottom_guideline" />
*
* </androidx.constraintlayout.widget.ConstraintLayout>
+ * </pre>
*/
@SuppressWarnings("deprecation")
@Deprecated
diff --git a/preference/preference/src/main/java/androidx/preference/DropDownPreference.java b/preference/preference/src/main/java/androidx/preference/DropDownPreference.java
index 45d0357..d66dc34 100644
--- a/preference/preference/src/main/java/androidx/preference/DropDownPreference.java
+++ b/preference/preference/src/main/java/androidx/preference/DropDownPreference.java
@@ -17,6 +17,7 @@
package androidx.preference;
import android.content.Context;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
@@ -136,7 +137,7 @@
CharSequence[] entryValues = getEntryValues();
if (value != null && entryValues != null) {
for (int i = entryValues.length - 1; i >= 0; i--) {
- if (entryValues[i].equals(value)) {
+ if (TextUtils.equals(entryValues[i].toString(), value)) {
return i;
}
}
diff --git a/preference/preference/src/main/java/androidx/preference/ListPreference.java b/preference/preference/src/main/java/androidx/preference/ListPreference.java
index 5b67a8b..3f1361d 100644
--- a/preference/preference/src/main/java/androidx/preference/ListPreference.java
+++ b/preference/preference/src/main/java/androidx/preference/ListPreference.java
@@ -148,9 +148,9 @@
@Override
public void setSummary(CharSequence summary) {
super.setSummary(summary);
- if (summary == null && mSummary != null) {
+ if (summary == null) {
mSummary = null;
- } else if (summary != null && !summary.equals(mSummary)) {
+ } else {
mSummary = summary.toString();
}
}
@@ -222,7 +222,7 @@
public int findIndexOfValue(String value) {
if (value != null && mEntryValues != null) {
for (int i = mEntryValues.length - 1; i >= 0; i--) {
- if (mEntryValues[i].equals(value)) {
+ if (TextUtils.equals(mEntryValues[i].toString(), value)) {
return i;
}
}
diff --git a/preference/preference/src/main/java/androidx/preference/MultiSelectListPreference.java b/preference/preference/src/main/java/androidx/preference/MultiSelectListPreference.java
index 931c9b9..008d326 100644
--- a/preference/preference/src/main/java/androidx/preference/MultiSelectListPreference.java
+++ b/preference/preference/src/main/java/androidx/preference/MultiSelectListPreference.java
@@ -20,6 +20,7 @@
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import android.util.AttributeSet;
import androidx.annotation.ArrayRes;
@@ -166,7 +167,7 @@
public int findIndexOfValue(String value) {
if (value != null && mEntryValues != null) {
for (int i = mEntryValues.length - 1; i >= 0; i--) {
- if (mEntryValues[i].equals(value)) {
+ if (TextUtils.equals(mEntryValues[i].toString(), value)) {
return i;
}
}
diff --git a/preference/preference/src/main/java/androidx/preference/Preference.java b/preference/preference/src/main/java/androidx/preference/Preference.java
index fd765a3..9d9932c 100644
--- a/preference/preference/src/main/java/androidx/preference/Preference.java
+++ b/preference/preference/src/main/java/androidx/preference/Preference.java
@@ -654,7 +654,7 @@
* @param title The title for this preference
*/
public void setTitle(CharSequence title) {
- if ((title == null && mTitle != null) || (title != null && !title.equals(mTitle))) {
+ if (!TextUtils.equals(title, mTitle)) {
mTitle = title;
notifyChanged();
}
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/LinearLayoutManagerSavedStateTest.java b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/LinearLayoutManagerSavedStateTest.java
index ac1562c..78bf4da 100644
--- a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/LinearLayoutManagerSavedStateTest.java
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/LinearLayoutManagerSavedStateTest.java
@@ -270,8 +270,8 @@
// TODO(b/142682722): This test is currently causing process crashes on CuttleFish API 29
// devices that are currently assumed to not be an issue with RecyclerView or this test.
- // Therefore we are temporarily supressing the test on all sdk versions 29 and above until
- // the issue is resovled so that RecyclerView CLs are not blocked.
+ // Therefore we are temporarily suppressing the test on all sdk versions 29 and above until
+ // the issue is resolved so that RecyclerView CLs are not blocked.
@Test
@SdkSuppress(maxSdkVersion = 28)
public void savedStateTest()
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/StaggeredGridLayoutManagerSnappingTest.java b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/StaggeredGridLayoutManagerSnappingTest.java
index da14e85..f602340 100644
--- a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/StaggeredGridLayoutManagerSnappingTest.java
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/StaggeredGridLayoutManagerSnappingTest.java
@@ -245,7 +245,8 @@
mLayoutManager.expectIdleState(2);
smoothScrollBy(scrollDist);
- mLayoutManager.waitForSnap(25);
+ // Very high number to try to reduce flakiness.
+ mLayoutManager.waitForSnap(50);
}
private int getViewDimension(View view) {
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
index d5b85f4..84441fe 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -43,8 +43,8 @@
val MISSING_RAWQUERY_ANNOTATION = "RawQuery methods must be annotated with" +
" ${RawQuery::class.java}"
val INVALID_ON_CONFLICT_VALUE = "On conflict value must be one of @OnConflictStrategy values."
- val TRANSACTION_REFERENCE_DOCS = "https://developer.android.com/reference/android/arch/" +
- "persistence/room/Transaction.html"
+ val TRANSACTION_REFERENCE_DOCS = "https://developer.android.com/reference/androidx/" +
+ "room/Transaction.html"
val ABSTRACT_METHOD_IN_DAO_MISSING_ANY_ANNOTATION = "Abstract method in DAO must be annotated" +
" with ${Query::class.java} AND ${Insert::class.java}"
diff --git a/room/compiler/src/main/kotlin/androidx/room/verifier/DatabaseVerifier.kt b/room/compiler/src/main/kotlin/androidx/room/verifier/DatabaseVerifier.kt
index a7e87c6..0a38780 100644
--- a/room/compiler/src/main/kotlin/androidx/room/verifier/DatabaseVerifier.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/verifier/DatabaseVerifier.kt
@@ -62,9 +62,16 @@
*/
private val SQLITE_NATIVE_LIB_EXTENSIONS = arrayOf(".so", ".jnilib", ".dll")
- private val sqliteNativeLibDir: File
+ private lateinit var sqliteNativeLibDir: File
init {
+ copyNativeLibs()
+ }
+
+ /**
+ * Copies native libraries into a tmp folder to be loaded.
+ */
+ private fun copyNativeLibs() {
// see: https://github.com/xerial/sqlite-jdbc/issues/97
val tmpDir = System.getProperty("java.io.tmpdir")
checkNotNull(tmpDir) {
@@ -106,7 +113,14 @@
nativeLibs.forEach {
it.setExecutable(true)
context.logger.d("reloading the sqlite native file: $it")
- System.load(it.absoluteFile.absolutePath)
+ try {
+ System.load(it.absoluteFile.absolutePath)
+ } catch (unsatisfied: UnsatisfiedLinkError) {
+ // https://issuetracker.google.com/issues/146061836
+ // workaround for b/146061836 where we just copy it again as
+ // another file.
+ copyNativeLibs()
+ }
}
} else {
context.logger.w(Warning.CANNOT_CREATE_VERIFICATION_DATABASE, element,
diff --git a/room/integration-tests/incremental-annotation-processing/build.gradle b/room/integration-tests/incremental-annotation-processing/build.gradle
index 6139835..acc978a 100644
--- a/room/integration-tests/incremental-annotation-processing/build.gradle
+++ b/room/integration-tests/incremental-annotation-processing/build.gradle
@@ -25,6 +25,8 @@
dependencies {
implementation(KOTLIN_STDLIB)
+
+ testImplementation(project(":internal-testutils-gradle-plugin"))
testImplementation(JUNIT)
testImplementation(TRUTH)
testImplementation gradleTestKit()
diff --git a/room/integration-tests/incremental-annotation-processing/src/test/kotlin/androidx/room/gradle/RoomIncrementalAnnotationProcessingTest.kt b/room/integration-tests/incremental-annotation-processing/src/test/kotlin/androidx/room/gradle/RoomIncrementalAnnotationProcessingTest.kt
index d9fd1da..1bf80e6 100644
--- a/room/integration-tests/incremental-annotation-processing/src/test/kotlin/androidx/room/gradle/RoomIncrementalAnnotationProcessingTest.kt
+++ b/room/integration-tests/incremental-annotation-processing/src/test/kotlin/androidx/room/gradle/RoomIncrementalAnnotationProcessingTest.kt
@@ -16,6 +16,7 @@
package androidx.room.gradle
+import androidx.testutils.gradle.ProjectSetupRule
import com.google.common.truth.Expect
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.GradleRunner
@@ -23,12 +24,10 @@
import org.junit.Before
import org.junit.Rule
import org.junit.Test
-import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import java.io.File
import java.nio.file.Files
-import java.util.Properties
@RunWith(Parameterized::class)
class RoomIncrementalAnnotationProcessingTest(private val withIncrementalRoom: Boolean) {
@@ -49,20 +48,11 @@
}
@get:Rule
- val testProjectDir = TemporaryFolder()
+ val projectSetup = ProjectSetupRule()
@get:Rule
val expect: Expect = Expect.create()
- // Properties to set up test project
- private lateinit var prebuiltsRoot: String
- private lateinit var agpDependency: String
- private lateinit var localSupportRepo: String
- private lateinit var compileSdkVersion: String
- private lateinit var buildToolsVersion: String
- private lateinit var minSdkVersion: String
- private lateinit var debugKeystore: String
-
// Original source files
private lateinit var srcDatabase1: File
private lateinit var srcDao1: File
@@ -100,34 +90,14 @@
@Before
fun setup() {
- val projectRoot = testProjectDir.root
-
- // copy local.properties
- File("../../../local.properties")
- .copyTo(File(projectRoot, "local.properties"), overwrite = true)
-
- // copy sdk.prop (created by module's build.gradle)
- RoomIncrementalAnnotationProcessingTest::class.java.classLoader
- .getResourceAsStream("sdk.prop")
- .use { input ->
- val properties = Properties().apply { load(input) }
- prebuiltsRoot = properties.getProperty("prebuiltsRoot")
- localSupportRepo = properties.getProperty("localSupportRepo")
- agpDependency = properties.getProperty("agpDependency")
- compileSdkVersion = properties.getProperty("compileSdkVersion")
- buildToolsVersion = properties.getProperty("buildToolsVersion")
- minSdkVersion = properties.getProperty("minSdkVersion")
- debugKeystore = properties.getProperty("debugKeystore")
- }
+ val projectRoot = projectSetup.rootDir
+ val prebuiltsRoot = projectSetup.props.prebuiltsRoot
+ val localSupportRepo = projectSetup.props.localSupportRepo
+ val agpDependency = projectSetup.props.agpDependency
// copy test project
File("src/test/data/simple-project").copyRecursively(projectRoot)
- // setup gradle.properties
- File(projectRoot, "gradle.properties").writeText(
- "android.useAndroidX=true"
- )
-
// set up build file
File(projectRoot, "build.gradle").writeText(
"""
@@ -154,20 +124,7 @@
}
}
- android {
- compileSdkVersion $compileSdkVersion
- buildToolsVersion "$buildToolsVersion"
-
- defaultConfig {
- minSdkVersion $minSdkVersion
- }
-
- signingConfigs {
- debug {
- storeFile file("$debugKeystore")
- }
- }
- }
+ %s
dependencies {
// Uses latest Room built from tip of tree
@@ -200,7 +157,11 @@
}
}
}
- """.trimIndent()
+ """
+ .trimIndent()
+ // doing format instead of "$projectSetup.androidProject" on purpose,
+ // because otherwise trimIndent will mess with formatting
+ .format(projectSetup.androidProject)
)
// Compute file paths
@@ -230,7 +191,7 @@
private fun runGradleTasks(vararg args: String): BuildResult {
return GradleRunner.create()
- .withProjectDir(testProjectDir.root)
+ .withProjectDir(projectSetup.rootDir)
.withArguments(*args)
.build()
}
diff --git a/room/runtime/src/main/java/androidx/room/InvalidationTracker.java b/room/runtime/src/main/java/androidx/room/InvalidationTracker.java
index f35b7f9..c7ea442 100644
--- a/room/runtime/src/main/java/androidx/room/InvalidationTracker.java
+++ b/room/runtime/src/main/java/androidx/room/InvalidationTracker.java
@@ -361,8 +361,8 @@
public void run() {
final Lock closeLock = mDatabase.getCloseLock();
Set<Integer> invalidatedTableIds = null;
+ closeLock.lock();
try {
- closeLock.lock();
if (!ensureInitialization()) {
return;
diff --git a/room/runtime/src/main/java/androidx/room/RoomDatabase.java b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
index b038c89..8595be4 100644
--- a/room/runtime/src/main/java/androidx/room/RoomDatabase.java
+++ b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
@@ -241,8 +241,8 @@
public void close() {
if (isOpen()) {
final Lock closeLock = mCloseLock.writeLock();
+ closeLock.lock();
try {
- closeLock.lock();
mInvalidationTracker.stopMultiInstanceInvalidation();
mOpenHelper.close();
} finally {
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/ContentUriKeyProvider.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/ContentUriKeyProvider.java
deleted file mode 100644
index cc83ca1..0000000
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/ContentUriKeyProvider.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2017 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.example.android.supportv7.widget.selection.fancy;
-
-import android.net.Uri;
-
-import androidx.annotation.Nullable;
-import androidx.recyclerview.selection.ItemKeyProvider;
-
-import java.util.HashMap;
-import java.util.Map;
-
-class ContentUriKeyProvider extends ItemKeyProvider<Uri> {
-
- private final Uri[] mUris;
- private final Map<Uri, Integer> mPositions;
-
- ContentUriKeyProvider(String authority, String[] values) {
- // Advise the world we can supply ids/position for entire copus
- // at any time.
- super(SCOPE_MAPPED);
-
- mUris = new Uri[values.length];
- mPositions = new HashMap<>();
-
- for (int i = 0; i < values.length; i++) {
- mUris[i] = new Uri.Builder()
- .scheme("content")
- .encodedAuthority(authority)
- .appendPath(values[i])
- .build();
- mPositions.put(mUris[i], i);
- }
- }
-
- @Override
- public @Nullable Uri getKey(int position) {
- return mUris[position];
- }
-
- @Override
- public int getPosition(Uri key) {
- return mPositions.get(key);
- }
-}
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyDetailsLookup.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyDetailsLookup.java
index 92ed977..c2d57f0 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyDetailsLookup.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyDetailsLookup.java
@@ -41,9 +41,11 @@
@Nullable View view = mRecView.findChildViewUnder(e.getX(), e.getY());
if (view != null) {
ViewHolder holder = mRecView.getChildViewHolder(view);
- if (holder instanceof FancyHolder) {
- return ((FancyHolder) holder).getItemDetails();
+ if (holder instanceof FancyItemHolder) {
+ return ((FancyItemHolder) holder).getItemDetails();
}
+ // FancyHeaderHolder doesn't hold a selectable item,
+ // so it doesn't support getItemDetails.
}
return null;
}
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHeaderHolder.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHeaderHolder.java
new file mode 100644
index 0000000..4ed2d1f
--- /dev/null
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHeaderHolder.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 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.example.android.supportv7.widget.selection.fancy;
+
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.example.android.supportv7.R;
+
+final class FancyHeaderHolder extends FancyHolder {
+
+ private static final String HEADER_TAG = "I'm a header";
+ public final TextView mLabel;
+
+ FancyHeaderHolder(LinearLayout layout) {
+ super(layout);
+ layout.setTag(HEADER_TAG);
+ mLabel = layout.findViewById(R.id.label);
+ }
+
+ void update(String label) {
+ mLabel.setText(label.toUpperCase() + label + label + "...");
+ }
+
+ @Override
+ public String toString() {
+ return "Header{name:" + mLabel.getText() + "}";
+ }
+
+ static boolean isHeader(View view) {
+ return HEADER_TAG.equals(view.getTag());
+ }
+}
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHolder.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHolder.java
index 6637d88..6fbc206 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHolder.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHolder.java
@@ -13,111 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.example.android.supportv7.widget.selection.fancy;
-import android.graphics.Rect;
-import android.net.Uri;
-import android.view.MotionEvent;
import android.widget.LinearLayout;
-import android.widget.TextView;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
import androidx.recyclerview.widget.RecyclerView;
-import com.example.android.supportv7.R;
-
-final class FancyHolder extends RecyclerView.ViewHolder {
-
- private final LinearLayout mContainer;
- public final TextView mSelector;
- public final TextView mLabel;
- private final ItemDetails<Uri> mDetails;
-
- private @Nullable Uri mKey;
-
+abstract class FancyHolder extends RecyclerView.ViewHolder {
FancyHolder(LinearLayout layout) {
super(layout);
- mContainer = layout.findViewById(R.id.container);
- mSelector = layout.findViewById(R.id.selector);
- mLabel = layout.findViewById(R.id.label);
- mDetails = new ItemDetails<Uri>() {
- @Override
- public int getPosition() {
- return FancyHolder.this.getAdapterPosition();
- }
-
- @Override
- public Uri getSelectionKey() {
- return FancyHolder.this.mKey;
- }
-
- @Override
- public boolean inDragRegion(@NonNull MotionEvent e) {
- return FancyHolder.this.inDragRegion(e);
- }
-
- @Override
- public boolean inSelectionHotspot(@NonNull MotionEvent e) {
- return FancyHolder.this.inSelectRegion(e);
- }
-
- @NonNull
- @Override
- public String toString() {
- return FancyHolder.this.toString();
- }
- };
- }
-
- void update(Uri key, String label, boolean selected) {
- mKey = key;
- mLabel.setText(label);
- setSelected(selected);
- }
-
- private void setSelected(boolean selected) {
- mContainer.setActivated(selected);
- mSelector.setActivated(selected);
- }
-
- boolean inDragRegion(MotionEvent event) {
- // If itemView is activated = selected, then whole region is interactive
- if (itemView.isActivated()) {
- return true;
- }
-
- // Do everything in global coordinates - it makes things simpler.
- int[] coords = new int[2];
- mSelector.getLocationOnScreen(coords);
-
- Rect textBounds = new Rect();
- mLabel.getPaint().getTextBounds(
- mLabel.getText().toString(), 0, mLabel.getText().length(), textBounds);
-
- Rect rect = new Rect(
- coords[0],
- coords[1],
- coords[0] + mSelector.getWidth() + textBounds.width(),
- coords[1] + Math.max(mSelector.getHeight(), textBounds.height()));
-
- // If the tap occurred inside icon or the text, these are interactive spots.
- return rect.contains((int) event.getRawX(), (int) event.getRawY());
- }
-
- boolean inSelectRegion(MotionEvent e) {
- Rect iconRect = new Rect();
- mSelector.getGlobalVisibleRect(iconRect);
- return iconRect.contains((int) e.getRawX(), (int) e.getRawY());
- }
-
- ItemDetails<Uri> getItemDetails() {
- return mDetails;
- }
-
- @Override
- public String toString() {
- return "Item{name:" + mLabel.getText() + ", url:" + mKey + "}";
}
}
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyItemHolder.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyItemHolder.java
new file mode 100644
index 0000000..c7761b2
--- /dev/null
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyItemHolder.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2017 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.example.android.supportv7.widget.selection.fancy;
+
+import android.graphics.Rect;
+import android.net.Uri;
+import android.view.MotionEvent;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
+
+import com.example.android.supportv7.R;
+
+final class FancyItemHolder extends FancyHolder {
+
+ private final LinearLayout mContainer;
+ private final TextView mSelector;
+ private final TextView mLabel;
+ private final ItemDetails<Uri> mDetails;
+
+ private @Nullable Uri mKey;
+
+ FancyItemHolder(LinearLayout layout) {
+ super(layout);
+
+ mContainer = layout.findViewById(R.id.container);
+ mSelector = layout.findViewById(R.id.selector);
+ mLabel = layout.findViewById(R.id.label);
+ mDetails = new ItemDetails<Uri>() {
+ @Override
+ public int getPosition() {
+ return FancyItemHolder.this.getAdapterPosition();
+ }
+
+ @Override
+ public Uri getSelectionKey() {
+ return FancyItemHolder.this.mKey;
+ }
+
+ @Override
+ public boolean inDragRegion(@NonNull MotionEvent e) {
+ return FancyItemHolder.this.inDragRegion(e);
+ }
+
+ @Override
+ public boolean inSelectionHotspot(@NonNull MotionEvent e) {
+ return FancyItemHolder.this.inSelectRegion(e);
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return FancyItemHolder.this.toString();
+ }
+ };
+ }
+
+ void update(Uri key, String label, boolean selected) {
+ mKey = key;
+ mLabel.setText(label);
+ setSelected(selected);
+ }
+
+ private void setSelected(boolean selected) {
+ mContainer.setActivated(selected);
+ mSelector.setActivated(selected);
+ }
+
+ boolean inDragRegion(MotionEvent event) {
+ // If itemView is activated = selected, then whole region is interactive
+ if (itemView.isActivated()) {
+ return true;
+ }
+
+ // Do everything in global coordinates - it makes things simpler.
+ int[] coords = new int[2];
+ mSelector.getLocationOnScreen(coords);
+
+ Rect textBounds = new Rect();
+ mLabel.getPaint().getTextBounds(
+ mLabel.getText().toString(), 0, mLabel.getText().length(), textBounds);
+
+ Rect rect = new Rect(
+ coords[0],
+ coords[1],
+ coords[0] + mSelector.getWidth() + textBounds.width(),
+ coords[1] + Math.max(mSelector.getHeight(), textBounds.height()));
+
+ // If the tap occurred inside icon or the text, these are interactive spots.
+ return rect.contains((int) event.getRawX(), (int) event.getRawY());
+ }
+
+ boolean inSelectRegion(MotionEvent e) {
+ Rect iconRect = new Rect();
+ mSelector.getGlobalVisibleRect(iconRect);
+ return iconRect.contains((int) e.getRawX(), (int) e.getRawY());
+ }
+
+ ItemDetails<Uri> getItemDetails() {
+ return mDetails;
+ }
+
+ @Override
+ public String toString() {
+ return "Item{name:" + mLabel.getText() + ", url:" + mKey + "}";
+ }
+}
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoActivity.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoActivity.java
index c54368b..38e0046 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoActivity.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoActivity.java
@@ -58,6 +58,7 @@
private GridLayoutManager mLayout;
private int mColumnCount = 1; // This will get updated when layout changes.
+ private boolean mIterceptListenerEnabled = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -66,6 +67,32 @@
setContentView(R.layout.selection_demo_layout);
mRecView = (RecyclerView) findViewById(R.id.list);
+ // If you want to provided special handling of clicks on items
+ // in RecyclerView (respond to a play button, or show a menu
+ // when a three-dot menu is clicked) you can't just add an OnClickListener
+ // to the View. This is because Selection lib installs an
+ // OnItemTouchListener w/ RecyclerView, and that listener eats
+ // up many of the touch/mouse events RecyclerView sends its way.
+ // To work around this install your own OnItemTouchListener *before*
+ // you build your SelectionTracker instance. That'll give your listener
+ // a chance to intercept events before Selection lib gobbles them up.
+ mRecView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
+ @Override
+ public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
+ return mIterceptListenerEnabled
+ && FancyHeaderHolder.isHeader(rv.findChildViewUnder(e.getX(), e.getY()));
+ }
+
+ @Override
+ public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
+ toast(FancySelectionDemoActivity.this, "Clicked on a header!");
+ }
+
+ @Override
+ public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+ }
+ });
+
mLayout = new GridLayoutManager(this, mColumnCount);
mRecView.setLayoutManager(mLayout);
mAdapter = new FancySelectionDemoAdapter(this);
@@ -137,27 +164,19 @@
@CallSuper
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- menu.findItem(R.id.option_menu_add_column).setEnabled(mColumnCount <= 3);
- menu.findItem(R.id.option_menu_remove_column).setEnabled(mColumnCount > 1);
+ menu.findItem(R.id.option_menu_enable_listener)
+ .setEnabled(!mIterceptListenerEnabled);
+ menu.findItem(R.id.option_menu_disable_listener)
+ .setEnabled(mIterceptListenerEnabled);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.option_menu_add_column:
- // TODO: Add columns
- mLayout.setSpanCount(++mColumnCount);
- return true;
- case R.id.option_menu_remove_column:
- mLayout.setSpanCount(--mColumnCount);
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
+ mIterceptListenerEnabled = !mIterceptListenerEnabled;
+ return true;
}
-
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
@@ -302,4 +321,4 @@
return true;
}
}
-}
\ No newline at end of file
+}
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoAdapter.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoAdapter.java
index 5d2f5cb..804e7ec 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoAdapter.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoAdapter.java
@@ -23,8 +23,9 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.LinearLayout;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.recyclerview.selection.ItemKeyProvider;
import androidx.recyclerview.selection.SelectionTracker;
import androidx.recyclerview.widget.RecyclerView;
@@ -32,29 +33,34 @@
import com.example.android.supportv7.Cheeses;
import com.example.android.supportv7.R;
+import java.util.HashMap;
+import java.util.Map;
+
final class FancySelectionDemoAdapter extends RecyclerView.Adapter<FancyHolder> {
- private final ContentUriKeyProvider mKeyProvider;
+ public static final int TYPE_HEADER = 1;
+ public static final int TYPE_ITEM = 2;
+
+ private final KeyProvider mKeyProvider;
private final Context mContext;
- // This should be replaced at "bind" time with a real test that
- // asks SelectionTracker.
- private SelectionTest mSelTest;
+ // This default implementation must be replaced
+ // with a real implementation in #bindSelectionHelper.
+ private SelectionTest mSelTest = new SelectionTest() {
+ @Override
+ public boolean isSelected(Uri id) {
+ throw new IllegalStateException(
+ "Adapter must be initialized with SelectionTracker");
+ }
+ };
FancySelectionDemoAdapter(Context context) {
mContext = context;
- mKeyProvider = new ContentUriKeyProvider("cheeses", Cheeses.sCheeseStrings);
- mSelTest = new SelectionTest() {
- @Override
- public boolean isSelected(Uri id) {
- throw new IllegalStateException(
- "Adapter must be initialized with SelectionTracker");
- }
- };
+ mKeyProvider = new KeyProvider("cheeses", Cheeses.sCheeseStrings);
// In the fancy edition of selection support we supply access to stable
// ids using content URI. Since we can map between position and selection key
- // at will we get fancy dependent functionality like band selection and range support.
+ // at-will we get band selection and range support.
setHasStableIds(false);
}
@@ -63,12 +69,12 @@
}
// Glue together SelectionTracker and the adapter.
- public void bindSelectionHelper(final SelectionTracker<Uri> selectionTracker) {
- checkArgument(selectionTracker != null);
+ public void bindSelectionHelper(final SelectionTracker<Uri> tracker) {
+ checkArgument(tracker != null);
mSelTest = new SelectionTest() {
@Override
public boolean isSelected(Uri id) {
- return selectionTracker.isSelected(id);
+ return tracker.isSelected(id);
}
};
}
@@ -83,7 +89,7 @@
@Override
public int getItemCount() {
- return Cheeses.sCheeseStrings.length;
+ return mKeyProvider.getCount();
}
@Override
@@ -92,15 +98,40 @@
}
@Override
- public void onBindViewHolder(FancyHolder holder, int position) {
- Uri uri = mKeyProvider.getKey(position);
- holder.update(uri, uri.getLastPathSegment(), mSelTest.isSelected(uri));
+ public void onBindViewHolder(@NonNull FancyHolder holder, int position) {
+ if (holder instanceof FancyHeaderHolder) {
+ Uri uri = mKeyProvider.getKey(position);
+ ((FancyHeaderHolder) holder).update(uri.getPathSegments().get(0));
+ } else if (holder instanceof FancyItemHolder) {
+ Uri uri = mKeyProvider.getKey(position);
+ ((FancyItemHolder) holder).update(uri, uri.getPathSegments().get(1),
+ mSelTest.isSelected(uri));
+ }
}
@Override
- public FancyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- LinearLayout layout = inflateLayout(mContext, parent, R.layout.selection_demo_list_item);
- return new FancyHolder(layout);
+ public int getItemViewType(int position) {
+ Uri key = mKeyProvider.getKey(position);
+ if (key.getPathSegments().size() == 1) {
+ return TYPE_HEADER;
+ } else if (key.getPathSegments().size() == 2) {
+ return TYPE_ITEM;
+ }
+
+ throw new RuntimeException("Unknown view type a position " + position);
+ }
+
+ @Override
+ public FancyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ switch (viewType) {
+ case TYPE_HEADER:
+ return new FancyHeaderHolder(
+ inflateLayout(mContext, parent, R.layout.selection_demo_list_header));
+ case TYPE_ITEM:
+ return new FancyItemHolder(
+ inflateLayout(mContext, parent, R.layout.selection_demo_list_item));
+ }
+ throw new RuntimeException("Unsupported view type" + viewType);
}
@SuppressWarnings("TypeParameterUnusedInFormals") // Convenience to avoid clumsy cast.
@@ -113,4 +144,62 @@
private interface SelectionTest {
boolean isSelected(Uri id);
}
+
+ private static final class KeyProvider extends ItemKeyProvider<Uri> {
+
+ private final Uri[] mUris;
+ private final Map<Uri, Integer> mPositions;
+
+ KeyProvider(String authority, String[] values) {
+ // Advise the world we can supply ids/position for entire copus
+ // at any time.
+ super(SCOPE_MAPPED);
+
+ // For the convenience of this demo, we simply trust, based on
+ // past understanding that Cheeses has at least one element
+ // starting with each letter of the English alphabet :)
+ mUris = new Uri[Cheeses.sCheeseStrings.length + 26];
+ mPositions = new HashMap<>();
+
+ char section = '-'; // anything value other than 'a' will do the trick here.
+ int headerOffset = 0;
+
+ for (int i = 0; i < Cheeses.sCheeseStrings.length; i++) {
+ char leadingChar = Cheeses.sCheeseStrings[i].toLowerCase().charAt(0);
+ // When we find a new leading character insert an artificial
+ // cheese header
+ if (leadingChar != section) {
+ section = leadingChar;
+ mUris[i + headerOffset] = new Uri.Builder()
+ .scheme("content")
+ .encodedAuthority(authority)
+ .appendPath(Character.toString(section))
+ .build();
+ mPositions.put(mUris[i + headerOffset], i + headerOffset);
+ headerOffset++;
+ }
+ mUris[i + headerOffset] = new Uri.Builder()
+ .scheme("content")
+ .encodedAuthority(authority)
+ .appendPath(Character.toString(section))
+ .appendPath(Cheeses.sCheeseStrings[i])
+ .build();
+ mPositions.put(mUris[i + headerOffset], i + headerOffset);
+ }
+ }
+
+ @Override
+ public @Nullable Uri getKey(int position) {
+ return mUris[position];
+ }
+
+ @Override
+ public int getPosition(@NonNull Uri key) {
+ return mPositions.get(key);
+ }
+
+ int getCount() {
+ return mUris.length;
+ }
+ }
}
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/SimpleSelectionDemoActivity.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/SimpleSelectionDemoActivity.java
index fafddc4..63fda61 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/SimpleSelectionDemoActivity.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/SimpleSelectionDemoActivity.java
@@ -19,12 +19,9 @@
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
import android.view.MotionEvent;
import android.widget.Toast;
-import androidx.annotation.CallSuper;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
import androidx.recyclerview.selection.ItemKeyProvider;
@@ -128,39 +125,6 @@
}
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
- boolean showMenu = super.onCreateOptionsMenu(menu);
- getMenuInflater().inflate(R.menu.selection_demo_actions, menu);
- return showMenu;
- }
-
- @Override
- @CallSuper
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- menu.findItem(R.id.option_menu_add_column).setEnabled(mColumnCount <= 3);
- menu.findItem(R.id.option_menu_remove_column).setEnabled(mColumnCount > 1);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.option_menu_add_column:
- // TODO: Add columns
- mLayout.setSpanCount(++mColumnCount);
- return true;
-
- case R.id.option_menu_remove_column:
- mLayout.setSpanCount(--mColumnCount);
- return true;
-
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
public void onBackPressed() {
if (mSelectionTracker.clearSelection()) {
return;
diff --git a/samples/Support7Demos/src/main/res/color/selection_demo_item.xml b/samples/Support7Demos/src/main/res/color/selection_demo_item.xml
new file mode 100644
index 0000000..ea11b42
--- /dev/null
+++ b/samples/Support7Demos/src/main/res/color/selection_demo_item.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_activated="true"
+ android:color="?android:attr/colorForegroundInverse"
+ />
+ <item
+ android:state_activated="false"
+ android:color="?android:attr/colorForegroundInverse"
+ android:alpha=".3"
+ />
+</selector>
diff --git a/samples/Support7Demos/src/main/res/color/selection_demo_item_selector.xml b/samples/Support7Demos/src/main/res/color/selection_demo_item_selector.xml
index bd87b4c..c800127 100644
--- a/samples/Support7Demos/src/main/res/color/selection_demo_item_selector.xml
+++ b/samples/Support7Demos/src/main/res/color/selection_demo_item_selector.xml
@@ -16,12 +16,13 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
- android:state_activated="true"
- android:color="?android:attr/colorForeground"
- />
- <item
android:state_activated="false"
android:color="?android:attr/colorForeground"
android:alpha=".3"
/>
+ <item
+ android:state_activated="true"
+ android:color="#FFFF0000"
+ android:alpha=".4"
+ />
</selector>
diff --git a/car-app/app/src/main/AndroidManifest.xml b/samples/Support7Demos/src/main/res/drawable/selection_demo_item.xml
similarity index 77%
rename from car-app/app/src/main/AndroidManifest.xml
rename to samples/Support7Demos/src/main/res/drawable/selection_demo_item.xml
index e1b4910..52d11c5 100644
--- a/car-app/app/src/main/AndroidManifest.xml
+++ b/samples/Support7Demos/src/main/res/drawable/selection_demo_item.xml
@@ -13,4 +13,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<manifest package="androidx.car.app"/>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_activated="true">
+ <color android:color="#22FF0000"></color>
+ </item>
+</selector>
diff --git a/samples/Support7Demos/src/main/res/drawable/selection_demo_item_background.xml b/samples/Support7Demos/src/main/res/drawable/selection_demo_item_background.xml
index e4dbd5f..e15b281 100644
--- a/samples/Support7Demos/src/main/res/drawable/selection_demo_item_background.xml
+++ b/samples/Support7Demos/src/main/res/drawable/selection_demo_item_background.xml
@@ -16,6 +16,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true">
- <color android:color="#220000FF"></color>
+ <color android:color="#2200FF00"></color>
</item>
</selector>
diff --git a/samples/Support7Demos/src/main/res/layout/selection_demo_list_header.xml b/samples/Support7Demos/src/main/res/layout/selection_demo_list_header.xml
new file mode 100644
index 0000000..13e127a
--- /dev/null
+++ b/samples/Support7Demos/src/main/res/layout/selection_demo_list_header.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:paddingStart="10dp"
+ android:paddingEnd="10dp"
+ android:paddingTop="5dp"
+ android:paddingBottom="5dp"
+ android:layout_height="50dp">
+ <LinearLayout
+ android:id="@+id/container"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:background="@drawable/selection_demo_item_background">
+ <TextView
+ android:id="@+id/label"
+ android:textSize="30sp"
+ android:textStyle="bold"
+ android:gravity="center_vertical"
+ android:paddingStart="10dp"
+ android:paddingEnd="10dp"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent">
+ </TextView>
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/Support7Demos/src/main/res/layout/selection_demo_list_item.xml b/samples/Support7Demos/src/main/res/layout/selection_demo_list_item.xml
index 0d4b718..fb5e8e9 100644
--- a/samples/Support7Demos/src/main/res/layout/selection_demo_list_item.xml
+++ b/samples/Support7Demos/src/main/res/layout/selection_demo_list_item.xml
@@ -27,11 +27,10 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
- android:background="@drawable/selection_demo_item_background">
+ android:background="#FFFFFFFF">
<TextView
android:id="@+id/selector"
android:textSize="20sp"
- android:textStyle="bold"
android:gravity="center"
android:layout_height="match_parent"
android:layout_width="40dp"
@@ -47,7 +46,8 @@
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:layout_height="match_parent"
- android:layout_width="match_parent">
+ android:layout_width="wrap_content"
+ android:background="@drawable/selection_demo_item">
</TextView>
</LinearLayout>
</LinearLayout>
diff --git a/samples/Support7Demos/src/main/res/menu/selection_demo_actions.xml b/samples/Support7Demos/src/main/res/menu/selection_demo_actions.xml
index 484d8b6..ce76ddc3 100644
--- a/samples/Support7Demos/src/main/res/menu/selection_demo_actions.xml
+++ b/samples/Support7Demos/src/main/res/menu/selection_demo_actions.xml
@@ -16,9 +16,9 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
- android:id="@+id/option_menu_add_column"
- android:title="Add column" />
+ android:id="@+id/option_menu_enable_listener"
+ android:title="Enable OnItemTouchListener" />
<item
- android:id="@+id/option_menu_remove_column"
- android:title="Remove column" />
+ android:id="@+id/option_menu_disable_listener"
+ android:title="Disable OnItemTouchListener" />
</menu>
diff --git a/samples/SupportTransitionDemos/build.gradle b/samples/SupportTransitionDemos/build.gradle
index d8ba71c..9838c8c 100644
--- a/samples/SupportTransitionDemos/build.gradle
+++ b/samples/SupportTransitionDemos/build.gradle
@@ -7,7 +7,7 @@
implementation(project(":transition:transition"))
implementation(project(":appcompat:appcompat"))
implementation(project(":recyclerview:recyclerview"))
- implementation(project(":interpolator"))
+ implementation(project(":interpolator:interpolator"))
}
android {
diff --git a/savedstate/api/1.0.0-alpha01.txt b/savedstate/savedstate/api/1.0.0-alpha01.txt
similarity index 100%
rename from savedstate/api/1.0.0-alpha01.txt
rename to savedstate/savedstate/api/1.0.0-alpha01.txt
diff --git a/savedstate/api/1.0.0-alpha02.txt b/savedstate/savedstate/api/1.0.0-alpha02.txt
similarity index 100%
rename from savedstate/api/1.0.0-alpha02.txt
rename to savedstate/savedstate/api/1.0.0-alpha02.txt
diff --git a/savedstate/api/1.0.0-alpha03.txt b/savedstate/savedstate/api/1.0.0-alpha03.txt
similarity index 100%
rename from savedstate/api/1.0.0-alpha03.txt
rename to savedstate/savedstate/api/1.0.0-alpha03.txt
diff --git a/savedstate/api/1.0.0-beta00.txt b/savedstate/savedstate/api/1.0.0-beta00.txt
similarity index 100%
rename from savedstate/api/1.0.0-beta00.txt
rename to savedstate/savedstate/api/1.0.0-beta00.txt
diff --git a/savedstate/api/1.0.0-beta01.txt b/savedstate/savedstate/api/1.0.0-beta01.txt
similarity index 100%
rename from savedstate/api/1.0.0-beta01.txt
rename to savedstate/savedstate/api/1.0.0-beta01.txt
diff --git a/savedstate/api/1.0.0-rc01.txt b/savedstate/savedstate/api/1.0.0-rc01.txt
similarity index 100%
rename from savedstate/api/1.0.0-rc01.txt
rename to savedstate/savedstate/api/1.0.0-rc01.txt
diff --git a/savedstate/api/1.1.0-alpha01.txt b/savedstate/savedstate/api/1.1.0-alpha01.txt
similarity index 100%
rename from savedstate/api/1.1.0-alpha01.txt
rename to savedstate/savedstate/api/1.1.0-alpha01.txt
diff --git a/savedstate/api/current.txt b/savedstate/savedstate/api/current.txt
similarity index 100%
rename from savedstate/api/current.txt
rename to savedstate/savedstate/api/current.txt
diff --git a/savedstate/api/public_plus_experimental_1.0.0-alpha02.txt b/savedstate/savedstate/api/public_plus_experimental_1.0.0-alpha02.txt
similarity index 100%
rename from savedstate/api/public_plus_experimental_1.0.0-alpha02.txt
rename to savedstate/savedstate/api/public_plus_experimental_1.0.0-alpha02.txt
diff --git a/savedstate/api/public_plus_experimental_1.0.0-beta01.txt b/savedstate/savedstate/api/public_plus_experimental_1.0.0-beta01.txt
similarity index 100%
rename from savedstate/api/public_plus_experimental_1.0.0-beta01.txt
rename to savedstate/savedstate/api/public_plus_experimental_1.0.0-beta01.txt
diff --git a/savedstate/api/public_plus_experimental_1.0.0-rc01.txt b/savedstate/savedstate/api/public_plus_experimental_1.0.0-rc01.txt
similarity index 100%
rename from savedstate/api/public_plus_experimental_1.0.0-rc01.txt
rename to savedstate/savedstate/api/public_plus_experimental_1.0.0-rc01.txt
diff --git a/savedstate/api/public_plus_experimental_1.1.0-alpha01.txt b/savedstate/savedstate/api/public_plus_experimental_1.1.0-alpha01.txt
similarity index 100%
rename from savedstate/api/public_plus_experimental_1.1.0-alpha01.txt
rename to savedstate/savedstate/api/public_plus_experimental_1.1.0-alpha01.txt
diff --git a/savedstate/api/public_plus_experimental_current.txt b/savedstate/savedstate/api/public_plus_experimental_current.txt
similarity index 100%
rename from savedstate/api/public_plus_experimental_current.txt
rename to savedstate/savedstate/api/public_plus_experimental_current.txt
diff --git a/savedstate/api/res-1.0.0-alpha01.txt b/savedstate/savedstate/api/res-1.0.0-alpha01.txt
similarity index 100%
rename from savedstate/api/res-1.0.0-alpha01.txt
rename to savedstate/savedstate/api/res-1.0.0-alpha01.txt
diff --git a/savedstate/api/res-1.0.0-alpha02.txt b/savedstate/savedstate/api/res-1.0.0-alpha02.txt
similarity index 100%
rename from savedstate/api/res-1.0.0-alpha02.txt
rename to savedstate/savedstate/api/res-1.0.0-alpha02.txt
diff --git a/savedstate/api/res-1.0.0-alpha03.txt b/savedstate/savedstate/api/res-1.0.0-alpha03.txt
similarity index 100%
rename from savedstate/api/res-1.0.0-alpha03.txt
rename to savedstate/savedstate/api/res-1.0.0-alpha03.txt
diff --git a/savedstate/api/res-1.0.0-beta00.txt b/savedstate/savedstate/api/res-1.0.0-beta00.txt
similarity index 100%
rename from savedstate/api/res-1.0.0-beta00.txt
rename to savedstate/savedstate/api/res-1.0.0-beta00.txt
diff --git a/savedstate/api/res-1.0.0-beta01.txt b/savedstate/savedstate/api/res-1.0.0-beta01.txt
similarity index 100%
rename from savedstate/api/res-1.0.0-beta01.txt
rename to savedstate/savedstate/api/res-1.0.0-beta01.txt
diff --git a/savedstate/api/res-1.0.0-rc01.txt b/savedstate/savedstate/api/res-1.0.0-rc01.txt
similarity index 100%
rename from savedstate/api/res-1.0.0-rc01.txt
rename to savedstate/savedstate/api/res-1.0.0-rc01.txt
diff --git a/savedstate/api/res-1.1.0-alpha01.txt b/savedstate/savedstate/api/res-1.1.0-alpha01.txt
similarity index 100%
rename from savedstate/api/res-1.1.0-alpha01.txt
rename to savedstate/savedstate/api/res-1.1.0-alpha01.txt
diff --git a/savedstate/api/restricted_1.0.0-alpha01.txt b/savedstate/savedstate/api/restricted_1.0.0-alpha01.txt
similarity index 100%
rename from savedstate/api/restricted_1.0.0-alpha01.txt
rename to savedstate/savedstate/api/restricted_1.0.0-alpha01.txt
diff --git a/savedstate/api/restricted_1.0.0-alpha02.txt b/savedstate/savedstate/api/restricted_1.0.0-alpha02.txt
similarity index 100%
rename from savedstate/api/restricted_1.0.0-alpha02.txt
rename to savedstate/savedstate/api/restricted_1.0.0-alpha02.txt
diff --git a/savedstate/api/restricted_1.0.0-alpha03.txt b/savedstate/savedstate/api/restricted_1.0.0-alpha03.txt
similarity index 100%
rename from savedstate/api/restricted_1.0.0-alpha03.txt
rename to savedstate/savedstate/api/restricted_1.0.0-alpha03.txt
diff --git a/savedstate/api/restricted_1.0.0-beta00.txt b/savedstate/savedstate/api/restricted_1.0.0-beta00.txt
similarity index 100%
rename from savedstate/api/restricted_1.0.0-beta00.txt
rename to savedstate/savedstate/api/restricted_1.0.0-beta00.txt
diff --git a/savedstate/api/restricted_1.0.0-beta01.txt b/savedstate/savedstate/api/restricted_1.0.0-beta01.txt
similarity index 100%
rename from savedstate/api/restricted_1.0.0-beta01.txt
rename to savedstate/savedstate/api/restricted_1.0.0-beta01.txt
diff --git a/savedstate/api/restricted_1.0.0-rc01.txt b/savedstate/savedstate/api/restricted_1.0.0-rc01.txt
similarity index 100%
rename from savedstate/api/restricted_1.0.0-rc01.txt
rename to savedstate/savedstate/api/restricted_1.0.0-rc01.txt
diff --git a/savedstate/api/restricted_1.1.0-alpha01.txt b/savedstate/savedstate/api/restricted_1.1.0-alpha01.txt
similarity index 100%
rename from savedstate/api/restricted_1.1.0-alpha01.txt
rename to savedstate/savedstate/api/restricted_1.1.0-alpha01.txt
diff --git a/savedstate/api/restricted_current.txt b/savedstate/savedstate/api/restricted_current.txt
similarity index 100%
rename from savedstate/api/restricted_current.txt
rename to savedstate/savedstate/api/restricted_current.txt
diff --git a/savedstate/build.gradle b/savedstate/savedstate/build.gradle
similarity index 100%
rename from savedstate/build.gradle
rename to savedstate/savedstate/build.gradle
diff --git a/savedstate/proguard-rules.pro b/savedstate/savedstate/proguard-rules.pro
similarity index 100%
rename from savedstate/proguard-rules.pro
rename to savedstate/savedstate/proguard-rules.pro
diff --git a/savedstate/src/androidTest/AndroidManifest.xml b/savedstate/savedstate/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from savedstate/src/androidTest/AndroidManifest.xml
rename to savedstate/savedstate/src/androidTest/AndroidManifest.xml
diff --git a/savedstate/src/androidTest/java/androidx/savedstate/ErrorInStaticBlock.java b/savedstate/savedstate/src/androidTest/java/androidx/savedstate/ErrorInStaticBlock.java
similarity index 100%
rename from savedstate/src/androidTest/java/androidx/savedstate/ErrorInStaticBlock.java
rename to savedstate/savedstate/src/androidTest/java/androidx/savedstate/ErrorInStaticBlock.java
diff --git a/savedstate/src/androidTest/java/androidx/savedstate/SavedStateRegistryTest.kt b/savedstate/savedstate/src/androidTest/java/androidx/savedstate/SavedStateRegistryTest.kt
similarity index 100%
rename from savedstate/src/androidTest/java/androidx/savedstate/SavedStateRegistryTest.kt
rename to savedstate/savedstate/src/androidTest/java/androidx/savedstate/SavedStateRegistryTest.kt
diff --git a/savedstate/src/main/AndroidManifest.xml b/savedstate/savedstate/src/main/AndroidManifest.xml
similarity index 100%
rename from savedstate/src/main/AndroidManifest.xml
rename to savedstate/savedstate/src/main/AndroidManifest.xml
diff --git a/savedstate/src/main/java/androidx/savedstate/Recreator.java b/savedstate/savedstate/src/main/java/androidx/savedstate/Recreator.java
similarity index 100%
rename from savedstate/src/main/java/androidx/savedstate/Recreator.java
rename to savedstate/savedstate/src/main/java/androidx/savedstate/Recreator.java
diff --git a/savedstate/src/main/java/androidx/savedstate/SavedStateRegistry.java b/savedstate/savedstate/src/main/java/androidx/savedstate/SavedStateRegistry.java
similarity index 100%
rename from savedstate/src/main/java/androidx/savedstate/SavedStateRegistry.java
rename to savedstate/savedstate/src/main/java/androidx/savedstate/SavedStateRegistry.java
diff --git a/savedstate/src/main/java/androidx/savedstate/SavedStateRegistryController.java b/savedstate/savedstate/src/main/java/androidx/savedstate/SavedStateRegistryController.java
similarity index 100%
rename from savedstate/src/main/java/androidx/savedstate/SavedStateRegistryController.java
rename to savedstate/savedstate/src/main/java/androidx/savedstate/SavedStateRegistryController.java
diff --git a/savedstate/src/main/java/androidx/savedstate/SavedStateRegistryOwner.java b/savedstate/savedstate/src/main/java/androidx/savedstate/SavedStateRegistryOwner.java
similarity index 100%
rename from savedstate/src/main/java/androidx/savedstate/SavedStateRegistryOwner.java
rename to savedstate/savedstate/src/main/java/androidx/savedstate/SavedStateRegistryOwner.java
diff --git a/settings.gradle b/settings.gradle
index 5072ddc..686c4f6 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -94,7 +94,6 @@
includeProject(":camera:integration-tests:camera-testapp-view", "camera/integration-tests/viewtestapp")
includeProject(":camera:integration-tests:camera-testlib-extensions", "camera/integration-tests/extensionstestlib")
includeProject(":car", "car/core")
-includeProject(":car-app:app", "car-app/app")
includeProject(":car-moderator", "car/moderator")
includeProject(":cardview:cardview", "cardview/cardview")
includeProject(":collection:collection", "collection/collection")
@@ -131,7 +130,7 @@
includeProject(":inspection:inspection", "inspection/inspection")
includeProject(":inspection:inspection-gradle-plugin", "inspection/inspection-gradle-plugin")
includeProject(":inspection:inspection-testing", "inspection/inspection-testing")
-includeProject(":interpolator", "interpolator")
+includeProject(":interpolator:interpolator", "interpolator/interpolator")
includeProject(":jetifier-core", "jetifier/jetifier/core")
includeProject(":jetifier-processor", "jetifier/jetifier/processor")
includeProject(":jetifier-standalone", "jetifier/jetifier/standalone")
@@ -201,6 +200,7 @@
includeProject(":paging:paging-rxjava2", "paging/rxjava2")
includeProject(":paging:paging-rxjava2-ktx", "paging/rxjava2/ktx")
includeProject(":paging:paging-guava", "paging/guava")
+includeProject(":paging:paging-testutils", "paging/testutils")
includeProject(":palette:palette", "palette/palette")
includeProject(":palette:palette-ktx", "palette/palette-ktx")
includeProject(":percentlayout:percentlayout", "percentlayout/percentlayout")
@@ -229,7 +229,7 @@
includeProject(":remotecallback", "remotecallback")
includeProject(":versionedparcelable-annotation", "versionedparcelable/annotation")
includeProject(":versionedparcelable", "versionedparcelable")
-includeProject(":savedstate", "savedstate")
+includeProject(":savedstate:savedstate", "savedstate/savedstate")
includeProject(":security:security-crypto", "security/crypto")
includeProject(":security:security-identity-credential", "security/identity-credential")
includeProject(":serialization:serialization", "serialization/serialization")
@@ -262,7 +262,7 @@
includeProject(":vectordrawable:vectordrawable", "vectordrawable/vectordrawable")
includeProject(":vectordrawable:vectordrawable-animated", "vectordrawable/vectordrawable-animated")
includeProject(":viewpager", "viewpager")
-includeProject(":viewpager2", "viewpager2")
+includeProject(":viewpager2:viewpager2", "viewpager2/viewpager2")
includeProject(":viewpager2:integration-tests:testapp", "viewpager2/integration-tests/testapp")
includeProject(":wear:wear", "wear/wear")
includeProject(":webkit:webkit", "webkit/webkit")
@@ -322,6 +322,7 @@
includeProject(":internal-testutils-truth", "testutils/testutils-truth")
includeProject(":internal-testutils-ktx", "testutils/testutils-ktx")
includeProject(":internal-testutils-navigation", "testutils/testutils-navigation")
+includeProject(":internal-testutils-gradle-plugin", "testutils/testutils-gradle-plugin")
/////////////////////////////
//
diff --git a/sqlite/sqlite-inspection/src/androidTest/java/SqliteInspectorTest.kt b/sqlite/sqlite-inspection/src/androidTest/java/SqliteInspectorTest.kt
deleted file mode 100644
index cbf6ff5..0000000
--- a/sqlite/sqlite-inspection/src/androidTest/java/SqliteInspectorTest.kt
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * Copyright 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 androidx.sqlite.inspection
-
-import android.database.sqlite.SQLiteDatabase
-import android.database.sqlite.SQLiteOpenHelper
-import androidx.inspection.InspectorEnvironment
-import androidx.inspection.InspectorEnvironment.EntryHook
-import androidx.inspection.InspectorEnvironment.ExitHook
-import androidx.inspection.testing.InspectorTester
-import androidx.sqlite.inspection.SqliteInspectorProtocol.CellValue
-import androidx.sqlite.inspection.SqliteInspectorProtocol.CellValue.ValueCase
-import androidx.sqlite.inspection.SqliteInspectorProtocol.Command
-import androidx.sqlite.inspection.SqliteInspectorProtocol.Event
-import androidx.sqlite.inspection.SqliteInspectorProtocol.GetSchemaCommand
-import androidx.sqlite.inspection.SqliteInspectorProtocol.Response
-import androidx.sqlite.inspection.SqliteInspectorProtocol.Row
-import androidx.sqlite.inspection.SqliteInspectorProtocol.TrackDatabasesCommand
-import androidx.sqlite.inspection.SqliteInspectorProtocol.TrackDatabasesResponse
-import androidx.sqlite.inspection.SqliteInspectorTest.FakeInspectorEnvironment.RegisterHookEntry.EntryHookEntry
-import androidx.sqlite.inspection.SqliteInspectorTest.FakeInspectorEnvironment.RegisterHookEntry.ExitHookEntry
-import androidx.sqlite.inspection.SqliteInspectorTest.MessageFactory.createTrackDatabasesCommand
-import androidx.sqlite.inspection.SqliteInspectorTest.MessageFactory.createTrackDatabasesResponse
-import androidx.sqlite.inspection.SqliteInspectorTest.MessageFactory.createGetSchemaCommand
-import androidx.sqlite.inspection.SqliteInspectorTest.MessageFactory.createQueryTableCommand
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.MediumTest
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.runBlocking
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.TemporaryFolder
-import org.junit.runner.RunWith
-
-@MediumTest
-@RunWith(AndroidJUnit4::class)
-@ExperimentalCoroutinesApi
-class SqliteInspectorTest {
- @get:Rule
- val tempDirectory = TemporaryFolder()
-
- @Test
- fun test_basic_proto() {
- val command = createTrackDatabasesCommand()
-
- val commandBytes = command.toByteArray()
- assertThat(commandBytes).isNotEmpty()
-
- val commandBack = Command.parseFrom(commandBytes)
- assertThat(commandBack).isEqualTo(command)
- }
-
- @Test
- fun test_basic_inject() = runBlocking {
- TestEnvironment.setUp().run {
- // no crash means the inspector was successfully injected
- assertNoQueuedEvents()
- dispose()
- }
- }
-
- @Test
- fun test_track_databases() = runBlocking {
- val alreadyOpenDatabases = listOf(Database("db1"), Database("db2"))
-
- TestEnvironment.setUp(alreadyOpenDatabases).run {
- sendCommand(createTrackDatabasesCommand()).let { response ->
- assertThat(response).isEqualTo(createTrackDatabasesResponse())
- }
-
- // evaluate 'already-open' instances are found
- alreadyOpenDatabases.let { expected ->
- val actual = expected.indices.map { receiveEvent().databaseOpened }
- assertNoQueuedEvents()
- assertThat(actual.map { it.databaseId }.distinct()).hasSize(expected.size)
- expected.forEachIndexed { ix, _ ->
- assertThat(actual[ix].name).isEqualTo(expected[ix].path)
- }
- }
-
- // evaluate registered hooks
- val hookEntries = consumeRegisteredHooks()
- assertThat(hookEntries).hasSize(1)
- hookEntries.first().let { entry ->
- // expect one exit hook tracking database open events
- assertThat(entry).isInstanceOf(ExitHookEntry::class.java)
- assertThat(entry.originClass.name).isEqualTo(SQLiteDatabase::class.java.name)
- assertThat(entry.originMethod)
- .isEqualTo(SqliteInspector.sOpenDatabaseCommandSignature)
-
- // verify that executing the registered hook will result in tracking events
- assertNoQueuedEvents()
- @Suppress("UNCHECKED_CAST")
- val exitHook = (entry as ExitHookEntry).exitHook as ExitHook<SQLiteDatabase>
- val database = Database("db3").instance
- assertThat(exitHook.onExit(database)).isSameInstanceAs(database)
- receiveEvent().let { event ->
- assertThat(event.databaseOpened.name).isEqualTo(database.path)
- }
- }
-
- assertThat(consumeRegisteredHooks()).isEmpty()
- dispose()
- }
- }
-
- @Test
- fun test_get_schema_complex_tables() {
- test_get_schema(
- listOf(
- Database(
- "db1",
- Table(
- "table1",
- Column("t", "TEXT"),
- Column("nu", "NUMERIC"),
- Column("i", "INTEGER"),
- Column("r", "REAL"),
- Column("b", "BLOB")
- ),
- Table(
- "table2",
- Column("id", "INTEGER"),
- Column("name", "TEXT")
-
- )
- )
- )
- )
- }
-
- @Test
- fun test_get_schema_multiple_databases() {
- test_get_schema(
- listOf(
- Database("db3", Table("t3", Column("c3", "BLOB"))),
- Database("db2", Table("t2", Column("c2", "TEXT"))),
- Database("db1", Table("t1", Column("c1", "TEXT")))
- )
- )
- }
-
- private fun test_get_schema(alreadyOpenDatabases: List<Database>) = runBlocking {
- assertThat(alreadyOpenDatabases).isNotEmpty()
-
- // prepare test environment
- TestEnvironment.setUp(alreadyOpenDatabases).run {
- sendCommand(createTrackDatabasesCommand())
- val databaseConnections =
- alreadyOpenDatabases.indices.map { receiveEvent().databaseOpened }
-
- val schemas =
- databaseConnections
- .sortedBy { it.name }
- .map { sendCommand(createGetSchemaCommand(it.databaseId)).getSchema }
-
- alreadyOpenDatabases
- .sortedBy { it.path }
- .forEach2(schemas) { expectedSchema, actualSchema ->
- val expectedTables = expectedSchema.tables.sortedBy { it.name }
- val actualTables = actualSchema.tablesList.sortedBy { it.name }
-
- expectedTables.forEach2(actualTables) { expectedTable, actualTable ->
- assertThat(actualTable.name).isEqualTo(expectedTable.name)
-
- val expectedColumns = expectedTable.columns.sortedBy { it.name }
- val actualColumns = actualTable.columnsList.sortedBy { it.name }
-
- expectedColumns.forEach2(actualColumns) { expectedColumn, actualColumn ->
- assertThat(actualColumn.name).isEqualTo(expectedColumn.name)
- assertThat(actualColumn.type).isEqualTo(expectedColumn.type)
- }
- }
- }
-
- dispose()
- }
- }
-
- @Test
- fun test_query() = runBlocking {
- // TODO: add tests for invalid queries
- // TODO: add tests spanning multiple tables (e.g. union of two queries)
- // TODO: split into smaller tests / test class
-
- // given
- val table1 = Table(
- "table1",
- Column("t", "TEXT"),
- Column("nu", "NUMERIC"),
- Column("i", "INTEGER"),
- Column("r", "REAL"),
- Column("b", "BLOB")
- )
-
- val table2 = Table(
- "table2",
- Column("id", "INTEGER"),
- Column("name", "TEXT")
- )
-
- val database = Database("db1", table1, table2)
-
- TestEnvironment.setUp(
- alreadyOpenDatabases = listOf(
- Database("ignored_1"),
- database,
- Database("ignored_2")
- )
- ).run {
- database.insertValues(table1, *repeat5("'500.0'"))
- database.insertValues(table1, *repeat5("500.0"))
- database.insertValues(table1, *repeat5("500"))
- database.insertValues(table1, *repeat5("x'0500'"))
- database.insertValues(table1, *repeat5("NULL"))
-
- database.insertValues(table2, "1", "'A'")
- database.insertValues(table2, "2", "'B'")
- database.insertValues(table2, "3", "'C'")
- database.insertValues(table2, "4", "'D'")
-
- sendCommand(createTrackDatabasesCommand())
- val databaseId = findDatabaseId(database.path)
-
- val query = "select * from ${table1.name}"
-
- val expectedValues = listOf(
- listOf("500.0", 500, 500, 500.0f, "500.0"), // text|integer|integer|float|text
- listOf("500.0", 500, 500, 500.0f, 500.0f), // text|integer|integer|float|float
- listOf("500", 500, 500, 500.0f, 500), // text|integer|integer|float|integer
- listOf(*repeat5(arrayOf<Any?>(5.toByte(), 0.toByte()))), // blob|blob|blob|blob|blob
- listOf(*repeat5<Any?>(null)) // null|null|null|null|null
- )
-
- val expectedTypes = listOf(
- listOf("text", "integer", "integer", "float", "text"),
- listOf("text", "integer", "integer", "float", "float"),
- listOf("text", "integer", "integer", "float", "integer"),
- listOf("blob", "blob", "blob", "blob", "blob"),
- listOf("null", "null", "null", "null", "null")
- )
-
- // when
- sendCommand(createQueryTableCommand(databaseId, query)).let { response ->
- // then
- response.query.rowsList.let { actualRows: List<Row> ->
- actualRows.forEachIndexed { rowIx, row ->
- row.valuesList.forEachIndexed { colIx, cell ->
- assertThat(cell.value).isEqualTo(expectedValues[rowIx][colIx])
- assertThat(cell.type).isEqualTo(expectedTypes[rowIx][colIx])
- assertThat(cell.columnName).isEqualTo(table1.columns[colIx].name)
- }
- }
- }
- }
- }
- }
-
- private class TestEnvironment private constructor(
- private val inspectorTester: InspectorTester,
- private val environment: FakeInspectorEnvironment
- ) {
- suspend fun sendCommand(command: Command): Response =
- inspectorTester.sendCommand(command.toByteArray())
- .let { responseBytes ->
- assertThat(responseBytes).isNotEmpty()
- Response.parseFrom(responseBytes)
- }
-
- suspend fun receiveEvent(): Event =
- inspectorTester.channel.receive().let { responseBytes ->
- assertThat(responseBytes).isNotEmpty()
- Event.parseFrom(responseBytes)
- }
-
- /** Assumes an event with the relevant database will be fired. */
- suspend fun findDatabaseId(databaseName: String): Int {
- while (true) {
- val event = receiveEvent().databaseOpened
- if (event.name == databaseName) {
- return event.databaseId
- }
- }
- }
-
- fun consumeRegisteredHooks(): List<FakeInspectorEnvironment.RegisterHookEntry> =
- environment.consumeRegisteredHooks()
-
- fun dispose() {
- assertNoQueuedEvents() // remove if doesn't match future test design
- inspectorTester.dispose()
- }
-
- fun assertNoQueuedEvents() {
- assertThat(inspectorTester.channel.isEmpty).isTrue()
- }
-
- /** Iterates over two lists of the same size */
- fun <A, B> List<A>.forEach2(other: List<B>, action: (A, B) -> Unit) {
- assertThat(this.size).isEqualTo(other.size)
- zip(other, action)
- }
-
- inline fun <reified T> repeatN(value: T, n: Int): Array<T> =
- (0 until n).map { value }.toTypedArray()
-
- inline fun <reified T> repeat5(v: T) = repeatN(v, 5)
-
- val (CellValue).value: Any? get() = valueType.first
- val (CellValue).type: String get() = valueType.second
- val (CellValue).valueType: Pair<Any?, String>
- get() = when (valueCase) {
- ValueCase.STRING_VALUE -> stringValue to "text"
- ValueCase.INT_VALUE -> intValue to "integer"
- ValueCase.FLOAT_VALUE -> floatValue to "float"
- ValueCase.BLOB_VALUE -> blobValue.toByteArray().toTypedArray() to "blob"
- ValueCase.VALUE_NOT_SET -> null to "null"
- else -> throw IllegalArgumentException()
- }
-
- companion object {
- suspend fun setUp(alreadyOpenDatabases: List<Database> = emptyList()): TestEnvironment {
- // prepare test environment
- val environment = FakeInspectorEnvironment()
- val inspectorTester =
- InspectorTester(SqliteInspectorFactory.SQLITE_INSPECTOR_ID, environment)
- // prepare test environment: registered hooks
- assertThat(environment.consumeRegisteredHooks()).isEmpty()
- // prepare test environment: register 'already open' instances
- environment.registerInstancesToFind(alreadyOpenDatabases.map {
- it.instance
- })
- return TestEnvironment(inspectorTester, environment)
- }
- }
- }
-
- private inner class Database(name: String, val tables: List<Table>) {
- constructor(name: String, vararg tables: Table) : this(name, tables.toList())
-
- val path: String = tempDirectory.newFile(name).absolutePath
-
- val instance: SQLiteDatabase by lazy {
- createDatabase().also { db -> tables.forEach { t -> db.addTable(t) } }
- }
-
- fun insertValues(table: Table, vararg values: String) {
- assertThat(values).isNotEmpty()
- assertThat(values).hasLength(table.columns.size)
- instance.insertValues(table.name, values.toList())
- }
-
- private fun createDatabase(): SQLiteDatabase {
- val context = ApplicationProvider.getApplicationContext() as android.content.Context
- val openHelper = object : SQLiteOpenHelper(context, path, null, 1) {
- override fun onCreate(db: SQLiteDatabase?) = Unit
- override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) = Unit
- }
- return openHelper.readableDatabase
- }
-
- private fun SQLiteDatabase.addTable(table: Table) = execSQL(table.toCreateString())
-
- private fun SQLiteDatabase.insertValues(tableName: String, values: List<String>) {
- execSQL(values.joinToString(
- prefix = "INSERT INTO $tableName VALUES(",
- postfix = ");"
- ) { it })
- }
- }
-
- private data class Table(val name: String, val columns: List<Column>) {
- constructor(name: String, vararg columns: Column) : this(name, columns.toList())
-
- init {
- assertThat(columns).isNotEmpty()
- }
-
- fun toCreateString(): String =
- columns.joinToString(
- prefix = "CREATE TABLE $name (",
- postfix = ");"
- ) { "${it.name} ${it.type}" }
- }
-
- private data class Column(val name: String, val type: String)
-
- private object MessageFactory {
- fun createTrackDatabasesCommand(): Command =
- Command.newBuilder().setTrackDatabases(
- TrackDatabasesCommand.getDefaultInstance()
- ).build()
-
- fun createTrackDatabasesResponse(): Response =
- Response.newBuilder().setTrackDatabases(
- TrackDatabasesResponse.getDefaultInstance()
- ).build()
-
- fun createGetSchemaCommand(databaseId: Int): Command =
- Command.newBuilder().setGetSchema(
- GetSchemaCommand.newBuilder().setDatabaseId(databaseId).build()
- ).build()
-
- fun createQueryTableCommand(
- databaseId: Int,
- query: String
- ): Command =
- Command.newBuilder().setQuery(
- SqliteInspectorProtocol.QueryCommand.newBuilder()
- .setDatabaseId(databaseId)
- .setQuery(query)
- .build()
- ).build()
- }
-
- /**
- * Fake inspector environment with the following behaviour:
- * - [findInstances] returns pre-registered values from [registerInstancesToFind].
- * - [registerEntryHook] and [registerExitHook] record the calls which can later be
- * retrieved in [consumeRegisteredHooks].
- */
- private class FakeInspectorEnvironment : InspectorEnvironment {
- private val instancesToFind = mutableListOf<Any>()
- private val registeredHooks = mutableListOf<RegisterHookEntry>()
-
- fun registerInstancesToFind(instances: List<Any>) {
- instancesToFind.addAll(instances)
- }
-
- /**
- * Returns instances pre-registered in [registerInstancesToFind].
- * By design crashes in case of the wrong setup - indicating an issue with test code.
- */
- @Suppress("UNCHECKED_CAST")
- // TODO: implement actual findInstances behaviour
- override fun <T : Any?> findInstances(clazz: Class<T>): MutableList<T> =
- instancesToFind.map { it as T }.toMutableList()
-
- override fun registerEntryHook(
- originClass: Class<*>,
- originMethod: String,
- entryHook: EntryHook
- ) {
- // TODO: implement actual registerEntryHook behaviour
- registeredHooks.add(EntryHookEntry(originClass, originMethod, entryHook))
- }
-
- override fun <T : Any?> registerExitHook(
- originClass: Class<*>,
- originMethod: String,
- exitHook: ExitHook<T>
- ) {
- // TODO: implement actual registerExitHook behaviour
- registeredHooks.add(ExitHookEntry(originClass, originMethod, exitHook))
- }
-
- fun consumeRegisteredHooks(): List<RegisterHookEntry> =
- registeredHooks.toList().also {
- registeredHooks.clear()
- }
-
- sealed class RegisterHookEntry(val originClass: Class<*>, val originMethod: String) {
- class ExitHookEntry(
- originClass: Class<*>,
- originMethod: String,
- val exitHook: ExitHook<*>
- ) : RegisterHookEntry(originClass, originMethod)
-
- class EntryHookEntry(
- originClass: Class<*>,
- originMethod: String,
- @Suppress("unused") val entryHook: EntryHook
- ) : RegisterHookEntry(originClass, originMethod)
- }
- }
-}
diff --git a/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/BasicTest.kt b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/BasicTest.kt
new file mode 100644
index 0000000..a95b53f
--- /dev/null
+++ b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/BasicTest.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 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.sqlite.inspection.test
+
+import androidx.sqlite.inspection.SqliteInspectorProtocol
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@ExperimentalCoroutinesApi
+class BasicTest {
+ @get:Rule
+ val testEnvironment = SqliteInspectorTestEnvironment()
+
+ @Test
+ fun test_basic_proto() {
+ val command = MessageFactory.createTrackDatabasesCommand()
+
+ val commandBytes = command.toByteArray()
+ assertThat(commandBytes).isNotEmpty()
+
+ val commandBack = SqliteInspectorProtocol.Command.parseFrom(commandBytes)
+ assertThat(commandBack).isEqualTo(command)
+ }
+
+ @Test
+ fun test_basic_inject() {
+ // no crash means the inspector was successfully injected
+ testEnvironment.assertNoQueuedEvents()
+ }
+}
diff --git a/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/DatabaseExtensions.kt b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/DatabaseExtensions.kt
new file mode 100644
index 0000000..0d3ea83
--- /dev/null
+++ b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/DatabaseExtensions.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2020 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.sqlite.inspection.test
+
+import android.database.sqlite.SQLiteDatabase
+import android.database.sqlite.SQLiteOpenHelper
+import androidx.test.core.app.ApplicationProvider
+import com.google.common.truth.Truth.assertThat
+import org.junit.rules.TemporaryFolder
+
+fun SQLiteDatabase.addTable(table: Table) = execSQL(table.toCreateString())
+
+fun SQLiteDatabase.insertValues(table: Table, vararg values: String) {
+ assertThat(values).isNotEmpty()
+ assertThat(values).hasLength(table.columns.size)
+ execSQL(values.joinToString(
+ prefix = "INSERT INTO ${table.name} VALUES(",
+ postfix = ");"
+ ) { it })
+}
+
+fun Database.createInstance(temporaryFolder: TemporaryFolder): SQLiteDatabase {
+ val path = temporaryFolder.newFile(this.name).absolutePath
+ val context = ApplicationProvider.getApplicationContext() as android.content.Context
+ val openHelper = object : SQLiteOpenHelper(context, path, null, 1) {
+ override fun onCreate(db: SQLiteDatabase?) = Unit
+ override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) = Unit
+ }
+ val db = openHelper.readableDatabase
+ tables.forEach { t -> db.addTable(t) }
+ return db
+}
+
+fun Table.toCreateString(): String =
+ columns.joinToString(
+ prefix = "CREATE TABLE $name (",
+ postfix = ");"
+ ) { "${it.name} ${it.type}" }
diff --git a/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/GetSchemaTest.kt b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/GetSchemaTest.kt
new file mode 100644
index 0000000..c5b6c2e
--- /dev/null
+++ b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/GetSchemaTest.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2020 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.sqlite.inspection.test
+
+import androidx.sqlite.inspection.test.MessageFactory.createGetSchemaCommand
+import androidx.sqlite.inspection.test.MessageFactory.createTrackDatabasesCommand
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@ExperimentalCoroutinesApi
+class GetSchemaTest {
+ @get:Rule
+ val testEnvironment = SqliteInspectorTestEnvironment()
+
+ @get:Rule
+ val temporaryFolder = TemporaryFolder()
+
+ @Test
+ fun test_get_schema_complex_tables() {
+ test_get_schema(
+ listOf(
+ Database(
+ "db1",
+ Table(
+ "table1",
+ Column("t", "TEXT"),
+ Column("nu", "NUMERIC"),
+ Column("i", "INTEGER"),
+ Column("r", "REAL"),
+ Column("b", "BLOB")
+ ),
+ Table(
+ "table2",
+ Column("id", "INTEGER"),
+ Column("name", "TEXT")
+
+ )
+ )
+ )
+ )
+ }
+
+ @Test
+ fun test_get_schema_multiple_databases() {
+ test_get_schema(
+ listOf(
+ Database("db3", Table("t3", Column("c3", "BLOB"))),
+ Database("db2", Table("t2", Column("c2", "TEXT"))),
+ Database("db1", Table("t1", Column("c1", "TEXT")))
+ )
+ )
+ }
+
+ private fun test_get_schema(alreadyOpenDatabases: List<Database>) = runBlocking {
+ assertThat(alreadyOpenDatabases).isNotEmpty() // sanity check
+
+ testEnvironment.registerAlreadyOpenDatabases(alreadyOpenDatabases.map {
+ it.createInstance(temporaryFolder)
+ })
+ testEnvironment.sendCommand(createTrackDatabasesCommand())
+ val databaseConnections =
+ alreadyOpenDatabases.indices.map { testEnvironment.receiveEvent().databaseOpened }
+
+ val schemas =
+ databaseConnections
+ .sortedBy { it.name }
+ .map {
+ testEnvironment.sendCommand(createGetSchemaCommand(it.databaseId)).getSchema
+ }
+
+ alreadyOpenDatabases
+ .sortedBy { it.name }
+ .zipSameSize(schemas)
+ .forEach { (expectedSchema, actualSchema) ->
+ val expectedTables = expectedSchema.tables.sortedBy { it.name }
+ val actualTables = actualSchema.tablesList.sortedBy { it.name }
+
+ expectedTables
+ .zipSameSize(actualTables)
+ .forEach { (expectedTable, actualTable) ->
+ assertThat(actualTable.name).isEqualTo(expectedTable.name)
+
+ val expectedColumns = expectedTable.columns.sortedBy { it.name }
+ val actualColumns = actualTable.columnsList.sortedBy { it.name }
+
+ expectedColumns
+ .zipSameSize(actualColumns)
+ .forEach { (expectedColumn, actualColumn) ->
+ assertThat(actualColumn.name).isEqualTo(expectedColumn.name)
+ assertThat(actualColumn.type).isEqualTo(expectedColumn.type)
+ }
+ }
+ }
+ }
+
+ /** Same as [List.zip] but ensures both lists are the same size. */
+ private fun <A, B> List<A>.zipSameSize(other: List<B>): List<Pair<A, B>> {
+ assertThat(this.size).isEqualTo(other.size)
+ return this.zip(other)
+ }
+}
diff --git a/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/Model.kt b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/Model.kt
new file mode 100644
index 0000000..fb9b5052
--- /dev/null
+++ b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/Model.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020 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.sqlite.inspection.test
+
+data class Database(val name: String, val tables: List<Table>) {
+ constructor(name: String, vararg tables: Table) : this(name, tables.toList())
+}
+
+data class Table(val name: String, val columns: List<Column>) {
+ constructor(name: String, vararg columns: Column) : this(name, columns.toList())
+}
+
+data class Column(val name: String, val type: String)
diff --git a/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/ProtoExtensions.kt b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/ProtoExtensions.kt
new file mode 100644
index 0000000..2b6c212
--- /dev/null
+++ b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/ProtoExtensions.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2020 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.sqlite.inspection.test
+
+import androidx.sqlite.inspection.SqliteInspectorProtocol
+import androidx.sqlite.inspection.SqliteInspectorProtocol.CellValue
+import androidx.sqlite.inspection.SqliteInspectorProtocol.CellValue.ValueCase
+
+val CellValue.value: Any? get() = valueType.first
+val CellValue.type: String get() = valueType.second
+val CellValue.valueType: Pair<Any?, String>
+ get() = when (valueCase) {
+ ValueCase.STRING_VALUE -> stringValue to "text"
+ ValueCase.INT_VALUE -> intValue to "integer"
+ ValueCase.FLOAT_VALUE -> floatValue to "float"
+ ValueCase.BLOB_VALUE -> blobValue.toByteArray().toTypedArray() to "blob"
+ ValueCase.VALUE_NOT_SET -> null to "null"
+ else -> throw IllegalArgumentException()
+ }
+
+object MessageFactory {
+ fun createTrackDatabasesCommand(): SqliteInspectorProtocol.Command =
+ SqliteInspectorProtocol.Command.newBuilder().setTrackDatabases(
+ SqliteInspectorProtocol.TrackDatabasesCommand.getDefaultInstance()
+ ).build()
+
+ fun createTrackDatabasesResponse(): SqliteInspectorProtocol.Response =
+ SqliteInspectorProtocol.Response.newBuilder().setTrackDatabases(
+ SqliteInspectorProtocol.TrackDatabasesResponse.getDefaultInstance()
+ ).build()
+
+ fun createGetSchemaCommand(databaseId: Int): SqliteInspectorProtocol.Command =
+ SqliteInspectorProtocol.Command.newBuilder().setGetSchema(
+ SqliteInspectorProtocol.GetSchemaCommand.newBuilder().setDatabaseId(databaseId).build()
+ ).build()
+
+ fun createQueryTableCommand(
+ databaseId: Int,
+ query: String
+ ): SqliteInspectorProtocol.Command =
+ SqliteInspectorProtocol.Command.newBuilder().setQuery(
+ SqliteInspectorProtocol.QueryCommand.newBuilder()
+ .setDatabaseId(databaseId)
+ .setQuery(query)
+ .build()
+ ).build()
+}
diff --git a/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/QueryTest.kt b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/QueryTest.kt
new file mode 100644
index 0000000..917e065
--- /dev/null
+++ b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/QueryTest.kt
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2020 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.sqlite.inspection.test
+
+import androidx.sqlite.inspection.SqliteInspectorProtocol
+import androidx.sqlite.inspection.test.MessageFactory.createQueryTableCommand
+import androidx.sqlite.inspection.test.MessageFactory.createTrackDatabasesCommand
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@ExperimentalCoroutinesApi
+// TODO: add tests for invalid queries: union of unequal number of columns, syntax error, etc.
+class QueryTest {
+ @get:Rule
+ val testEnvironment = SqliteInspectorTestEnvironment()
+
+ @get:Rule
+ val temporaryFolder = TemporaryFolder()
+
+ private val table1: Table = Table(
+ "table1",
+ Column("t", "TEXT"),
+ Column("nu", "NUMERIC"),
+ Column("i", "INTEGER"),
+ Column("r", "REAL"),
+ Column("b", "BLOB")
+ )
+
+ private val table2: Table = Table(
+ "table2",
+ Column("id", "INTEGER"),
+ Column("name", "TEXT")
+ )
+
+ private val database = Database("db1", table1, table2)
+
+ /** Query verifying type affinity behaviour */
+ @Test
+ fun test_valid_query_type_affinity_cases() {
+ val values = listOf(
+ table1 to repeat5("'abc'"),
+ table1 to repeat5("'500.0'"),
+ table1 to repeat5("500.0"),
+ table1 to repeat5("500"),
+ table1 to repeat5("x'0500'"),
+ table1 to repeat5("NULL"),
+
+ table2 to arrayOf("1", "'A'"),
+ table2 to arrayOf("2", "'B'"),
+ table2 to arrayOf("3", "'C'"),
+ table2 to arrayOf("4", "'D'")
+ )
+
+ val query = "select * from ${table1.name}"
+
+ val expectedValues = listOf(
+ repeat5("abc").toList(),
+ listOf("500.0", 500, 500, 500.0f, "500.0"), // text|integer|integer|float|text
+ listOf("500.0", 500, 500, 500.0f, 500.0f), // text|integer|integer|float|float
+ listOf("500", 500, 500, 500.0f, 500), // text|integer|integer|float|integer
+ listOf(*repeat5(arrayOf<Any?>(5.toByte(), 0.toByte()))), // blob|blob|blob|blob|blob
+ listOf(*repeat5<Any?>(null)) // null|null|null|null|null
+ )
+
+ val expectedTypes = listOf(
+ repeat5("text").toList(),
+ listOf("text", "integer", "integer", "float", "text"),
+ listOf("text", "integer", "integer", "float", "float"),
+ listOf("text", "integer", "integer", "float", "integer"),
+ listOf("blob", "blob", "blob", "blob", "blob"),
+ listOf("null", "null", "null", "null", "null")
+ )
+
+ val expectedColumnNames = table1.columns.map { it.name }
+
+ test_valid_query(
+ database,
+ values,
+ query,
+ expectedValues,
+ expectedTypes,
+ expectedColumnNames
+ )
+ }
+
+ /** Union of two queries (different column names) resulting in using first query columns. */
+ @Test
+ fun test_valid_query_two_table_union() {
+ val values = listOf(
+ table1 to repeat5("'abc'"),
+ table1 to repeat5("'xyz'"),
+ table2 to arrayOf("1", "'A'"),
+ table2 to arrayOf("2", "'B'")
+ )
+
+ // query construction
+ val columns1 = table1.columns.take(2).map { it.name }
+ val columns2 = table2.columns.take(2).map { it.name }
+ val column11 = columns1.first()
+ val column12 = columns1.last()
+ val column21 = columns2.first()
+ val column22 = columns2.last()
+ val query1 = "select $column11, $column12 from ${table1.name} where $column11 is 'abc'"
+ val query2 = "select $column21, $column22 from ${table2.name} where $column22 is 'B'"
+ val query = "$query1 union $query2"
+
+ val expectedValues = listOf(
+ listOf(2, "B"),
+ listOf("abc", "abc")
+ )
+
+ val expectedTypes = listOf(
+ listOf("integer", "text"),
+ listOf("text", "text")
+ )
+
+ test_valid_query(
+ database,
+ values,
+ query,
+ expectedValues,
+ expectedTypes,
+ expectedColumnNames = columns1
+ )
+ }
+
+ private fun test_valid_query(
+ database: Database,
+ values: List<Pair<Table, Array<String>>>,
+ query: String,
+ expectedValues: List<List<Any?>>,
+ expectedTypes: List<List<String>>,
+ expectedColumnNames: List<String>
+ ) = runBlocking {
+ // given
+ val databaseInstance = database.createInstance(temporaryFolder)
+ values.forEach { (table, values) -> databaseInstance.insertValues(table, *values) }
+
+ testEnvironment.registerAlreadyOpenDatabases(
+ listOf(
+ Database("ignored_1").createInstance(temporaryFolder),
+ databaseInstance,
+ Database("ignored_2").createInstance(temporaryFolder)
+ )
+ )
+ testEnvironment.sendCommand(createTrackDatabasesCommand())
+ val databaseId = testEnvironment.awaitDatabaseOpenedEvent(database.name).databaseId
+
+ // when
+ testEnvironment.sendCommand(createQueryTableCommand(databaseId, query)).let { response ->
+ // then
+ response.query.rowsList.let { actualRows: List<SqliteInspectorProtocol.Row> ->
+ actualRows.forEachIndexed { rowIx, row ->
+ row.valuesList.forEachIndexed { colIx, cell ->
+ assertThat(cell.value).isEqualTo(expectedValues[rowIx][colIx])
+ assertThat(cell.type).isEqualTo(expectedTypes[rowIx][colIx])
+ assertThat(cell.columnName).isEqualTo(expectedColumnNames[colIx])
+ }
+ }
+ }
+ }
+ }
+
+ private inline fun <reified T> repeatN(value: T, n: Int): Array<T> =
+ (0 until n).map { value }.toTypedArray()
+
+ private inline fun <reified T> repeat5(v: T) = repeatN(v, 5)
+}
diff --git a/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/SqliteInspectorTestEnvironment.kt b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/SqliteInspectorTestEnvironment.kt
new file mode 100644
index 0000000..5c4af60
--- /dev/null
+++ b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/SqliteInspectorTestEnvironment.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2020 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.sqlite.inspection.test
+
+import android.database.sqlite.SQLiteDatabase
+import androidx.inspection.InspectorEnvironment
+import androidx.inspection.testing.InspectorTester
+import androidx.sqlite.inspection.SqliteInspectorProtocol.Command
+import androidx.sqlite.inspection.SqliteInspectorProtocol.DatabaseOpenedEvent
+import androidx.sqlite.inspection.SqliteInspectorProtocol.Event
+import androidx.sqlite.inspection.SqliteInspectorProtocol.Response
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
+import org.junit.rules.ExternalResource
+
+private const val SQLITE_INSPECTOR_ID = "androidx.sqlite.inspection"
+
+class SqliteInspectorTestEnvironment : ExternalResource() {
+ private lateinit var inspectorTester: InspectorTester
+ private lateinit var environment: FakeInspectorEnvironment
+
+ override fun before() {
+ environment = FakeInspectorEnvironment()
+ inspectorTester = runBlocking { InspectorTester(SQLITE_INSPECTOR_ID, environment) }
+ }
+
+ override fun after() {
+ inspectorTester.dispose()
+ }
+
+ @ExperimentalCoroutinesApi
+ fun assertNoQueuedEvents() {
+ assertThat(inspectorTester.channel.isEmpty).isTrue()
+ }
+
+ suspend fun sendCommand(command: Command): Response {
+ inspectorTester.sendCommand(command.toByteArray())
+ .let { responseBytes ->
+ assertThat(responseBytes).isNotEmpty()
+ return Response.parseFrom(responseBytes)
+ }
+ }
+
+ suspend fun receiveEvent(): Event {
+ inspectorTester.channel.receive().let { responseBytes ->
+ assertThat(responseBytes).isNotEmpty()
+ return Event.parseFrom(responseBytes)
+ }
+ }
+
+ fun registerAlreadyOpenDatabases(databases: List<SQLiteDatabase>) {
+ environment.registerInstancesToFind(databases)
+ }
+
+ fun consumeRegisteredHooks(): List<Hook> =
+ environment.consumeRegisteredHooks()
+
+ /** Assumes an event with the relevant database will be fired. */
+ suspend fun awaitDatabaseOpenedEvent(databaseName: String): DatabaseOpenedEvent {
+ while (true) {
+ val event = receiveEvent().databaseOpened
+ if (event.name.endsWith("/$databaseName")) {
+ return event
+ }
+ }
+ }
+}
+
+/**
+ * Fake inspector environment with the following behaviour:
+ * - [findInstances] returns pre-registered values from [registerInstancesToFind].
+ * - [registerEntryHook] and [registerExitHook] record the calls which can later be
+ * retrieved in [consumeRegisteredHooks].
+ */
+private class FakeInspectorEnvironment : InspectorEnvironment {
+ private val instancesToFind = mutableListOf<Any>()
+ private val registeredHooks = mutableListOf<Hook>()
+
+ fun registerInstancesToFind(instances: List<Any>) {
+ instancesToFind.addAll(instances)
+ }
+
+ /**
+ * Returns instances pre-registered in [registerInstancesToFind].
+ * By design crashes in case of the wrong setup - indicating an issue with test code.
+ */
+ @Suppress("UNCHECKED_CAST")
+ // TODO: implement actual findInstances behaviour
+ override fun <T : Any?> findInstances(clazz: Class<T>): MutableList<T> =
+ instancesToFind.map { it as T }.toMutableList()
+
+ override fun registerEntryHook(
+ originClass: Class<*>,
+ originMethod: String,
+ entryHook: InspectorEnvironment.EntryHook
+ ) {
+ // TODO: implement actual registerEntryHook behaviour
+ registeredHooks.add(Hook.EntryHook(originClass, originMethod, entryHook))
+ }
+
+ override fun <T : Any?> registerExitHook(
+ originClass: Class<*>,
+ originMethod: String,
+ exitHook: InspectorEnvironment.ExitHook<T>
+ ) {
+ // TODO: implement actual registerExitHook behaviour
+ registeredHooks.add(Hook.ExitHook(originClass, originMethod, exitHook))
+ }
+
+ fun consumeRegisteredHooks(): List<Hook> =
+ registeredHooks.toList().also {
+ registeredHooks.clear()
+ }
+}
+
+sealed class Hook(val originClass: Class<*>, val originMethod: String) {
+ class ExitHook(
+ originClass: Class<*>,
+ originMethod: String,
+ val exitHook: InspectorEnvironment.ExitHook<*>
+ ) : Hook(originClass, originMethod)
+
+ class EntryHook(
+ originClass: Class<*>,
+ originMethod: String,
+ @Suppress("unused") val entryHook: InspectorEnvironment.EntryHook
+ ) : Hook(originClass, originMethod)
+}
diff --git a/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/TrackDatabasesTest.kt b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/TrackDatabasesTest.kt
new file mode 100644
index 0000000..560b76e
--- /dev/null
+++ b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/TrackDatabasesTest.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2020 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.sqlite.inspection.test
+
+import android.database.sqlite.SQLiteDatabase
+import androidx.inspection.InspectorEnvironment
+import androidx.sqlite.inspection.test.MessageFactory.createTrackDatabasesCommand
+import androidx.sqlite.inspection.test.MessageFactory.createTrackDatabasesResponse
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+
+private const val OPEN_DATABASE_COMMAND_SIGNATURE: String = "openDatabase" +
+ "(" +
+ "Ljava/io/File;" +
+ "Landroid/database/sqlite/SQLiteDatabase\$OpenParams;" +
+ ")" +
+ "Landroid/database/sqlite/SQLiteDatabase;"
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@ExperimentalCoroutinesApi
+class TrackDatabasesTest {
+ @get:Rule
+ val testEnvironment = SqliteInspectorTestEnvironment()
+
+ @get:Rule
+ val temporaryFolder = TemporaryFolder()
+
+ @Test
+ fun test_track_databases() = runBlocking {
+ val alreadyOpenDatabases = listOf(
+ Database("db1").createInstance(temporaryFolder),
+ Database("db2").createInstance(temporaryFolder)
+ )
+
+ testEnvironment.registerAlreadyOpenDatabases(alreadyOpenDatabases)
+
+ testEnvironment.sendCommand(createTrackDatabasesCommand()).let { response ->
+ assertThat(response).isEqualTo(createTrackDatabasesResponse())
+ }
+
+ // evaluate 'already-open' instances are found
+ alreadyOpenDatabases.let { expected ->
+ val actual = expected.indices.map { testEnvironment.receiveEvent().databaseOpened }
+ testEnvironment.assertNoQueuedEvents()
+ assertThat(actual.map { it.databaseId }.distinct()).hasSize(expected.size)
+ expected.forEachIndexed { ix, _ ->
+ assertThat(actual[ix].name).isEqualTo(expected[ix].path)
+ }
+ }
+
+ // evaluate registered hooks
+ val hookEntries = testEnvironment.consumeRegisteredHooks()
+ assertThat(hookEntries).hasSize(1)
+ hookEntries.first().let { entry ->
+ // expect one exit hook tracking database open events
+ assertThat(entry).isInstanceOf(Hook.ExitHook::class.java)
+ assertThat(entry.originClass.name).isEqualTo(SQLiteDatabase::class.java.name)
+ assertThat(entry.originMethod)
+ .isEqualTo(OPEN_DATABASE_COMMAND_SIGNATURE)
+
+ // verify that executing the registered hook will result in tracking events
+ testEnvironment.assertNoQueuedEvents()
+ @Suppress("UNCHECKED_CAST")
+ val exitHook = (entry as Hook.ExitHook).exitHook as
+ InspectorEnvironment.ExitHook<SQLiteDatabase>
+ val database = Database("db3").createInstance(temporaryFolder)
+ assertThat(exitHook.onExit(database)).isSameInstanceAs(database)
+ testEnvironment.receiveEvent().let { event ->
+ assertThat(event.databaseOpened.name).isEqualTo(database.path)
+ }
+ }
+
+ assertThat(testEnvironment.consumeRegisteredHooks()).isEmpty()
+ }
+}
diff --git a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqliteInspector.java b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqliteInspector.java
index 451c33f..86fd084 100644
--- a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqliteInspector.java
+++ b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqliteInspector.java
@@ -22,7 +22,6 @@
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
import androidx.inspection.Connection;
import androidx.inspection.Inspector;
import androidx.inspection.InspectorEnvironment;
@@ -60,8 +59,7 @@
*/
final class SqliteInspector extends Inspector {
// TODO: identify all SQLiteDatabase openDatabase methods
- @SuppressWarnings("WeakerAccess")
- @VisibleForTesting static final String sOpenDatabaseCommandSignature = "openDatabase"
+ private static final String sOpenDatabaseCommandSignature = "openDatabase"
+ "("
+ "Ljava/io/File;"
+ "Landroid/database/sqlite/SQLiteDatabase$OpenParams;"
diff --git a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqliteInspectorFactory.java b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqliteInspectorFactory.java
index 4e28dd9..6f37957 100644
--- a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqliteInspectorFactory.java
+++ b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqliteInspectorFactory.java
@@ -17,7 +17,6 @@
package androidx.sqlite.inspection;
import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
import androidx.inspection.Connection;
import androidx.inspection.InspectorEnvironment;
import androidx.inspection.InspectorFactory;
@@ -26,7 +25,7 @@
* Factory for SqliteInspector
*/
public final class SqliteInspectorFactory extends InspectorFactory<SqliteInspector> {
- @VisibleForTesting static final String SQLITE_INSPECTOR_ID = "androidx.sqlite.inspection";
+ private static final String SQLITE_INSPECTOR_ID = "androidx.sqlite.inspection";
public SqliteInspectorFactory() {
super(SQLITE_INSPECTOR_ID);
diff --git a/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteOpenHelper.java b/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteOpenHelper.java
index afe705f..f39b07c 100644
--- a/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteOpenHelper.java
+++ b/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteOpenHelper.java
@@ -358,7 +358,7 @@
Context mContext;
String mName;
SupportSQLiteOpenHelper.Callback mCallback;
- boolean mUseNoBackUpDirectory;
+ boolean mUseNoBackupDirectory;
/**
* <p>
@@ -381,12 +381,12 @@
throw new IllegalArgumentException("Must set a non-null context to create"
+ " the configuration.");
}
- if (mUseNoBackUpDirectory && TextUtils.isEmpty(mName)) {
+ if (mUseNoBackupDirectory && TextUtils.isEmpty(mName)) {
throw new IllegalArgumentException(
"Must set a non-null database name to a configuration that uses the "
+ "no backup directory.");
}
- return new Configuration(mContext, mName, mCallback, mUseNoBackUpDirectory);
+ return new Configuration(mContext, mName, mCallback, mUseNoBackupDirectory);
}
Builder(@NonNull Context context) {
@@ -415,13 +415,13 @@
/**
* Sets whether to use a no backup directory or not.
- * @param useNoBackUpDirectory If {@code true} the database file will be stored in the
+ * @param useNoBackupDirectory If {@code true} the database file will be stored in the
* no-backup directory.
* @return this
*/
@NonNull
- public Builder noBackupDirectory(boolean useNoBackUpDirectory) {
- mUseNoBackUpDirectory = useNoBackUpDirectory;
+ public Builder noBackupDirectory(boolean useNoBackupDirectory) {
+ mUseNoBackupDirectory = useNoBackupDirectory;
return this;
}
}
diff --git a/testutils/testutils-gradle-plugin/build.gradle b/testutils/testutils-gradle-plugin/build.gradle
new file mode 100644
index 0000000..43650cb
--- /dev/null
+++ b/testutils/testutils-gradle-plugin/build.gradle
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+
+plugins {
+ id("AndroidXPlugin")
+ id("kotlin")
+}
+
+dependencies {
+ implementation(KOTLIN_STDLIB)
+ implementation(ANDROIDX_TEST_EXT_JUNIT)
+ implementation(ANDROIDX_TEST_CORE)
+ implementation(ANDROIDX_TEST_RULES)
+}
+
+androidx {
+ toolingProject = true
+}
diff --git a/testutils/testutils-gradle-plugin/src/main/java/androidx/testutils/gradle/ProjectSetupRule.kt b/testutils/testutils-gradle-plugin/src/main/java/androidx/testutils/gradle/ProjectSetupRule.kt
new file mode 100644
index 0000000..d492dbb
--- /dev/null
+++ b/testutils/testutils-gradle-plugin/src/main/java/androidx/testutils/gradle/ProjectSetupRule.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2020 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.testutils.gradle
+
+import org.junit.rules.ExternalResource
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+import java.io.File
+import java.lang.IllegalStateException
+import java.util.Properties
+
+/**
+ * Test rule that helps to setup android project in tests that run gradle.
+ *
+ * It should be used along side with SdkResourceGenerator in your build.gradle file
+ */
+class ProjectSetupRule : ExternalResource() {
+ val testProjectDir = TemporaryFolder()
+
+ lateinit var props: ProjectProps
+
+ val rootDir: File
+ get() = testProjectDir.root
+
+ val buildFile: File
+ get() = File(rootDir, "build.gradle")
+
+ val gradlePropertiesFile: File
+ get() = File(rootDir, "gradle.properties")
+
+ private val repositories: String
+ get() = """
+ repositories {
+ maven { url "${props.prebuiltsRoot}/androidx/external" }
+ maven { url "${props.prebuiltsRoot}/androidx/internal" }
+ }
+ """.trimIndent()
+
+ val androidProject: String
+ get() = """
+ android {
+ compileSdkVersion ${props.compileSdkVersion}
+ buildToolsVersion "${props.buildToolsVersion}"
+
+ defaultConfig {
+ minSdkVersion ${props.minSdkVersion}
+ }
+
+ signingConfigs {
+ debug {
+ storeFile file("${props.debugKeystore}")
+ }
+ }
+ }
+ """.trimIndent()
+
+ private val defaultBuildGradle: String
+ get() = "\n$repositories\n\n$androidProject\n\n"
+
+ fun writeDefaultBuildGradle(prefix: String, suffix: String) {
+ buildFile.writeText(prefix)
+ buildFile.appendText(defaultBuildGradle)
+ buildFile.appendText(suffix)
+
+ println(buildFile.readText())
+ }
+
+ override fun apply(base: Statement, description: Description): Statement {
+ return testProjectDir.apply(super.apply(base, description), description)
+ }
+
+ override fun before() {
+ props = ProjectProps.load()
+ buildFile.createNewFile()
+ copyLocalProperties()
+ writeGradleProperties()
+ }
+
+ private fun copyLocalProperties() {
+ val localProperties = File(props.rootProjectPath, "local.properties")
+ if (localProperties.exists()) {
+ localProperties.copyTo(File(rootDir, "local.properties"), overwrite = true)
+ } else {
+ throw IllegalStateException("local.properties doesn't exist at: $localProperties")
+ }
+ }
+
+ private fun writeGradleProperties() {
+ gradlePropertiesFile.writer().use {
+ val props = Properties()
+ props.setProperty("android.useAndroidX", "true")
+ props.store(it, null)
+ }
+ }
+}
+
+data class ProjectProps(
+ val prebuiltsRoot: String,
+ val compileSdkVersion: String,
+ val buildToolsVersion: String,
+ val minSdkVersion: String,
+ val debugKeystore: String,
+ var navigationCommon: String,
+ val kotlinStblib: String,
+ val rootProjectPath: String,
+ val localSupportRepo: String,
+ val agpDependency: String
+) {
+ companion object {
+ fun load(): ProjectProps {
+ val stream = ProjectSetupRule::class.java.classLoader.getResourceAsStream("sdk.prop")
+ val properties = Properties()
+ properties.load(stream)
+ return ProjectProps(
+ prebuiltsRoot = properties.getProperty("prebuiltsRoot"),
+ compileSdkVersion = properties.getProperty("compileSdkVersion"),
+ buildToolsVersion = properties.getProperty("buildToolsVersion"),
+ minSdkVersion = properties.getProperty("minSdkVersion"),
+ debugKeystore = properties.getProperty("debugKeystore"),
+ navigationCommon = properties.getProperty("navigationCommon"),
+ kotlinStblib = properties.getProperty("kotlinStdlib"),
+ rootProjectPath = properties.getProperty("rootProjectPath"),
+ localSupportRepo = properties.getProperty("localSupportRepo"),
+ agpDependency = properties.getProperty("agpDependency")
+ )
+ }
+ }
+}
diff --git a/ui/integration-tests/test/src/androidTest/java/androidx/ui/integration/test/VectorAssetTest.kt b/ui/integration-tests/test/src/androidTest/java/androidx/ui/integration/test/VectorAssetTest.kt
index 600acd7..db585d6 100644
--- a/ui/integration-tests/test/src/androidTest/java/androidx/ui/integration/test/VectorAssetTest.kt
+++ b/ui/integration-tests/test/src/androidTest/java/androidx/ui/integration/test/VectorAssetTest.kt
@@ -16,7 +16,9 @@
package androidx.ui.integration.test
+import android.os.Build
import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
import androidx.ui.layout.Column
import androidx.ui.test.captureToBitmap
import androidx.ui.integration.test.framework.ProgrammaticVectorTestCase
@@ -35,6 +37,7 @@
* output when ran. This ensures correctness for the corresponding benchmarks.
*/
@LargeTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@RunWith(JUnit4::class)
class VectorAssetTest {
@get:Rule
diff --git a/ui/integration-tests/test/src/main/java/androidx/ui/integration/test/framework/VectorAssetTestCase.kt b/ui/integration-tests/test/src/main/java/androidx/ui/integration/test/framework/VectorAssetTestCase.kt
index 3ab13ab..dda850b 100644
--- a/ui/integration-tests/test/src/main/java/androidx/ui/integration/test/framework/VectorAssetTestCase.kt
+++ b/ui/integration-tests/test/src/main/java/androidx/ui/integration/test/framework/VectorAssetTestCase.kt
@@ -19,7 +19,6 @@
import androidx.compose.Composable
import androidx.ui.core.TestTag
import androidx.ui.core.dp
-import androidx.ui.core.px
import androidx.ui.graphics.Color
import androidx.ui.graphics.SolidColor
import androidx.ui.graphics.StrokeCap
@@ -82,8 +81,8 @@
*/
@Composable
override fun getVectorAsset() = VectorAssetBuilder(
- defaultWidth = 84.px,
- defaultHeight = 84.px,
+ defaultWidth = 24.dp,
+ defaultHeight = 24.dp,
viewportWidth = 24f,
viewportHeight = 24f
).apply {
diff --git a/ui/ui-android-view-non-ir/src/main/java/androidx/ui/androidview/adapters/ViewAttributeAdapter.kt b/ui/ui-android-view-non-ir/src/main/java/androidx/ui/androidview/adapters/ViewAttributeAdapter.kt
index 8f671fd..1b77435 100644
--- a/ui/ui-android-view-non-ir/src/main/java/androidx/ui/androidview/adapters/ViewAttributeAdapter.kt
+++ b/ui/ui-android-view-non-ir/src/main/java/androidx/ui/androidview/adapters/ViewAttributeAdapter.kt
@@ -18,9 +18,8 @@
package androidx.ui.androidview.adapters
-import android.annotation.SuppressLint
-import androidx.annotation.DimenRes
import android.view.View
+import androidx.annotation.DimenRes
import androidx.ui.androidview.annotations.ConflictsWith
// NOTE: these attributes are added to every view/component so that we can have a "key" attribute
@@ -146,7 +145,6 @@
fun View.setScrollY(scrollY: Dimension) = setScrollY(scrollY.toIntPixels(metrics))
fun View.setTop(top: Dimension) = setTop(top.toIntPixels(metrics))
-@SuppressLint("UnnecessaryLambdaCreation")
// TODO: Necessary because the IR doesn't support SAM conversion yet
fun View.setOnClick(lambda: () -> Unit) { this.setOnClickListener { lambda() } }
diff --git a/ui/ui-core/api/0.1.0-dev04.txt b/ui/ui-core/api/0.1.0-dev04.txt
index 736a077..6cad729 100644
--- a/ui/ui-core/api/0.1.0-dev04.txt
+++ b/ui/ui-core/api/0.1.0-dev04.txt
@@ -524,7 +524,7 @@
enum_constant public static final androidx.ui.core.LayoutDirection Rtl;
}
- public interface LayoutModifier extends androidx.ui.core.ParentDataModifier {
+ public interface LayoutModifier extends androidx.ui.core.Modifier.Element {
method public default androidx.ui.core.IntPx maxIntrinsicHeightOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx width);
method public default androidx.ui.core.IntPx maxIntrinsicWidthOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx height);
method public default androidx.ui.core.IntPx minIntrinsicHeightOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx width);
diff --git a/ui/ui-core/api/current.txt b/ui/ui-core/api/current.txt
index 736a077..6cad729 100644
--- a/ui/ui-core/api/current.txt
+++ b/ui/ui-core/api/current.txt
@@ -524,7 +524,7 @@
enum_constant public static final androidx.ui.core.LayoutDirection Rtl;
}
- public interface LayoutModifier extends androidx.ui.core.ParentDataModifier {
+ public interface LayoutModifier extends androidx.ui.core.Modifier.Element {
method public default androidx.ui.core.IntPx maxIntrinsicHeightOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx width);
method public default androidx.ui.core.IntPx maxIntrinsicWidthOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx height);
method public default androidx.ui.core.IntPx minIntrinsicHeightOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx width);
diff --git a/ui/ui-core/api/public_plus_experimental_0.1.0-dev04.txt b/ui/ui-core/api/public_plus_experimental_0.1.0-dev04.txt
index 736a077..6cad729 100644
--- a/ui/ui-core/api/public_plus_experimental_0.1.0-dev04.txt
+++ b/ui/ui-core/api/public_plus_experimental_0.1.0-dev04.txt
@@ -524,7 +524,7 @@
enum_constant public static final androidx.ui.core.LayoutDirection Rtl;
}
- public interface LayoutModifier extends androidx.ui.core.ParentDataModifier {
+ public interface LayoutModifier extends androidx.ui.core.Modifier.Element {
method public default androidx.ui.core.IntPx maxIntrinsicHeightOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx width);
method public default androidx.ui.core.IntPx maxIntrinsicWidthOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx height);
method public default androidx.ui.core.IntPx minIntrinsicHeightOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx width);
diff --git a/ui/ui-core/api/public_plus_experimental_current.txt b/ui/ui-core/api/public_plus_experimental_current.txt
index 736a077..6cad729 100644
--- a/ui/ui-core/api/public_plus_experimental_current.txt
+++ b/ui/ui-core/api/public_plus_experimental_current.txt
@@ -524,7 +524,7 @@
enum_constant public static final androidx.ui.core.LayoutDirection Rtl;
}
- public interface LayoutModifier extends androidx.ui.core.ParentDataModifier {
+ public interface LayoutModifier extends androidx.ui.core.Modifier.Element {
method public default androidx.ui.core.IntPx maxIntrinsicHeightOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx width);
method public default androidx.ui.core.IntPx maxIntrinsicWidthOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx height);
method public default androidx.ui.core.IntPx minIntrinsicHeightOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx width);
diff --git a/ui/ui-core/api/restricted_0.1.0-dev04.txt b/ui/ui-core/api/restricted_0.1.0-dev04.txt
index 736a077..6cad729 100644
--- a/ui/ui-core/api/restricted_0.1.0-dev04.txt
+++ b/ui/ui-core/api/restricted_0.1.0-dev04.txt
@@ -524,7 +524,7 @@
enum_constant public static final androidx.ui.core.LayoutDirection Rtl;
}
- public interface LayoutModifier extends androidx.ui.core.ParentDataModifier {
+ public interface LayoutModifier extends androidx.ui.core.Modifier.Element {
method public default androidx.ui.core.IntPx maxIntrinsicHeightOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx width);
method public default androidx.ui.core.IntPx maxIntrinsicWidthOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx height);
method public default androidx.ui.core.IntPx minIntrinsicHeightOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx width);
diff --git a/ui/ui-core/api/restricted_current.txt b/ui/ui-core/api/restricted_current.txt
index 736a077..6cad729 100644
--- a/ui/ui-core/api/restricted_current.txt
+++ b/ui/ui-core/api/restricted_current.txt
@@ -524,7 +524,7 @@
enum_constant public static final androidx.ui.core.LayoutDirection Rtl;
}
- public interface LayoutModifier extends androidx.ui.core.ParentDataModifier {
+ public interface LayoutModifier extends androidx.ui.core.Modifier.Element {
method public default androidx.ui.core.IntPx maxIntrinsicHeightOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx width);
method public default androidx.ui.core.IntPx maxIntrinsicWidthOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx height);
method public default androidx.ui.core.IntPx minIntrinsicHeightOf(androidx.ui.core.DensityScope, androidx.ui.core.Measurable measurable, androidx.ui.core.IntPx width);
diff --git a/ui/ui-core/src/main/java/androidx/ui/core/LayoutModifier.kt b/ui/ui-core/src/main/java/androidx/ui/core/LayoutModifier.kt
index 33fef24..0522f21 100644
--- a/ui/ui-core/src/main/java/androidx/ui/core/LayoutModifier.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/core/LayoutModifier.kt
@@ -19,7 +19,7 @@
/**
* A [Modifier.Element] that changes the way a UI component is measured and laid out.
*/
-interface LayoutModifier : ParentDataModifier {
+interface LayoutModifier : Modifier.Element {
/**
* Modifies [constraints] for performing measurement of the modified layout element.
*/
diff --git a/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/ScrollerTest.kt b/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/ScrollerTest.kt
index 74e8e03..d3acedf 100644
--- a/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/ScrollerTest.kt
+++ b/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/ScrollerTest.kt
@@ -15,29 +15,22 @@
*/
package androidx.ui.foundation
-import android.graphics.Bitmap
import android.os.Handler
import android.os.Looper
-import android.view.PixelCopy
-import android.view.View
-import android.view.ViewGroup
-import android.view.ViewTreeObserver
import androidx.annotation.RequiresApi
import androidx.compose.Composable
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import androidx.ui.core.Alignment
-import androidx.ui.core.AndroidComposeView
import androidx.ui.core.Dp
import androidx.ui.core.Draw
import androidx.ui.core.IntPx
-import androidx.ui.core.Px
+import androidx.ui.core.IntPxSize
import androidx.ui.core.TestTag
import androidx.ui.core.Text
import androidx.ui.core.dp
import androidx.ui.core.ipx
import androidx.ui.core.px
-import androidx.ui.core.setContent
import androidx.ui.core.toPx
import androidx.ui.core.toRect
import androidx.ui.core.withDensity
@@ -46,7 +39,6 @@
import androidx.ui.graphics.Color
import androidx.ui.graphics.Paint
import androidx.ui.graphics.PaintingStyle
-import androidx.ui.graphics.toArgb
import androidx.ui.layout.Align
import androidx.ui.layout.Column
import androidx.ui.layout.Container
@@ -55,9 +47,10 @@
import androidx.ui.semantics.Semantics
import androidx.ui.test.GestureScope
import androidx.ui.test.SemanticsNodeInteraction
-import androidx.ui.test.android.AndroidComposeTestRule
import androidx.ui.test.assertIsDisplayed
import androidx.ui.test.assertIsNotDisplayed
+import androidx.ui.test.assertPixels
+import androidx.ui.test.captureToBitmap
import androidx.ui.test.createComposeRule
import androidx.ui.test.doGesture
import androidx.ui.test.doScrollTo
@@ -70,13 +63,11 @@
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
-import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
@SmallTest
@RunWith(JUnit4::class)
@@ -85,10 +76,7 @@
@get:Rule
val composeTestRule = createComposeRule()
- // TODO(malkov/pavlis) : some tests here require activity access as we need
- // to take screen's bitmap, abstract it better
- private val activity
- get() = (composeTestRule as AndroidComposeTestRule).activityTestRule.activity
+ private val scrollerTag = "ScrollerTest"
private val defaultCrossAxisSize = 45.ipx
private val defaultMainAxisSize = 40.ipx
@@ -105,17 +93,6 @@
Color(red = 0xA5, green = 0, blue = 0xFF, alpha = 0xFF)
)
- private var drawLatch = CountDownLatch(1)
- private lateinit var handler: Handler
-
- @Before
- fun setupDrawLatch() {
- drawLatch = CountDownLatch(1)
- composeTestRule.runOnUiThread {
- handler = Handler()
- }
- }
-
@SdkSuppress(minSdkVersion = 26)
@Test
fun verticalScroller_SmallContent() {
@@ -276,31 +253,27 @@
val scrollerPosition = ScrollerPosition()
createScrollableContent(isVertical, scrollerPosition = scrollerPosition)
- assertThat(scrollerPosition.getValueOnUiThread()).isEqualTo(0.px)
- findByTag("scroller")
+ composeTestRule.runOnIdleCompose {
+ assertThat(scrollerPosition.value).isEqualTo(0.px)
+ }
+
+ findByTag(scrollerTag)
.doGesture { firstSwipe() }
.awaitScrollAnimation(scrollerPosition)
- val scrolledValue = scrollerPosition.getValueOnUiThread()
+ val scrolledValue = composeTestRule.runOnIdleCompose {
+ scrollerPosition.value
+ }
assertThat(scrolledValue).isGreaterThan(0.px)
- findByTag("scroller")
+ findByTag(scrollerTag)
.doGesture { secondSwipe() }
.awaitScrollAnimation(scrollerPosition)
- assertThat(scrollerPosition.getValueOnUiThread()).isLessThan(scrolledValue)
- }
-
- private fun ScrollerPosition.getValueOnUiThread(): Px {
- var value = 0.px
- val latch = CountDownLatch(1)
- composeTestRule.runOnUiThread {
- value = this.value
- latch.countDown()
+ composeTestRule.runOnIdleCompose {
+ assertThat(scrollerPosition.value).isLessThan(scrolledValue)
}
- latch.await()
- return value
}
private fun composeVerticalScroller(
@@ -311,9 +284,9 @@
) {
// We assume that the height of the device is more than 45 px
withDensity(composeTestRule.density) {
- composeTestRule.runOnUiThread {
- activity.setContent {
- Align(alignment = Alignment.TopLeft) {
+ composeTestRule.setContent {
+ Align(alignment = Alignment.TopLeft) {
+ TestTag(scrollerTag) {
VerticalScroller(
scrollerPosition = scrollerPosition,
modifier = LayoutSize(width.toDp(), height.toDp())
@@ -334,9 +307,6 @@
}
}
}
- Draw { _, _ ->
- drawLatch.countDown()
- }
}
}
}
@@ -351,9 +321,9 @@
) {
// We assume that the height of the device is more than 45 px
withDensity(composeTestRule.density) {
- composeTestRule.runOnUiThread {
- activity.setContent {
- Align(alignment = Alignment.TopLeft) {
+ composeTestRule.setContent {
+ Align(alignment = Alignment.TopLeft) {
+ TestTag(scrollerTag) {
HorizontalScroller(
scrollerPosition = scrollerPosition,
modifier = LayoutSize(width.toDp(), height.toDp())
@@ -374,9 +344,6 @@
}
}
}
- Draw { _, _ ->
- drawLatch.countDown()
- }
}
}
}
@@ -390,23 +357,12 @@
height: IntPx = 40.ipx,
rowHeight: IntPx = 5.ipx
) {
- assertTrue(drawLatch.await(1, TimeUnit.SECONDS))
-
- val bitmap = waitAndScreenShot()
- assertTrue(bitmap.height >= height.value)
- assertTrue(bitmap.width >= width.value)
- for (y in 0 until height.value) {
- val colorIndex = (offset.value + y) / rowHeight.value
- val expectedColor = colors[colorIndex]
-
- for (x in 0 until width.value) {
- val pixel = bitmap.getPixel(x, y)
- assertEquals(
- "Expected $expectedColor, but got ${Color(pixel)} at $x, $y",
- expectedColor.toArgb(), pixel
- )
+ findByTag(scrollerTag)
+ .captureToBitmap()
+ .assertPixels(expectedSize = IntPxSize(width, height)) { pos ->
+ val colorIndex = (offset.value + pos.y.value) / rowHeight.value
+ colors[colorIndex]
}
- }
}
@RequiresApi(api = 26)
@@ -416,23 +372,12 @@
height: IntPx = 45.ipx,
columnWidth: IntPx = 5.ipx
) {
- assertTrue(drawLatch.await(1, TimeUnit.SECONDS))
-
- val bitmap = waitAndScreenShot()
- assertTrue(bitmap.height >= height.value)
- assertTrue(bitmap.width >= width.value)
- for (x in 0 until width.value) {
- val colorIndex = (offset.value + x) / columnWidth.value
- val expectedColor = colors[colorIndex]
-
- for (y in 0 until height.value) {
- val pixel = bitmap.getPixel(x, y)
- assertEquals(
- "Expected $expectedColor, but got ${Color(pixel)} at $x, $y",
- expectedColor.toArgb(), pixel
- )
+ findByTag(scrollerTag)
+ .captureToBitmap()
+ .assertPixels(expectedSize = IntPxSize(width, height)) { pos ->
+ val colorIndex = (offset.value + pos.x.value) / columnWidth.value
+ colors[colorIndex]
}
- }
}
private fun createScrollableContent(
@@ -451,55 +396,29 @@
Align(alignment = Alignment.TopLeft) {
Container(width = width, height = height) {
DrawShape(RectangleShape, Color.White)
- TestTag("scroller") {
- Semantics {
- if (isVertical) {
- VerticalScroller(scrollerPosition) {
- Column {
- content()
+ TestTag(scrollerTag) {
+ Semantics {
+ if (isVertical) {
+ VerticalScroller(scrollerPosition) {
+ Column {
+ content()
+ }
}
- }
- } else {
- HorizontalScroller(scrollerPosition) {
- Row {
- content()
+ } else {
+ HorizontalScroller(scrollerPosition) {
+ Row {
+ content()
+ }
}
}
}
}
- }
}
}
}
}
- @RequiresApi(api = 26) // For PixelCopy.request(Window, Rect, Bitmap, listener, Handler)
- private fun waitAndScreenShot(): Bitmap {
- val view = findAndroidComposeView()
- waitForDraw(view)
-
- val offset = intArrayOf(0, 0)
- val width = view.width
- val height = view.height
-
- val dest =
- Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
- val srcRect = android.graphics.Rect(0, 0, width, height)
- srcRect.offset(offset[0], offset[1])
- val latch = CountDownLatch(1)
- var copyResult = 0
- val onCopyFinished = object : PixelCopy.OnPixelCopyFinishedListener {
- override fun onPixelCopyFinished(result: Int) {
- copyResult = result
- latch.countDown()
- }
- }
- PixelCopy.request(activity.window, srcRect, dest, onCopyFinished, handler)
- assertTrue(latch.await(1, TimeUnit.SECONDS))
- assertEquals(PixelCopy.SUCCESS, copyResult)
- return dest
- }
-
+ // TODO(b/147291885): This should not be needed in the future.
private fun SemanticsNodeInteraction.awaitScrollAnimation(
scroller: ScrollerPosition
): SemanticsNodeInteraction {
@@ -520,42 +439,4 @@
latch.await()
return this
}
-
- // TODO(malkov): ALL below is copypaste from LayoutTest as this test in ui-foundation now
-
- private fun findAndroidComposeView(): AndroidComposeView {
- val contentViewGroup = activity.findViewById<ViewGroup>(android.R.id.content)
- return findAndroidComposeView(contentViewGroup)!!
- }
-
- private fun findAndroidComposeView(parent: ViewGroup): AndroidComposeView? {
- for (index in 0 until parent.childCount) {
- val child = parent.getChildAt(index)
- if (child is AndroidComposeView) {
- return child
- } else if (child is ViewGroup) {
- val composeView = findAndroidComposeView(child)
- if (composeView != null) {
- return composeView
- }
- }
- }
- return null
- }
-
- private fun waitForDraw(view: View) {
- val viewDrawLatch = CountDownLatch(1)
- val listener = object : ViewTreeObserver.OnDrawListener {
- override fun onDraw() {
- viewDrawLatch.countDown()
- }
- }
- view.post(object : Runnable {
- override fun run() {
- view.viewTreeObserver.addOnDrawListener(listener)
- view.invalidate()
- }
- })
- assertTrue(viewDrawLatch.await(1, TimeUnit.SECONDS))
- }
}
diff --git a/ui/ui-framework/api/0.1.0-dev04.txt b/ui/ui-framework/api/0.1.0-dev04.txt
index 2086670..d14369a 100644
--- a/ui/ui-framework/api/0.1.0-dev04.txt
+++ b/ui/ui-framework/api/0.1.0-dev04.txt
@@ -394,8 +394,15 @@
package androidx.ui.graphics.vector {
public final class VectorAsset {
- method public androidx.ui.core.Px getDefaultHeight();
- method public androidx.ui.core.Px getDefaultWidth();
+ method public String component1();
+ method public androidx.ui.core.Dp component2();
+ method public androidx.ui.core.Dp component3();
+ method public float component4();
+ method public float component5();
+ method public androidx.ui.graphics.vector.VectorGroup component6();
+ method public androidx.ui.graphics.vector.VectorAsset copy(String name, androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth, float viewportHeight, androidx.ui.graphics.vector.VectorGroup root);
+ method public androidx.ui.core.Dp getDefaultHeight();
+ method public androidx.ui.core.Dp getDefaultWidth();
method public String getName();
method public androidx.ui.graphics.vector.VectorGroup getRoot();
method public float getViewportHeight();
@@ -403,12 +410,12 @@
}
public final class VectorAssetBuilder {
- ctor public VectorAssetBuilder(String name, androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth, float viewportHeight);
+ ctor public VectorAssetBuilder(String name, androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth, float viewportHeight);
method public androidx.ui.graphics.vector.VectorAssetBuilder addPath(java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
method public androidx.ui.graphics.vector.VectorAsset build();
method public void ensureNotConsumed();
- method public androidx.ui.core.Px getDefaultHeight();
- method public androidx.ui.core.Px getDefaultWidth();
+ method public androidx.ui.core.Dp getDefaultHeight();
+ method public androidx.ui.core.Dp getDefaultWidth();
method public String getName();
method public float getViewportHeight();
method public float getViewportWidth();
@@ -430,6 +437,16 @@
public final class VectorGroup extends androidx.ui.graphics.vector.VectorNode implements java.lang.Iterable<androidx.ui.graphics.vector.VectorNode> kotlin.jvm.internal.markers.KMappedMarker {
ctor public VectorGroup(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData);
ctor public VectorGroup();
+ method public String component1();
+ method public float component2();
+ method public float component3();
+ method public float component4();
+ method public float component5();
+ method public float component6();
+ method public float component7();
+ method public float component8();
+ method public java.util.List<androidx.ui.graphics.vector.PathNode> component9();
+ method public androidx.ui.graphics.vector.VectorGroup copy(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData);
method public operator androidx.ui.graphics.vector.VectorNode get(int index);
method public java.util.List<androidx.ui.graphics.vector.PathNode> getClipPathData();
method public String getName();
@@ -450,6 +467,17 @@
public final class VectorPath extends androidx.ui.graphics.vector.VectorNode {
ctor public VectorPath(String name, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, androidx.ui.graphics.Brush? fill, float fillAlpha, androidx.ui.graphics.Brush? stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.graphics.StrokeCap strokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin, float strokeLineMiter);
+ method public String component1();
+ method public float component10();
+ method public java.util.List<androidx.ui.graphics.vector.PathNode> component2();
+ method public androidx.ui.graphics.Brush? component3();
+ method public float component4();
+ method public androidx.ui.graphics.Brush? component5();
+ method public float component6();
+ method public float component7();
+ method public androidx.ui.graphics.StrokeCap component8();
+ method public androidx.ui.graphics.StrokeJoin component9();
+ method public androidx.ui.graphics.vector.VectorPath copy(String name, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, androidx.ui.graphics.Brush? fill, float fillAlpha, androidx.ui.graphics.Brush? stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.graphics.StrokeCap strokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin, float strokeLineMiter);
method public androidx.ui.graphics.Brush? getFill();
method public float getFillAlpha();
method public String getName();
diff --git a/ui/ui-framework/api/current.txt b/ui/ui-framework/api/current.txt
index 2086670..d14369a 100644
--- a/ui/ui-framework/api/current.txt
+++ b/ui/ui-framework/api/current.txt
@@ -394,8 +394,15 @@
package androidx.ui.graphics.vector {
public final class VectorAsset {
- method public androidx.ui.core.Px getDefaultHeight();
- method public androidx.ui.core.Px getDefaultWidth();
+ method public String component1();
+ method public androidx.ui.core.Dp component2();
+ method public androidx.ui.core.Dp component3();
+ method public float component4();
+ method public float component5();
+ method public androidx.ui.graphics.vector.VectorGroup component6();
+ method public androidx.ui.graphics.vector.VectorAsset copy(String name, androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth, float viewportHeight, androidx.ui.graphics.vector.VectorGroup root);
+ method public androidx.ui.core.Dp getDefaultHeight();
+ method public androidx.ui.core.Dp getDefaultWidth();
method public String getName();
method public androidx.ui.graphics.vector.VectorGroup getRoot();
method public float getViewportHeight();
@@ -403,12 +410,12 @@
}
public final class VectorAssetBuilder {
- ctor public VectorAssetBuilder(String name, androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth, float viewportHeight);
+ ctor public VectorAssetBuilder(String name, androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth, float viewportHeight);
method public androidx.ui.graphics.vector.VectorAssetBuilder addPath(java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
method public androidx.ui.graphics.vector.VectorAsset build();
method public void ensureNotConsumed();
- method public androidx.ui.core.Px getDefaultHeight();
- method public androidx.ui.core.Px getDefaultWidth();
+ method public androidx.ui.core.Dp getDefaultHeight();
+ method public androidx.ui.core.Dp getDefaultWidth();
method public String getName();
method public float getViewportHeight();
method public float getViewportWidth();
@@ -430,6 +437,16 @@
public final class VectorGroup extends androidx.ui.graphics.vector.VectorNode implements java.lang.Iterable<androidx.ui.graphics.vector.VectorNode> kotlin.jvm.internal.markers.KMappedMarker {
ctor public VectorGroup(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData);
ctor public VectorGroup();
+ method public String component1();
+ method public float component2();
+ method public float component3();
+ method public float component4();
+ method public float component5();
+ method public float component6();
+ method public float component7();
+ method public float component8();
+ method public java.util.List<androidx.ui.graphics.vector.PathNode> component9();
+ method public androidx.ui.graphics.vector.VectorGroup copy(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData);
method public operator androidx.ui.graphics.vector.VectorNode get(int index);
method public java.util.List<androidx.ui.graphics.vector.PathNode> getClipPathData();
method public String getName();
@@ -450,6 +467,17 @@
public final class VectorPath extends androidx.ui.graphics.vector.VectorNode {
ctor public VectorPath(String name, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, androidx.ui.graphics.Brush? fill, float fillAlpha, androidx.ui.graphics.Brush? stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.graphics.StrokeCap strokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin, float strokeLineMiter);
+ method public String component1();
+ method public float component10();
+ method public java.util.List<androidx.ui.graphics.vector.PathNode> component2();
+ method public androidx.ui.graphics.Brush? component3();
+ method public float component4();
+ method public androidx.ui.graphics.Brush? component5();
+ method public float component6();
+ method public float component7();
+ method public androidx.ui.graphics.StrokeCap component8();
+ method public androidx.ui.graphics.StrokeJoin component9();
+ method public androidx.ui.graphics.vector.VectorPath copy(String name, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, androidx.ui.graphics.Brush? fill, float fillAlpha, androidx.ui.graphics.Brush? stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.graphics.StrokeCap strokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin, float strokeLineMiter);
method public androidx.ui.graphics.Brush? getFill();
method public float getFillAlpha();
method public String getName();
diff --git a/ui/ui-framework/api/public_plus_experimental_0.1.0-dev04.txt b/ui/ui-framework/api/public_plus_experimental_0.1.0-dev04.txt
index 2086670..d14369a 100644
--- a/ui/ui-framework/api/public_plus_experimental_0.1.0-dev04.txt
+++ b/ui/ui-framework/api/public_plus_experimental_0.1.0-dev04.txt
@@ -394,8 +394,15 @@
package androidx.ui.graphics.vector {
public final class VectorAsset {
- method public androidx.ui.core.Px getDefaultHeight();
- method public androidx.ui.core.Px getDefaultWidth();
+ method public String component1();
+ method public androidx.ui.core.Dp component2();
+ method public androidx.ui.core.Dp component3();
+ method public float component4();
+ method public float component5();
+ method public androidx.ui.graphics.vector.VectorGroup component6();
+ method public androidx.ui.graphics.vector.VectorAsset copy(String name, androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth, float viewportHeight, androidx.ui.graphics.vector.VectorGroup root);
+ method public androidx.ui.core.Dp getDefaultHeight();
+ method public androidx.ui.core.Dp getDefaultWidth();
method public String getName();
method public androidx.ui.graphics.vector.VectorGroup getRoot();
method public float getViewportHeight();
@@ -403,12 +410,12 @@
}
public final class VectorAssetBuilder {
- ctor public VectorAssetBuilder(String name, androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth, float viewportHeight);
+ ctor public VectorAssetBuilder(String name, androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth, float viewportHeight);
method public androidx.ui.graphics.vector.VectorAssetBuilder addPath(java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
method public androidx.ui.graphics.vector.VectorAsset build();
method public void ensureNotConsumed();
- method public androidx.ui.core.Px getDefaultHeight();
- method public androidx.ui.core.Px getDefaultWidth();
+ method public androidx.ui.core.Dp getDefaultHeight();
+ method public androidx.ui.core.Dp getDefaultWidth();
method public String getName();
method public float getViewportHeight();
method public float getViewportWidth();
@@ -430,6 +437,16 @@
public final class VectorGroup extends androidx.ui.graphics.vector.VectorNode implements java.lang.Iterable<androidx.ui.graphics.vector.VectorNode> kotlin.jvm.internal.markers.KMappedMarker {
ctor public VectorGroup(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData);
ctor public VectorGroup();
+ method public String component1();
+ method public float component2();
+ method public float component3();
+ method public float component4();
+ method public float component5();
+ method public float component6();
+ method public float component7();
+ method public float component8();
+ method public java.util.List<androidx.ui.graphics.vector.PathNode> component9();
+ method public androidx.ui.graphics.vector.VectorGroup copy(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData);
method public operator androidx.ui.graphics.vector.VectorNode get(int index);
method public java.util.List<androidx.ui.graphics.vector.PathNode> getClipPathData();
method public String getName();
@@ -450,6 +467,17 @@
public final class VectorPath extends androidx.ui.graphics.vector.VectorNode {
ctor public VectorPath(String name, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, androidx.ui.graphics.Brush? fill, float fillAlpha, androidx.ui.graphics.Brush? stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.graphics.StrokeCap strokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin, float strokeLineMiter);
+ method public String component1();
+ method public float component10();
+ method public java.util.List<androidx.ui.graphics.vector.PathNode> component2();
+ method public androidx.ui.graphics.Brush? component3();
+ method public float component4();
+ method public androidx.ui.graphics.Brush? component5();
+ method public float component6();
+ method public float component7();
+ method public androidx.ui.graphics.StrokeCap component8();
+ method public androidx.ui.graphics.StrokeJoin component9();
+ method public androidx.ui.graphics.vector.VectorPath copy(String name, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, androidx.ui.graphics.Brush? fill, float fillAlpha, androidx.ui.graphics.Brush? stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.graphics.StrokeCap strokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin, float strokeLineMiter);
method public androidx.ui.graphics.Brush? getFill();
method public float getFillAlpha();
method public String getName();
diff --git a/ui/ui-framework/api/public_plus_experimental_current.txt b/ui/ui-framework/api/public_plus_experimental_current.txt
index 2086670..d14369a 100644
--- a/ui/ui-framework/api/public_plus_experimental_current.txt
+++ b/ui/ui-framework/api/public_plus_experimental_current.txt
@@ -394,8 +394,15 @@
package androidx.ui.graphics.vector {
public final class VectorAsset {
- method public androidx.ui.core.Px getDefaultHeight();
- method public androidx.ui.core.Px getDefaultWidth();
+ method public String component1();
+ method public androidx.ui.core.Dp component2();
+ method public androidx.ui.core.Dp component3();
+ method public float component4();
+ method public float component5();
+ method public androidx.ui.graphics.vector.VectorGroup component6();
+ method public androidx.ui.graphics.vector.VectorAsset copy(String name, androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth, float viewportHeight, androidx.ui.graphics.vector.VectorGroup root);
+ method public androidx.ui.core.Dp getDefaultHeight();
+ method public androidx.ui.core.Dp getDefaultWidth();
method public String getName();
method public androidx.ui.graphics.vector.VectorGroup getRoot();
method public float getViewportHeight();
@@ -403,12 +410,12 @@
}
public final class VectorAssetBuilder {
- ctor public VectorAssetBuilder(String name, androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth, float viewportHeight);
+ ctor public VectorAssetBuilder(String name, androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth, float viewportHeight);
method public androidx.ui.graphics.vector.VectorAssetBuilder addPath(java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
method public androidx.ui.graphics.vector.VectorAsset build();
method public void ensureNotConsumed();
- method public androidx.ui.core.Px getDefaultHeight();
- method public androidx.ui.core.Px getDefaultWidth();
+ method public androidx.ui.core.Dp getDefaultHeight();
+ method public androidx.ui.core.Dp getDefaultWidth();
method public String getName();
method public float getViewportHeight();
method public float getViewportWidth();
@@ -430,6 +437,16 @@
public final class VectorGroup extends androidx.ui.graphics.vector.VectorNode implements java.lang.Iterable<androidx.ui.graphics.vector.VectorNode> kotlin.jvm.internal.markers.KMappedMarker {
ctor public VectorGroup(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData);
ctor public VectorGroup();
+ method public String component1();
+ method public float component2();
+ method public float component3();
+ method public float component4();
+ method public float component5();
+ method public float component6();
+ method public float component7();
+ method public float component8();
+ method public java.util.List<androidx.ui.graphics.vector.PathNode> component9();
+ method public androidx.ui.graphics.vector.VectorGroup copy(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData);
method public operator androidx.ui.graphics.vector.VectorNode get(int index);
method public java.util.List<androidx.ui.graphics.vector.PathNode> getClipPathData();
method public String getName();
@@ -450,6 +467,17 @@
public final class VectorPath extends androidx.ui.graphics.vector.VectorNode {
ctor public VectorPath(String name, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, androidx.ui.graphics.Brush? fill, float fillAlpha, androidx.ui.graphics.Brush? stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.graphics.StrokeCap strokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin, float strokeLineMiter);
+ method public String component1();
+ method public float component10();
+ method public java.util.List<androidx.ui.graphics.vector.PathNode> component2();
+ method public androidx.ui.graphics.Brush? component3();
+ method public float component4();
+ method public androidx.ui.graphics.Brush? component5();
+ method public float component6();
+ method public float component7();
+ method public androidx.ui.graphics.StrokeCap component8();
+ method public androidx.ui.graphics.StrokeJoin component9();
+ method public androidx.ui.graphics.vector.VectorPath copy(String name, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, androidx.ui.graphics.Brush? fill, float fillAlpha, androidx.ui.graphics.Brush? stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.graphics.StrokeCap strokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin, float strokeLineMiter);
method public androidx.ui.graphics.Brush? getFill();
method public float getFillAlpha();
method public String getName();
diff --git a/ui/ui-framework/api/restricted_0.1.0-dev04.txt b/ui/ui-framework/api/restricted_0.1.0-dev04.txt
index 2086670..d14369a 100644
--- a/ui/ui-framework/api/restricted_0.1.0-dev04.txt
+++ b/ui/ui-framework/api/restricted_0.1.0-dev04.txt
@@ -394,8 +394,15 @@
package androidx.ui.graphics.vector {
public final class VectorAsset {
- method public androidx.ui.core.Px getDefaultHeight();
- method public androidx.ui.core.Px getDefaultWidth();
+ method public String component1();
+ method public androidx.ui.core.Dp component2();
+ method public androidx.ui.core.Dp component3();
+ method public float component4();
+ method public float component5();
+ method public androidx.ui.graphics.vector.VectorGroup component6();
+ method public androidx.ui.graphics.vector.VectorAsset copy(String name, androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth, float viewportHeight, androidx.ui.graphics.vector.VectorGroup root);
+ method public androidx.ui.core.Dp getDefaultHeight();
+ method public androidx.ui.core.Dp getDefaultWidth();
method public String getName();
method public androidx.ui.graphics.vector.VectorGroup getRoot();
method public float getViewportHeight();
@@ -403,12 +410,12 @@
}
public final class VectorAssetBuilder {
- ctor public VectorAssetBuilder(String name, androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth, float viewportHeight);
+ ctor public VectorAssetBuilder(String name, androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth, float viewportHeight);
method public androidx.ui.graphics.vector.VectorAssetBuilder addPath(java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
method public androidx.ui.graphics.vector.VectorAsset build();
method public void ensureNotConsumed();
- method public androidx.ui.core.Px getDefaultHeight();
- method public androidx.ui.core.Px getDefaultWidth();
+ method public androidx.ui.core.Dp getDefaultHeight();
+ method public androidx.ui.core.Dp getDefaultWidth();
method public String getName();
method public float getViewportHeight();
method public float getViewportWidth();
@@ -430,6 +437,16 @@
public final class VectorGroup extends androidx.ui.graphics.vector.VectorNode implements java.lang.Iterable<androidx.ui.graphics.vector.VectorNode> kotlin.jvm.internal.markers.KMappedMarker {
ctor public VectorGroup(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData);
ctor public VectorGroup();
+ method public String component1();
+ method public float component2();
+ method public float component3();
+ method public float component4();
+ method public float component5();
+ method public float component6();
+ method public float component7();
+ method public float component8();
+ method public java.util.List<androidx.ui.graphics.vector.PathNode> component9();
+ method public androidx.ui.graphics.vector.VectorGroup copy(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData);
method public operator androidx.ui.graphics.vector.VectorNode get(int index);
method public java.util.List<androidx.ui.graphics.vector.PathNode> getClipPathData();
method public String getName();
@@ -450,6 +467,17 @@
public final class VectorPath extends androidx.ui.graphics.vector.VectorNode {
ctor public VectorPath(String name, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, androidx.ui.graphics.Brush? fill, float fillAlpha, androidx.ui.graphics.Brush? stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.graphics.StrokeCap strokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin, float strokeLineMiter);
+ method public String component1();
+ method public float component10();
+ method public java.util.List<androidx.ui.graphics.vector.PathNode> component2();
+ method public androidx.ui.graphics.Brush? component3();
+ method public float component4();
+ method public androidx.ui.graphics.Brush? component5();
+ method public float component6();
+ method public float component7();
+ method public androidx.ui.graphics.StrokeCap component8();
+ method public androidx.ui.graphics.StrokeJoin component9();
+ method public androidx.ui.graphics.vector.VectorPath copy(String name, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, androidx.ui.graphics.Brush? fill, float fillAlpha, androidx.ui.graphics.Brush? stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.graphics.StrokeCap strokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin, float strokeLineMiter);
method public androidx.ui.graphics.Brush? getFill();
method public float getFillAlpha();
method public String getName();
diff --git a/ui/ui-framework/api/restricted_current.txt b/ui/ui-framework/api/restricted_current.txt
index 2086670..d14369a 100644
--- a/ui/ui-framework/api/restricted_current.txt
+++ b/ui/ui-framework/api/restricted_current.txt
@@ -394,8 +394,15 @@
package androidx.ui.graphics.vector {
public final class VectorAsset {
- method public androidx.ui.core.Px getDefaultHeight();
- method public androidx.ui.core.Px getDefaultWidth();
+ method public String component1();
+ method public androidx.ui.core.Dp component2();
+ method public androidx.ui.core.Dp component3();
+ method public float component4();
+ method public float component5();
+ method public androidx.ui.graphics.vector.VectorGroup component6();
+ method public androidx.ui.graphics.vector.VectorAsset copy(String name, androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth, float viewportHeight, androidx.ui.graphics.vector.VectorGroup root);
+ method public androidx.ui.core.Dp getDefaultHeight();
+ method public androidx.ui.core.Dp getDefaultWidth();
method public String getName();
method public androidx.ui.graphics.vector.VectorGroup getRoot();
method public float getViewportHeight();
@@ -403,12 +410,12 @@
}
public final class VectorAssetBuilder {
- ctor public VectorAssetBuilder(String name, androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth, float viewportHeight);
+ ctor public VectorAssetBuilder(String name, androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth, float viewportHeight);
method public androidx.ui.graphics.vector.VectorAssetBuilder addPath(java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
method public androidx.ui.graphics.vector.VectorAsset build();
method public void ensureNotConsumed();
- method public androidx.ui.core.Px getDefaultHeight();
- method public androidx.ui.core.Px getDefaultWidth();
+ method public androidx.ui.core.Dp getDefaultHeight();
+ method public androidx.ui.core.Dp getDefaultWidth();
method public String getName();
method public float getViewportHeight();
method public float getViewportWidth();
@@ -430,6 +437,16 @@
public final class VectorGroup extends androidx.ui.graphics.vector.VectorNode implements java.lang.Iterable<androidx.ui.graphics.vector.VectorNode> kotlin.jvm.internal.markers.KMappedMarker {
ctor public VectorGroup(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData);
ctor public VectorGroup();
+ method public String component1();
+ method public float component2();
+ method public float component3();
+ method public float component4();
+ method public float component5();
+ method public float component6();
+ method public float component7();
+ method public float component8();
+ method public java.util.List<androidx.ui.graphics.vector.PathNode> component9();
+ method public androidx.ui.graphics.vector.VectorGroup copy(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData);
method public operator androidx.ui.graphics.vector.VectorNode get(int index);
method public java.util.List<androidx.ui.graphics.vector.PathNode> getClipPathData();
method public String getName();
@@ -450,6 +467,17 @@
public final class VectorPath extends androidx.ui.graphics.vector.VectorNode {
ctor public VectorPath(String name, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, androidx.ui.graphics.Brush? fill, float fillAlpha, androidx.ui.graphics.Brush? stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.graphics.StrokeCap strokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin, float strokeLineMiter);
+ method public String component1();
+ method public float component10();
+ method public java.util.List<androidx.ui.graphics.vector.PathNode> component2();
+ method public androidx.ui.graphics.Brush? component3();
+ method public float component4();
+ method public androidx.ui.graphics.Brush? component5();
+ method public float component6();
+ method public float component7();
+ method public androidx.ui.graphics.StrokeCap component8();
+ method public androidx.ui.graphics.StrokeJoin component9();
+ method public androidx.ui.graphics.vector.VectorPath copy(String name, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, androidx.ui.graphics.Brush? fill, float fillAlpha, androidx.ui.graphics.Brush? stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.graphics.StrokeCap strokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin, float strokeLineMiter);
method public androidx.ui.graphics.Brush? getFill();
method public float getFillAlpha();
method public String getName();
diff --git a/ui/ui-framework/src/androidTest/java/androidx/ui/core/selection/SelectionContainerTest.kt b/ui/ui-framework/src/androidTest/java/androidx/ui/core/selection/SelectionContainerTest.kt
index bff3427..95f1530 100644
--- a/ui/ui-framework/src/androidTest/java/androidx/ui/core/selection/SelectionContainerTest.kt
+++ b/ui/ui-framework/src/androidTest/java/androidx/ui/core/selection/SelectionContainerTest.kt
@@ -17,6 +17,7 @@
package androidx.ui.core.selection
import android.R
+import android.app.Activity
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
@@ -31,7 +32,6 @@
import androidx.ui.core.test.ValueModel
import androidx.ui.core.withDensity
import androidx.ui.test.android.AndroidComposeTestRule
-import androidx.ui.test.createComposeRule
import androidx.ui.text.TextStyle
import androidx.ui.text.font.Font
import androidx.ui.text.font.FontStyle
@@ -50,10 +50,10 @@
@RunWith(JUnit4::class)
class SelectionContainerTest {
@get:Rule
- val composeTestRule = createComposeRule()
+ val composeTestRule = AndroidComposeTestRule<Activity>()
private val activity
- get() = (composeTestRule as AndroidComposeTestRule).activityTestRule.activity
+ get() = composeTestRule.activityTestRule.activity
private lateinit var view: View
diff --git a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
index 9e09f6f..a11786f 100644
--- a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
+++ b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
@@ -39,6 +39,7 @@
import androidx.ui.core.DensityAmbient
import androidx.ui.core.DensityScope
import androidx.ui.core.Draw
+import androidx.ui.core.DrawModifier
import androidx.ui.core.HorizontalAlignmentLine
import androidx.ui.core.IntPx
import androidx.ui.core.IntPxPosition
@@ -51,6 +52,7 @@
import androidx.ui.core.OnPositioned
import androidx.ui.core.ParentData
import androidx.ui.core.ParentDataModifier
+import androidx.ui.core.PxSize
import androidx.ui.core.Ref
import androidx.ui.core.RepaintBoundary
import androidx.ui.core.VerticalAlignmentLine
@@ -71,6 +73,7 @@
import androidx.ui.core.toRect
import androidx.ui.engine.geometry.Rect
import androidx.ui.framework.test.TestActivity
+import androidx.ui.graphics.Canvas
import androidx.ui.graphics.Color
import androidx.ui.graphics.Paint
import androidx.ui.graphics.PaintingStyle
@@ -1974,6 +1977,23 @@
)
}
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun modifier_combinedModifiers() {
+ activityTestRule.runOnUiThreadIR {
+ activity.setContentInFrameLayout {
+ FixedSize(30.ipx, background(Color.Blue)) {
+ Draw { _, _ ->
+ drawLatch.countDown()
+ }
+ JustConstraints(CombinedModifier(Color.White)) {
+ }
+ }
+ }
+ }
+ validateSquareColors(outerColor = Color.Blue, innerColor = Color.White, size = 10)
+ }
+
private val AlignTopLeft = object : LayoutModifier {
override fun DensityScope.modifyConstraints(constraints: Constraints) =
constraints.looseMin()
@@ -2435,6 +2455,13 @@
}
}
+@Composable
+fun JustConstraints(modifier: Modifier, children: @Composable() () -> Unit) {
+ Layout(children, modifier) { _, constraints ->
+ layout(constraints.minWidth, constraints.minHeight) {}
+ }
+}
+
class DrawCounterListener(private val view: View) :
ViewTreeObserver.OnPreDrawListener {
val latch = CountDownLatch(5)
@@ -2596,3 +2623,35 @@
}
canvas.drawRect(size.toRect(), paint)
}
+
+class CombinedModifier(color: Color) : LayoutModifier, DrawModifier {
+ val paint = Paint().also { paint ->
+ paint.color = color
+ paint.style = PaintingStyle.fill
+ }
+
+ override fun DensityScope.modifyPosition(
+ childSize: IntPxSize,
+ containerSize: IntPxSize
+ ): IntPxPosition {
+ return IntPxPosition(
+ (containerSize.width - childSize.width) / 2,
+ (containerSize.height - childSize.height) / 2
+ )
+ }
+
+ override fun DensityScope.modifyConstraints(constraints: Constraints): Constraints {
+ return Constraints.tightConstraints(10.ipx, 10.ipx)
+ }
+
+ override fun DensityScope.modifySize(
+ constraints: Constraints,
+ childSize: IntPxSize
+ ): IntPxSize {
+ return IntPxSize(constraints.maxWidth, constraints.maxHeight)
+ }
+
+ override fun draw(density: Density, drawContent: () -> Unit, canvas: Canvas, size: PxSize) {
+ canvas.drawRect(size.toRect(), paint)
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-framework/src/androidTest/java/androidx/ui/graphics/vector/VectorInvalidationTestCase.kt b/ui/ui-framework/src/androidTest/java/androidx/ui/graphics/vector/VectorInvalidationTestCase.kt
index 57c8d8e..5a788e1 100644
--- a/ui/ui-framework/src/androidTest/java/androidx/ui/graphics/vector/VectorInvalidationTestCase.kt
+++ b/ui/ui-framework/src/androidTest/java/androidx/ui/graphics/vector/VectorInvalidationTestCase.kt
@@ -48,7 +48,7 @@
val vectorAsset = loadVectorResource(state.value)
WithDensity {
vectorAsset.resource.resource?.let {
- val width = it.defaultWidth.toDp()
+ val width = it.defaultWidth
vectorSize = width.toIntPx().value
AtLeastSize(size = width.toIntPx()) {
Draw { canvas, parentSize ->
diff --git a/ui/ui-framework/src/androidTest/java/androidx/ui/graphics/vector/compat/XmlVectorParserTest.kt b/ui/ui-framework/src/androidTest/java/androidx/ui/graphics/vector/compat/XmlVectorParserTest.kt
index 4f4287c..132daea 100644
--- a/ui/ui-framework/src/androidTest/java/androidx/ui/graphics/vector/compat/XmlVectorParserTest.kt
+++ b/ui/ui-framework/src/androidTest/java/androidx/ui/graphics/vector/compat/XmlVectorParserTest.kt
@@ -18,14 +18,12 @@
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
-import androidx.ui.core.Px
-
-import androidx.ui.graphics.vector.VectorPath
+import androidx.ui.core.dp
import androidx.ui.framework.test.R
import androidx.ui.graphics.Color
import androidx.ui.graphics.SolidColor
import androidx.ui.graphics.vector.PathCommand
-import androidx.ui.graphics.vector.PathNode
+import androidx.ui.graphics.vector.VectorPath
import androidx.ui.res.loadVectorResource
import org.junit.Assert.assertEquals
import org.junit.Test
@@ -44,8 +42,7 @@
res,
R.drawable.test_compose_vector
)
- val density = res.displayMetrics.density
- val expectedSize = Px(density*24)
+ val expectedSize = 24.dp
assertEquals(expectedSize, asset.defaultWidth)
assertEquals(expectedSize, asset.defaultHeight)
assertEquals(24.0f, asset.viewportWidth)
@@ -57,20 +54,20 @@
val path = node.pathData
assertEquals(3, path.size)
- assertEquals(PathCommand.MoveTo, path.get(0).command)
- assertEquals(20.0f, path.get(0).args[0])
- assertEquals(10.0f, path.get(0).args[1])
+ assertEquals(PathCommand.MoveTo, path[0].command)
+ assertEquals(20.0f, path[0].args[0])
+ assertEquals(10.0f, path[0].args[1])
- assertEquals(PathCommand.RelativeLineTo, path.get(1).command)
- assertEquals(6, path.get(1).args.size)
- assertEquals(10.0f, path.get(1).args[0])
- assertEquals(0.0f, path.get(1).args[1])
- assertEquals(0.0f, path.get(1).args[2])
- assertEquals(10.0f, path.get(1).args[3])
- assertEquals(-10.0f, path.get(1).args[4])
- assertEquals(0.0f, path.get(1).args[5])
+ assertEquals(PathCommand.RelativeLineTo, path[1].command)
+ assertEquals(6, path[1].args.size)
+ assertEquals(10.0f, path[1].args[0])
+ assertEquals(0.0f, path[1].args[1])
+ assertEquals(0.0f, path[1].args[2])
+ assertEquals(10.0f, path[1].args[3])
+ assertEquals(-10.0f, path[1].args[4])
+ assertEquals(0.0f, path[1].args[5])
- assertEquals(PathCommand.RelativeClose, path.get(2).command)
- assertEquals(0, path.get(2).args.size)
+ assertEquals(PathCommand.RelativeClose, path[2].command)
+ assertEquals(0, path[2].args.size)
}
}
\ No newline at end of file
diff --git a/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorAsset.kt b/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorAsset.kt
index 3ce6d70..b35b046 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorAsset.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorAsset.kt
@@ -18,7 +18,7 @@
import androidx.compose.Composable
import androidx.ui.core.Alignment
-import androidx.ui.core.Px
+import androidx.ui.core.Dp
import androidx.ui.graphics.BlendMode
import androidx.ui.graphics.Brush
import androidx.ui.graphics.Color
@@ -44,14 +44,14 @@
val name: String = DefaultGroupName,
/**
- * Intrinsic width of the Vector in pixels
+ * Intrinsic width of the Vector in [Dp]
*/
- val defaultWidth: Px,
+ val defaultWidth: Dp,
/**
- * Intrinsic height of the Vector in pixels
+ * Intrinsic height of the Vector in [Dp]
*/
- val defaultHeight: Px,
+ val defaultHeight: Dp,
/**
* Used to define the width of the viewport space. Viewport is basically the virtual canvas
@@ -200,7 +200,7 @@
* Vector graphics object that is generated as a result of [VectorAssetBuilder]]
* It can be composed and rendered by passing it as an argument to [DrawVector]
*/
-class VectorAsset internal constructor(
+data class VectorAsset internal constructor(
/**
* Name of the Vector asset
@@ -208,14 +208,14 @@
val name: String,
/**
- * Intrinsic width of the vector asset in pixels
+ * Intrinsic width of the vector asset in [Dp]
*/
- val defaultWidth: Px,
+ val defaultWidth: Dp,
/**
- * Intrinsic height of the vector asset in pixels
+ * Intrinsic height of the vector asset in [Dp]
*/
- val defaultHeight: Px,
+ val defaultHeight: Dp,
/**
* Used to define the width of the viewport space. Viewport is basically the virtual canvas
@@ -240,7 +240,7 @@
* The transformations are defined in the same coordinates as the viewport.
* The transformations are applied in the order of scale, rotate then translate.
*/
-class VectorGroup(
+data class VectorGroup(
/**
* Name of the corresponding group
*/
@@ -317,7 +317,7 @@
* Leaf node of a Vector graphics tree. This specifies a path shape and parameters
* to color and style the the shape itself
*/
-class VectorPath(
+data class VectorPath(
/**
* Name of the corresponding path
*/
diff --git a/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/compat/XmlVectorParser.kt b/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/compat/XmlVectorParser.kt
index c7b248e..53be7f4 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/compat/XmlVectorParser.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/compat/XmlVectorParser.kt
@@ -20,17 +20,14 @@
import android.util.AttributeSet
import androidx.core.content.res.ComplexColorCompat
import androidx.core.content.res.TypedArrayUtils
-import androidx.ui.core.Px
-import androidx.ui.graphics.vector.VectorAssetBuilder
+import androidx.ui.core.dp
import androidx.ui.graphics.Brush
import androidx.ui.graphics.Color
+import androidx.ui.graphics.Shader
import androidx.ui.graphics.ShaderBrush
import androidx.ui.graphics.SolidColor
-
-import androidx.ui.graphics.Shader
import androidx.ui.graphics.StrokeCap
import androidx.ui.graphics.StrokeJoin
-import androidx.ui.graphics.vector.addPathNodes
import androidx.ui.graphics.vector.DefaultPivotX
import androidx.ui.graphics.vector.DefaultPivotY
import androidx.ui.graphics.vector.DefaultRotation
@@ -40,6 +37,8 @@
import androidx.ui.graphics.vector.DefaultTranslationY
import androidx.ui.graphics.vector.EmptyPath
import androidx.ui.graphics.vector.PathNode
+import androidx.ui.graphics.vector.VectorAssetBuilder
+import androidx.ui.graphics.vector.addPathNodes
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
@@ -156,13 +155,11 @@
if (viewportWidth <= 0) {
throw XmlPullParserException(
- vectorAttrs.getPositionDescription() +
- "<VectorGraphic> tag requires viewportWidth > 0"
+ vectorAttrs.positionDescription + "<VectorGraphic> tag requires viewportWidth > 0"
)
} else if (viewportHeight <= 0) {
throw XmlPullParserException(
- vectorAttrs.getPositionDescription() +
- "<VectorGraphic> tag requires viewportHeight > 0"
+ vectorAttrs.positionDescription + "<VectorGraphic> tag requires viewportHeight > 0"
)
}
@@ -173,11 +170,14 @@
AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_HEIGHT, 0.0f
)
+ val defaultWidthDp = (defaultWidth / res.displayMetrics.density).dp
+ val defaultHeightDp = (defaultHeight / res.displayMetrics.density).dp
+
vectorAttrs.recycle()
return VectorAssetBuilder(
- defaultWidth = Px(defaultWidth),
- defaultHeight = Px(defaultHeight),
+ defaultWidth = defaultWidthDp,
+ defaultHeight = defaultHeightDp,
viewportWidth = viewportWidth,
viewportHeight = viewportHeight
)
diff --git a/ui/ui-internal-lint-checks/src/main/java/androidx/ui/lint/UnnecessaryLambdaCreationDetector.kt b/ui/ui-internal-lint-checks/src/main/java/androidx/ui/lint/UnnecessaryLambdaCreationDetector.kt
index dc261ca..3481f8d 100644
--- a/ui/ui-internal-lint-checks/src/main/java/androidx/ui/lint/UnnecessaryLambdaCreationDetector.kt
+++ b/ui/ui-internal-lint-checks/src/main/java/androidx/ui/lint/UnnecessaryLambdaCreationDetector.kt
@@ -87,9 +87,18 @@
else -> null
} ?: return
+ // This is the parent function call that contains the lambda expression.
+ // I.e in Foo { bar() } this will be the call to `Foo`.
// We want to make sure this lambda is being invoked in the context of a function call,
- // and not as a property assignment.
- val parentExpression = node.uastParent!!.sourcePsi as? KtCallExpression ?: return
+ // and not as a property assignment - so we cast to KotlinUFunctionCallExpression to
+ // filter out such cases.
+ val parentExpression = (node.uastParent as? KotlinUFunctionCallExpression) ?: return
+
+ // If we can't resolve the parent call, then the parent function is defined in a
+ // separate module, so we don't have the right metadata - and hence the argumentType
+ // below will be Function0 even if in the actual source it has a scope. Return early to
+ // avoid false positives.
+ parentExpression.resolve() ?: return
// If the expression has no receiver, it is not a lambda invocation
val functionType = expression.receiverType as? PsiClassReferenceType ?: return
@@ -111,7 +120,11 @@
// shouldn't matter that much in practice.
if (functionType.reference.canonicalText.contains(NonExistentClass)) return
- if (parentExpression.isComponentNodeInvocation()) return
+ // Component nodes are classes that are invoked as if they are a function call, but
+ // they aren't actually a function call and so they cannot be inlined. Unfortunately
+ // since this is done in a compiler plugin, when running lint we don't have a way to
+ // understand this better, so we just check to see if the name looks like it is a node.
+ if (parentExpression.isComponentNodeInvocation) return
val lambdaName = expression.methodIdentifier!!.name
if (node.valueParameters.any { it.name == lambdaName }) return
@@ -126,8 +139,9 @@
}
companion object {
- private fun KtCallExpression.isComponentNodeInvocation() =
- referenceExpression()!!.text.endsWith("Node")
+ private val KotlinUFunctionCallExpression.isComponentNodeInvocation
+ get() = (sourcePsi as? KtCallExpression)?.referenceExpression()?.text
+ ?.endsWith("Node") == true
private const val NonExistentClass = "error.NonExistentClass"
diff --git a/ui/ui-layout/src/main/java/androidx/ui/layout/ConstraintLayout.kt b/ui/ui-layout/src/main/java/androidx/ui/layout/ConstraintLayout.kt
index 5596d0b..29cdffa 100644
--- a/ui/ui-layout/src/main/java/androidx/ui/layout/ConstraintLayout.kt
+++ b/ui/ui-layout/src/main/java/androidx/ui/layout/ConstraintLayout.kt
@@ -38,6 +38,7 @@
import androidx.ui.core.Layout
import androidx.ui.core.LayoutModifier
import androidx.ui.core.Measurable
+import androidx.ui.core.ParentDataModifier
import androidx.ui.core.Placeable
import androidx.ui.core.Placeable.PlacementScope.place
import androidx.ui.core.dp
@@ -656,7 +657,7 @@
get() = verticalBehavior == ConstraintWidget.DimensionBehaviour.WRAP_CONTENT
}
-private data class TagModifier(val tag: Any) : LayoutModifier {
+private data class TagModifier(val tag: Any) : LayoutModifier, ParentDataModifier {
override fun DensityScope.modifyConstraints(constraints: Constraints) = constraints
override fun DensityScope.modifySize(constraints: Constraints, childSize: IntPxSize) = childSize
override fun DensityScope.minIntrinsicWidthOf(measurable: Measurable, height: IntPx) =
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/ComponentNodes.kt b/ui/ui-platform/src/main/java/androidx/ui/core/ComponentNodes.kt
index e5bf326..24f380c 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/ComponentNodes.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/ComponentNodes.kt
@@ -1015,12 +1015,17 @@
// Rebuild layoutNodeWrapper
val oldPlaceable = layoutNodeWrapper
layoutNodeWrapper = modifier.foldOut(innerLayoutNodeWrapper) { mod, toWrap ->
- when (mod) {
- is LayoutModifier -> ModifiedLayoutNode(toWrap, mod)
- is ParentDataModifier -> ModifiedParentDataNode(toWrap, mod)
- is DrawModifier -> ModifiedDrawNode(toWrap, mod)
- else -> toWrap
+ var wrapper = toWrap
+ if (mod is DrawModifier) {
+ wrapper = ModifiedDrawNode(wrapper, mod)
}
+ if (mod is LayoutModifier) {
+ wrapper = ModifiedLayoutNode(wrapper, mod)
+ }
+ if (mod is ParentDataModifier) {
+ wrapper = ModifiedParentDataNode(wrapper, mod)
+ }
+ wrapper
}
// Optimize the case where the layout itself is not modified. A common reason for
// this is if no wrapping actually occurs above because no LayoutModifiers are
@@ -1182,7 +1187,7 @@
private inner class ModifiedLayoutNode(
override val wrapped: LayoutNodeWrapper,
val layoutModifier: LayoutModifier
- ) : ModifiedParentDataNode(wrapped, layoutModifier) {
+ ) : DelegatingLayoutNodeWrapper() {
/**
* The [Placeable] returned by measuring [wrapped] in [measure].
diff --git a/ui/ui-test/api/0.1.0-dev04.txt b/ui/ui-test/api/0.1.0-dev04.txt
index 133d226..fe1c8b5 100644
--- a/ui/ui-test/api/0.1.0-dev04.txt
+++ b/ui/ui-test/api/0.1.0-dev04.txt
@@ -103,8 +103,8 @@
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.ui.core.Density getDensity();
method public android.util.DisplayMetrics getDisplayMetrics();
- method public void runOnIdleCompose(kotlin.jvm.functions.Function0<kotlin.Unit> action);
- method public void runOnUiThread(kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public <T> T! runOnIdleCompose(kotlin.jvm.functions.Function0<? extends T> action);
+ method public <T> T! runOnUiThread(kotlin.jvm.functions.Function0<? extends T> action);
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
property public abstract androidx.ui.core.Density density;
property public abstract android.util.DisplayMetrics displayMetrics;
@@ -191,20 +191,19 @@
method public void performTestWithEventsControl(kotlin.jvm.functions.Function1<? super androidx.ui.test.ComposeExecutionControl,kotlin.Unit> block);
}
- public final class AndroidComposeTestRule implements androidx.ui.test.ComposeTestRule {
- ctor public AndroidComposeTestRule(boolean disableTransitions);
- ctor public AndroidComposeTestRule();
+ public final class AndroidComposeTestRule<T extends android.app.Activity> implements androidx.ui.test.ComposeTestRule {
+ ctor public AndroidComposeTestRule(Class<T> activityClass, boolean disableTransitions);
method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description? description);
method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
- method public androidx.test.rule.ActivityTestRule<android.app.Activity> getActivityTestRule();
+ method public androidx.test.rule.ActivityTestRule<T> getActivityTestRule();
method public androidx.ui.core.Density getDensity();
method public android.util.DisplayMetrics getDisplayMetrics();
- method public void runOnIdleCompose(kotlin.jvm.functions.Function0<kotlin.Unit> action);
- method public void runOnUiThread(kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public <T> T! runOnIdleCompose(kotlin.jvm.functions.Function0<? extends T> action);
+ method public <T> T! runOnUiThread(kotlin.jvm.functions.Function0<? extends T> action);
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
- property public final androidx.test.rule.ActivityTestRule<android.app.Activity> activityTestRule;
+ property public final androidx.test.rule.ActivityTestRule<T> activityTestRule;
property public androidx.ui.core.Density density;
property public android.util.DisplayMetrics displayMetrics;
}
@@ -214,6 +213,10 @@
method public void evaluate();
}
+ public final class AndroidComposeTestRuleKt {
+ method public static inline <reified T extends android.app.Activity> androidx.ui.test.android.AndroidComposeTestRule<T> AndroidComposeTestRule(boolean disableTransitions = false);
+ }
+
public final class ComposeIdlingResourceKt {
method public static void registerComposeWithEspresso();
method public static void unregisterComposeFromEspresso();
diff --git a/ui/ui-test/api/current.txt b/ui/ui-test/api/current.txt
index 133d226..fe1c8b5 100644
--- a/ui/ui-test/api/current.txt
+++ b/ui/ui-test/api/current.txt
@@ -103,8 +103,8 @@
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.ui.core.Density getDensity();
method public android.util.DisplayMetrics getDisplayMetrics();
- method public void runOnIdleCompose(kotlin.jvm.functions.Function0<kotlin.Unit> action);
- method public void runOnUiThread(kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public <T> T! runOnIdleCompose(kotlin.jvm.functions.Function0<? extends T> action);
+ method public <T> T! runOnUiThread(kotlin.jvm.functions.Function0<? extends T> action);
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
property public abstract androidx.ui.core.Density density;
property public abstract android.util.DisplayMetrics displayMetrics;
@@ -191,20 +191,19 @@
method public void performTestWithEventsControl(kotlin.jvm.functions.Function1<? super androidx.ui.test.ComposeExecutionControl,kotlin.Unit> block);
}
- public final class AndroidComposeTestRule implements androidx.ui.test.ComposeTestRule {
- ctor public AndroidComposeTestRule(boolean disableTransitions);
- ctor public AndroidComposeTestRule();
+ public final class AndroidComposeTestRule<T extends android.app.Activity> implements androidx.ui.test.ComposeTestRule {
+ ctor public AndroidComposeTestRule(Class<T> activityClass, boolean disableTransitions);
method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description? description);
method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
- method public androidx.test.rule.ActivityTestRule<android.app.Activity> getActivityTestRule();
+ method public androidx.test.rule.ActivityTestRule<T> getActivityTestRule();
method public androidx.ui.core.Density getDensity();
method public android.util.DisplayMetrics getDisplayMetrics();
- method public void runOnIdleCompose(kotlin.jvm.functions.Function0<kotlin.Unit> action);
- method public void runOnUiThread(kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public <T> T! runOnIdleCompose(kotlin.jvm.functions.Function0<? extends T> action);
+ method public <T> T! runOnUiThread(kotlin.jvm.functions.Function0<? extends T> action);
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
- property public final androidx.test.rule.ActivityTestRule<android.app.Activity> activityTestRule;
+ property public final androidx.test.rule.ActivityTestRule<T> activityTestRule;
property public androidx.ui.core.Density density;
property public android.util.DisplayMetrics displayMetrics;
}
@@ -214,6 +213,10 @@
method public void evaluate();
}
+ public final class AndroidComposeTestRuleKt {
+ method public static inline <reified T extends android.app.Activity> androidx.ui.test.android.AndroidComposeTestRule<T> AndroidComposeTestRule(boolean disableTransitions = false);
+ }
+
public final class ComposeIdlingResourceKt {
method public static void registerComposeWithEspresso();
method public static void unregisterComposeFromEspresso();
diff --git a/ui/ui-test/api/public_plus_experimental_0.1.0-dev04.txt b/ui/ui-test/api/public_plus_experimental_0.1.0-dev04.txt
index 133d226..fe1c8b5 100644
--- a/ui/ui-test/api/public_plus_experimental_0.1.0-dev04.txt
+++ b/ui/ui-test/api/public_plus_experimental_0.1.0-dev04.txt
@@ -103,8 +103,8 @@
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.ui.core.Density getDensity();
method public android.util.DisplayMetrics getDisplayMetrics();
- method public void runOnIdleCompose(kotlin.jvm.functions.Function0<kotlin.Unit> action);
- method public void runOnUiThread(kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public <T> T! runOnIdleCompose(kotlin.jvm.functions.Function0<? extends T> action);
+ method public <T> T! runOnUiThread(kotlin.jvm.functions.Function0<? extends T> action);
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
property public abstract androidx.ui.core.Density density;
property public abstract android.util.DisplayMetrics displayMetrics;
@@ -191,20 +191,19 @@
method public void performTestWithEventsControl(kotlin.jvm.functions.Function1<? super androidx.ui.test.ComposeExecutionControl,kotlin.Unit> block);
}
- public final class AndroidComposeTestRule implements androidx.ui.test.ComposeTestRule {
- ctor public AndroidComposeTestRule(boolean disableTransitions);
- ctor public AndroidComposeTestRule();
+ public final class AndroidComposeTestRule<T extends android.app.Activity> implements androidx.ui.test.ComposeTestRule {
+ ctor public AndroidComposeTestRule(Class<T> activityClass, boolean disableTransitions);
method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description? description);
method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
- method public androidx.test.rule.ActivityTestRule<android.app.Activity> getActivityTestRule();
+ method public androidx.test.rule.ActivityTestRule<T> getActivityTestRule();
method public androidx.ui.core.Density getDensity();
method public android.util.DisplayMetrics getDisplayMetrics();
- method public void runOnIdleCompose(kotlin.jvm.functions.Function0<kotlin.Unit> action);
- method public void runOnUiThread(kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public <T> T! runOnIdleCompose(kotlin.jvm.functions.Function0<? extends T> action);
+ method public <T> T! runOnUiThread(kotlin.jvm.functions.Function0<? extends T> action);
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
- property public final androidx.test.rule.ActivityTestRule<android.app.Activity> activityTestRule;
+ property public final androidx.test.rule.ActivityTestRule<T> activityTestRule;
property public androidx.ui.core.Density density;
property public android.util.DisplayMetrics displayMetrics;
}
@@ -214,6 +213,10 @@
method public void evaluate();
}
+ public final class AndroidComposeTestRuleKt {
+ method public static inline <reified T extends android.app.Activity> androidx.ui.test.android.AndroidComposeTestRule<T> AndroidComposeTestRule(boolean disableTransitions = false);
+ }
+
public final class ComposeIdlingResourceKt {
method public static void registerComposeWithEspresso();
method public static void unregisterComposeFromEspresso();
diff --git a/ui/ui-test/api/public_plus_experimental_current.txt b/ui/ui-test/api/public_plus_experimental_current.txt
index 133d226..fe1c8b5 100644
--- a/ui/ui-test/api/public_plus_experimental_current.txt
+++ b/ui/ui-test/api/public_plus_experimental_current.txt
@@ -103,8 +103,8 @@
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.ui.core.Density getDensity();
method public android.util.DisplayMetrics getDisplayMetrics();
- method public void runOnIdleCompose(kotlin.jvm.functions.Function0<kotlin.Unit> action);
- method public void runOnUiThread(kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public <T> T! runOnIdleCompose(kotlin.jvm.functions.Function0<? extends T> action);
+ method public <T> T! runOnUiThread(kotlin.jvm.functions.Function0<? extends T> action);
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
property public abstract androidx.ui.core.Density density;
property public abstract android.util.DisplayMetrics displayMetrics;
@@ -191,20 +191,19 @@
method public void performTestWithEventsControl(kotlin.jvm.functions.Function1<? super androidx.ui.test.ComposeExecutionControl,kotlin.Unit> block);
}
- public final class AndroidComposeTestRule implements androidx.ui.test.ComposeTestRule {
- ctor public AndroidComposeTestRule(boolean disableTransitions);
- ctor public AndroidComposeTestRule();
+ public final class AndroidComposeTestRule<T extends android.app.Activity> implements androidx.ui.test.ComposeTestRule {
+ ctor public AndroidComposeTestRule(Class<T> activityClass, boolean disableTransitions);
method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description? description);
method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
- method public androidx.test.rule.ActivityTestRule<android.app.Activity> getActivityTestRule();
+ method public androidx.test.rule.ActivityTestRule<T> getActivityTestRule();
method public androidx.ui.core.Density getDensity();
method public android.util.DisplayMetrics getDisplayMetrics();
- method public void runOnIdleCompose(kotlin.jvm.functions.Function0<kotlin.Unit> action);
- method public void runOnUiThread(kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public <T> T! runOnIdleCompose(kotlin.jvm.functions.Function0<? extends T> action);
+ method public <T> T! runOnUiThread(kotlin.jvm.functions.Function0<? extends T> action);
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
- property public final androidx.test.rule.ActivityTestRule<android.app.Activity> activityTestRule;
+ property public final androidx.test.rule.ActivityTestRule<T> activityTestRule;
property public androidx.ui.core.Density density;
property public android.util.DisplayMetrics displayMetrics;
}
@@ -214,6 +213,10 @@
method public void evaluate();
}
+ public final class AndroidComposeTestRuleKt {
+ method public static inline <reified T extends android.app.Activity> androidx.ui.test.android.AndroidComposeTestRule<T> AndroidComposeTestRule(boolean disableTransitions = false);
+ }
+
public final class ComposeIdlingResourceKt {
method public static void registerComposeWithEspresso();
method public static void unregisterComposeFromEspresso();
diff --git a/ui/ui-test/api/restricted_0.1.0-dev04.txt b/ui/ui-test/api/restricted_0.1.0-dev04.txt
index 133d226..fe1c8b5 100644
--- a/ui/ui-test/api/restricted_0.1.0-dev04.txt
+++ b/ui/ui-test/api/restricted_0.1.0-dev04.txt
@@ -103,8 +103,8 @@
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.ui.core.Density getDensity();
method public android.util.DisplayMetrics getDisplayMetrics();
- method public void runOnIdleCompose(kotlin.jvm.functions.Function0<kotlin.Unit> action);
- method public void runOnUiThread(kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public <T> T! runOnIdleCompose(kotlin.jvm.functions.Function0<? extends T> action);
+ method public <T> T! runOnUiThread(kotlin.jvm.functions.Function0<? extends T> action);
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
property public abstract androidx.ui.core.Density density;
property public abstract android.util.DisplayMetrics displayMetrics;
@@ -191,20 +191,19 @@
method public void performTestWithEventsControl(kotlin.jvm.functions.Function1<? super androidx.ui.test.ComposeExecutionControl,kotlin.Unit> block);
}
- public final class AndroidComposeTestRule implements androidx.ui.test.ComposeTestRule {
- ctor public AndroidComposeTestRule(boolean disableTransitions);
- ctor public AndroidComposeTestRule();
+ public final class AndroidComposeTestRule<T extends android.app.Activity> implements androidx.ui.test.ComposeTestRule {
+ ctor public AndroidComposeTestRule(Class<T> activityClass, boolean disableTransitions);
method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description? description);
method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
- method public androidx.test.rule.ActivityTestRule<android.app.Activity> getActivityTestRule();
+ method public androidx.test.rule.ActivityTestRule<T> getActivityTestRule();
method public androidx.ui.core.Density getDensity();
method public android.util.DisplayMetrics getDisplayMetrics();
- method public void runOnIdleCompose(kotlin.jvm.functions.Function0<kotlin.Unit> action);
- method public void runOnUiThread(kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public <T> T! runOnIdleCompose(kotlin.jvm.functions.Function0<? extends T> action);
+ method public <T> T! runOnUiThread(kotlin.jvm.functions.Function0<? extends T> action);
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
- property public final androidx.test.rule.ActivityTestRule<android.app.Activity> activityTestRule;
+ property public final androidx.test.rule.ActivityTestRule<T> activityTestRule;
property public androidx.ui.core.Density density;
property public android.util.DisplayMetrics displayMetrics;
}
@@ -214,6 +213,10 @@
method public void evaluate();
}
+ public final class AndroidComposeTestRuleKt {
+ method public static inline <reified T extends android.app.Activity> androidx.ui.test.android.AndroidComposeTestRule<T> AndroidComposeTestRule(boolean disableTransitions = false);
+ }
+
public final class ComposeIdlingResourceKt {
method public static void registerComposeWithEspresso();
method public static void unregisterComposeFromEspresso();
diff --git a/ui/ui-test/api/restricted_current.txt b/ui/ui-test/api/restricted_current.txt
index 133d226..fe1c8b5 100644
--- a/ui/ui-test/api/restricted_current.txt
+++ b/ui/ui-test/api/restricted_current.txt
@@ -103,8 +103,8 @@
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.ui.core.Density getDensity();
method public android.util.DisplayMetrics getDisplayMetrics();
- method public void runOnIdleCompose(kotlin.jvm.functions.Function0<kotlin.Unit> action);
- method public void runOnUiThread(kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public <T> T! runOnIdleCompose(kotlin.jvm.functions.Function0<? extends T> action);
+ method public <T> T! runOnUiThread(kotlin.jvm.functions.Function0<? extends T> action);
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
property public abstract androidx.ui.core.Density density;
property public abstract android.util.DisplayMetrics displayMetrics;
@@ -191,20 +191,19 @@
method public void performTestWithEventsControl(kotlin.jvm.functions.Function1<? super androidx.ui.test.ComposeExecutionControl,kotlin.Unit> block);
}
- public final class AndroidComposeTestRule implements androidx.ui.test.ComposeTestRule {
- ctor public AndroidComposeTestRule(boolean disableTransitions);
- ctor public AndroidComposeTestRule();
+ public final class AndroidComposeTestRule<T extends android.app.Activity> implements androidx.ui.test.ComposeTestRule {
+ ctor public AndroidComposeTestRule(Class<T> activityClass, boolean disableTransitions);
method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description? description);
method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
- method public androidx.test.rule.ActivityTestRule<android.app.Activity> getActivityTestRule();
+ method public androidx.test.rule.ActivityTestRule<T> getActivityTestRule();
method public androidx.ui.core.Density getDensity();
method public android.util.DisplayMetrics getDisplayMetrics();
- method public void runOnIdleCompose(kotlin.jvm.functions.Function0<kotlin.Unit> action);
- method public void runOnUiThread(kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public <T> T! runOnIdleCompose(kotlin.jvm.functions.Function0<? extends T> action);
+ method public <T> T! runOnUiThread(kotlin.jvm.functions.Function0<? extends T> action);
method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
- property public final androidx.test.rule.ActivityTestRule<android.app.Activity> activityTestRule;
+ property public final androidx.test.rule.ActivityTestRule<T> activityTestRule;
property public androidx.ui.core.Density density;
property public android.util.DisplayMetrics displayMetrics;
}
@@ -214,6 +213,10 @@
method public void evaluate();
}
+ public final class AndroidComposeTestRuleKt {
+ method public static inline <reified T extends android.app.Activity> androidx.ui.test.android.AndroidComposeTestRule<T> AndroidComposeTestRule(boolean disableTransitions = false);
+ }
+
public final class ComposeIdlingResourceKt {
method public static void registerComposeWithEspresso();
method public static void unregisterComposeFromEspresso();
diff --git a/ui/ui-test/src/androidTest/AndroidManifest.xml b/ui/ui-test/src/androidTest/AndroidManifest.xml
index 3c799d0..b08a496a 100644
--- a/ui/ui-test/src/androidTest/AndroidManifest.xml
+++ b/ui/ui-test/src/androidTest/AndroidManifest.xml
@@ -18,6 +18,8 @@
<application>
<activity android:name="android.app.Activity"
android:theme="@android:style/Theme.Material.NoActionBar.Fullscreen"/>
+ <activity android:name="androidx.ui.test.CustomActivity"
+ android:theme="@android:style/Theme.Material.NoActionBar.Fullscreen"/>
</application>
</manifest>
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/CustomActivityTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/CustomActivityTest.kt
new file mode 100644
index 0000000..0a431d0
--- /dev/null
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/CustomActivityTest.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2020 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.ui.test
+
+import android.app.Activity
+import android.os.Bundle
+import androidx.test.filters.MediumTest
+import androidx.ui.core.setContent
+import androidx.ui.layout.Stack
+import androidx.ui.material.Button
+import androidx.ui.material.MaterialTheme
+import androidx.ui.test.android.AndroidComposeTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+class CustomActivity : Activity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContent {
+ MaterialTheme {
+ Stack {
+ Button(text = "Hello")
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Tests that we can launch custom activities via [AndroidComposeTestRule].
+ */
+@MediumTest
+@RunWith(JUnit4::class)
+class CustomActivityTest {
+
+ @get:Rule
+ val testRule = AndroidComposeTestRule<CustomActivity>()
+
+ @Test
+ fun launchCustomActivity() {
+ findByText("Hello").assertIsVisible()
+ }
+}
diff --git a/ui/ui-test/src/main/java/androidx/ui/test/ComposeTestRule.kt b/ui/ui-test/src/main/java/androidx/ui/test/ComposeTestRule.kt
index bb05ada..8436ffb 100644
--- a/ui/ui-test/src/main/java/androidx/ui/test/ComposeTestRule.kt
+++ b/ui/ui-test/src/main/java/androidx/ui/test/ComposeTestRule.kt
@@ -16,6 +16,7 @@
package androidx.ui.test
+import android.app.Activity
import android.graphics.Bitmap
import android.os.Build
import android.util.DisplayMetrics
@@ -66,7 +67,7 @@
*
* This method is blocking until the action is complete.
*/
- fun runOnUiThread(action: () -> Unit)
+ fun <T> runOnUiThread(action: () -> T): T
/**
* Executes the given action in the same way as [runOnUiThread] but also makes sure Compose
@@ -75,7 +76,7 @@
*
* This method is blocking until the action is complete.
*/
- fun runOnIdleCompose(action: () -> Unit)
+ fun <T> runOnIdleCompose(action: () -> T): T
/**
* Takes screenshot of the Activity's window after Compose UI gets idle.
@@ -112,7 +113,14 @@
/**
* Factory method to provide implementation of [ComposeTestRule].
+ *
+ * This method is useful for tests in compose libraries where no custom Activity is usually
+ * needed. For app tests or launching custom activities, see [AndroidComposeTestRule].
+ *
+ * For Android this will use the default Activity (android.app.Activity). You need to add a
+ * reference to this activity into the manifest file of the corresponding tests (usually in
+ * androidTest/AndroidManifest.xml).
*/
fun createComposeRule(disableTransitions: Boolean = false): ComposeTestRule {
- return AndroidComposeTestRule(disableTransitions)
+ return AndroidComposeTestRule(Activity::class.java, disableTransitions)
}
diff --git a/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidComposeTestRule.kt b/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidComposeTestRule.kt
index 70ff64f..7c4044f 100644
--- a/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidComposeTestRule.kt
+++ b/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidComposeTestRule.kt
@@ -43,13 +43,34 @@
import java.util.concurrent.TimeUnit
/**
+ * Factory method to provide implementation of [AndroidComposeTestRule].
+ *
+ * This method is useful for tests that require a custom Activity. This is usually the case for
+ * app tests. Make sure that you add the provided activity into your app's manifest file (usually
+ * in main/AndroidManifest.xml).
+ *
+ * If you don't care about specific activity and just want to test composables in general, see
+ * [AndroidComposeTestRule].
+ */
+inline fun <reified T : Activity> AndroidComposeTestRule(
+ disableTransitions: Boolean = false
+): AndroidComposeTestRule<T> {
+ // TODO(b/138993381): By launching custom activities we are losing control over what content is
+ // already there. This is issue in case the user already set some compose content and decides
+ // to set it again via our API. In such case we won't be able to dispose the old composition.
+ // Other option would be to provide a smaller interface that does not expose these methods.
+ return AndroidComposeTestRule(T::class.java, disableTransitions)
+}
+
+/**
* Android specific implementation of [ComposeTestRule].
*/
-class AndroidComposeTestRule(
+class AndroidComposeTestRule<T : Activity>(
+ activityClass: Class<T>,
private val disableTransitions: Boolean = false
) : ComposeTestRule {
- val activityTestRule = ActivityTestRule<Activity>(Activity::class.java)
+ val activityTestRule = ActivityTestRule<T>(activityClass)
private val handler: Handler = Handler(Looper.getMainLooper())
private var disposeContentHook: (() -> Unit)? = null
@@ -63,20 +84,22 @@
return activityTestRule.apply(AndroidComposeStatement(base), description)
}
- override fun runOnUiThread(action: () -> Unit) {
+ override fun <T> runOnUiThread(action: () -> T): T {
// Workaround for lambda bug in IR
+ var result: T? = null
activityTestRule.runOnUiThread(object : Runnable {
override fun run() {
- action.invoke()
+ result = action.invoke()
}
})
+ return result!!
}
- override fun runOnIdleCompose(action: () -> Unit) {
+ override fun <T> runOnIdleCompose(action: () -> T): T {
// Method below make sure that compose is idle.
SynchronizedTreeCollector.waitForIdle()
// Execute the action on ui thread in a blocking way.
- runOnUiThread(action)
+ return runOnUiThread(action)
}
/**
diff --git a/viewpager2/integration-tests/testapp/build.gradle b/viewpager2/integration-tests/testapp/build.gradle
index 6cdafa6..a2268a1 100644
--- a/viewpager2/integration-tests/testapp/build.gradle
+++ b/viewpager2/integration-tests/testapp/build.gradle
@@ -35,7 +35,7 @@
dependencies {
api(KOTLIN_STDLIB)
- implementation(project(":viewpager2"))
+ implementation(project(":viewpager2:viewpager2"))
implementation("androidx.activity:activity-ktx:1.0.0")
implementation("com.google.android.material:material:1.1.0-alpha08") {
exclude group: 'androidx.viewpager2', module: 'viewpager2'
diff --git a/viewpager2/api/1.0.0-alpha02.txt b/viewpager2/viewpager2/api/1.0.0-alpha02.txt
similarity index 100%
rename from viewpager2/api/1.0.0-alpha02.txt
rename to viewpager2/viewpager2/api/1.0.0-alpha02.txt
diff --git a/viewpager2/api/1.0.0-alpha03.txt b/viewpager2/viewpager2/api/1.0.0-alpha03.txt
similarity index 100%
rename from viewpager2/api/1.0.0-alpha03.txt
rename to viewpager2/viewpager2/api/1.0.0-alpha03.txt
diff --git a/viewpager2/api/1.0.0-alpha04.txt b/viewpager2/viewpager2/api/1.0.0-alpha04.txt
similarity index 100%
rename from viewpager2/api/1.0.0-alpha04.txt
rename to viewpager2/viewpager2/api/1.0.0-alpha04.txt
diff --git a/viewpager2/api/1.0.0-alpha05.txt b/viewpager2/viewpager2/api/1.0.0-alpha05.txt
similarity index 100%
rename from viewpager2/api/1.0.0-alpha05.txt
rename to viewpager2/viewpager2/api/1.0.0-alpha05.txt
diff --git a/viewpager2/api/1.0.0-alpha06.txt b/viewpager2/viewpager2/api/1.0.0-alpha06.txt
similarity index 100%
rename from viewpager2/api/1.0.0-alpha06.txt
rename to viewpager2/viewpager2/api/1.0.0-alpha06.txt
diff --git a/viewpager2/api/1.0.0-beta01.txt b/viewpager2/viewpager2/api/1.0.0-beta01.txt
similarity index 100%
rename from viewpager2/api/1.0.0-beta01.txt
rename to viewpager2/viewpager2/api/1.0.0-beta01.txt
diff --git a/viewpager2/api/1.0.0-beta02.txt b/viewpager2/viewpager2/api/1.0.0-beta02.txt
similarity index 100%
rename from viewpager2/api/1.0.0-beta02.txt
rename to viewpager2/viewpager2/api/1.0.0-beta02.txt
diff --git a/viewpager2/api/1.0.0-beta03.txt b/viewpager2/viewpager2/api/1.0.0-beta03.txt
similarity index 100%
rename from viewpager2/api/1.0.0-beta03.txt
rename to viewpager2/viewpager2/api/1.0.0-beta03.txt
diff --git a/viewpager2/api/1.0.0-beta04.txt b/viewpager2/viewpager2/api/1.0.0-beta04.txt
similarity index 100%
rename from viewpager2/api/1.0.0-beta04.txt
rename to viewpager2/viewpager2/api/1.0.0-beta04.txt
diff --git a/viewpager2/api/1.0.0-beta05.txt b/viewpager2/viewpager2/api/1.0.0-beta05.txt
similarity index 100%
rename from viewpager2/api/1.0.0-beta05.txt
rename to viewpager2/viewpager2/api/1.0.0-beta05.txt
diff --git a/viewpager2/api/1.0.0-beta06.txt b/viewpager2/viewpager2/api/1.0.0-beta06.txt
similarity index 100%
rename from viewpager2/api/1.0.0-beta06.txt
rename to viewpager2/viewpager2/api/1.0.0-beta06.txt
diff --git a/viewpager2/api/1.0.0-rc01.txt b/viewpager2/viewpager2/api/1.0.0-rc01.txt
similarity index 100%
rename from viewpager2/api/1.0.0-rc01.txt
rename to viewpager2/viewpager2/api/1.0.0-rc01.txt
diff --git a/viewpager2/api/1.1.0-alpha01.txt b/viewpager2/viewpager2/api/1.1.0-alpha01.txt
similarity index 100%
rename from viewpager2/api/1.1.0-alpha01.txt
rename to viewpager2/viewpager2/api/1.1.0-alpha01.txt
diff --git a/viewpager2/api/api_lint.ignore b/viewpager2/viewpager2/api/api_lint.ignore
similarity index 100%
rename from viewpager2/api/api_lint.ignore
rename to viewpager2/viewpager2/api/api_lint.ignore
diff --git a/viewpager2/api/current.txt b/viewpager2/viewpager2/api/current.txt
similarity index 100%
rename from viewpager2/api/current.txt
rename to viewpager2/viewpager2/api/current.txt
diff --git a/viewpager2/api/public_plus_experimental_1.0.0-alpha01.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.0.0-alpha01.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_1.0.0-alpha01.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_1.0.0-alpha01.txt
diff --git a/viewpager2/api/public_plus_experimental_1.0.0-alpha02.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.0.0-alpha02.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_1.0.0-alpha02.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_1.0.0-alpha02.txt
diff --git a/viewpager2/api/public_plus_experimental_1.0.0-alpha03.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.0.0-alpha03.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_1.0.0-alpha03.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_1.0.0-alpha03.txt
diff --git a/viewpager2/api/public_plus_experimental_1.0.0-alpha04.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.0.0-alpha04.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_1.0.0-alpha04.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_1.0.0-alpha04.txt
diff --git a/viewpager2/api/public_plus_experimental_1.0.0-alpha05.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.0.0-alpha05.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_1.0.0-alpha05.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_1.0.0-alpha05.txt
diff --git a/viewpager2/api/public_plus_experimental_1.0.0-alpha06.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.0.0-alpha06.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_1.0.0-alpha06.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_1.0.0-alpha06.txt
diff --git a/viewpager2/api/public_plus_experimental_1.0.0-beta01.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.0.0-beta01.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_1.0.0-beta01.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_1.0.0-beta01.txt
diff --git a/viewpager2/api/public_plus_experimental_1.0.0-beta02.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.0.0-beta02.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_1.0.0-beta02.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_1.0.0-beta02.txt
diff --git a/viewpager2/api/public_plus_experimental_1.0.0-beta03.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.0.0-beta03.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_1.0.0-beta03.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_1.0.0-beta03.txt
diff --git a/viewpager2/api/public_plus_experimental_1.0.0-beta04.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.0.0-beta04.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_1.0.0-beta04.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_1.0.0-beta04.txt
diff --git a/viewpager2/api/public_plus_experimental_1.0.0-beta05.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.0.0-beta05.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_1.0.0-beta05.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_1.0.0-beta05.txt
diff --git a/viewpager2/api/public_plus_experimental_1.0.0-beta06.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.0.0-beta06.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_1.0.0-beta06.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_1.0.0-beta06.txt
diff --git a/viewpager2/api/public_plus_experimental_1.0.0-rc01.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.0.0-rc01.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_1.0.0-rc01.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_1.0.0-rc01.txt
diff --git a/viewpager2/api/public_plus_experimental_1.1.0-alpha01.txt b/viewpager2/viewpager2/api/public_plus_experimental_1.1.0-alpha01.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_1.1.0-alpha01.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_1.1.0-alpha01.txt
diff --git a/viewpager2/api/public_plus_experimental_current.txt b/viewpager2/viewpager2/api/public_plus_experimental_current.txt
similarity index 100%
rename from viewpager2/api/public_plus_experimental_current.txt
rename to viewpager2/viewpager2/api/public_plus_experimental_current.txt
diff --git a/viewpager2/api/res-1.0.0-alpha01.txt b/viewpager2/viewpager2/api/res-1.0.0-alpha01.txt
similarity index 100%
rename from viewpager2/api/res-1.0.0-alpha01.txt
rename to viewpager2/viewpager2/api/res-1.0.0-alpha01.txt
diff --git a/viewpager2/api/res-1.0.0-alpha02.txt b/viewpager2/viewpager2/api/res-1.0.0-alpha02.txt
similarity index 100%
rename from viewpager2/api/res-1.0.0-alpha02.txt
rename to viewpager2/viewpager2/api/res-1.0.0-alpha02.txt
diff --git a/viewpager2/api/res-1.0.0-alpha03.txt b/viewpager2/viewpager2/api/res-1.0.0-alpha03.txt
similarity index 100%
rename from viewpager2/api/res-1.0.0-alpha03.txt
rename to viewpager2/viewpager2/api/res-1.0.0-alpha03.txt
diff --git a/viewpager2/api/res-1.0.0-alpha04.txt b/viewpager2/viewpager2/api/res-1.0.0-alpha04.txt
similarity index 100%
rename from viewpager2/api/res-1.0.0-alpha04.txt
rename to viewpager2/viewpager2/api/res-1.0.0-alpha04.txt
diff --git a/viewpager2/api/res-1.0.0-alpha05.txt b/viewpager2/viewpager2/api/res-1.0.0-alpha05.txt
similarity index 100%
rename from viewpager2/api/res-1.0.0-alpha05.txt
rename to viewpager2/viewpager2/api/res-1.0.0-alpha05.txt
diff --git a/viewpager2/api/res-1.0.0-alpha06.txt b/viewpager2/viewpager2/api/res-1.0.0-alpha06.txt
similarity index 100%
rename from viewpager2/api/res-1.0.0-alpha06.txt
rename to viewpager2/viewpager2/api/res-1.0.0-alpha06.txt
diff --git a/viewpager2/api/res-1.0.0-beta01.txt b/viewpager2/viewpager2/api/res-1.0.0-beta01.txt
similarity index 100%
rename from viewpager2/api/res-1.0.0-beta01.txt
rename to viewpager2/viewpager2/api/res-1.0.0-beta01.txt
diff --git a/viewpager2/api/res-1.0.0-beta02.txt b/viewpager2/viewpager2/api/res-1.0.0-beta02.txt
similarity index 100%
rename from viewpager2/api/res-1.0.0-beta02.txt
rename to viewpager2/viewpager2/api/res-1.0.0-beta02.txt
diff --git a/viewpager2/api/res-1.0.0-beta03.txt b/viewpager2/viewpager2/api/res-1.0.0-beta03.txt
similarity index 100%
rename from viewpager2/api/res-1.0.0-beta03.txt
rename to viewpager2/viewpager2/api/res-1.0.0-beta03.txt
diff --git a/viewpager2/api/res-1.0.0-beta04.txt b/viewpager2/viewpager2/api/res-1.0.0-beta04.txt
similarity index 100%
rename from viewpager2/api/res-1.0.0-beta04.txt
rename to viewpager2/viewpager2/api/res-1.0.0-beta04.txt
diff --git a/viewpager2/api/res-1.0.0-beta05.txt b/viewpager2/viewpager2/api/res-1.0.0-beta05.txt
similarity index 100%
rename from viewpager2/api/res-1.0.0-beta05.txt
rename to viewpager2/viewpager2/api/res-1.0.0-beta05.txt
diff --git a/viewpager2/api/res-1.0.0-beta06.txt b/viewpager2/viewpager2/api/res-1.0.0-beta06.txt
similarity index 100%
rename from viewpager2/api/res-1.0.0-beta06.txt
rename to viewpager2/viewpager2/api/res-1.0.0-beta06.txt
diff --git a/viewpager2/api/res-1.0.0-rc01.txt b/viewpager2/viewpager2/api/res-1.0.0-rc01.txt
similarity index 100%
rename from viewpager2/api/res-1.0.0-rc01.txt
rename to viewpager2/viewpager2/api/res-1.0.0-rc01.txt
diff --git a/viewpager2/api/res-1.1.0-alpha01.txt b/viewpager2/viewpager2/api/res-1.1.0-alpha01.txt
similarity index 100%
rename from viewpager2/api/res-1.1.0-alpha01.txt
rename to viewpager2/viewpager2/api/res-1.1.0-alpha01.txt
diff --git a/viewpager2/api/restricted_1.0.0-alpha02.txt b/viewpager2/viewpager2/api/restricted_1.0.0-alpha02.txt
similarity index 100%
rename from viewpager2/api/restricted_1.0.0-alpha02.txt
rename to viewpager2/viewpager2/api/restricted_1.0.0-alpha02.txt
diff --git a/viewpager2/api/restricted_1.0.0-alpha03.txt b/viewpager2/viewpager2/api/restricted_1.0.0-alpha03.txt
similarity index 100%
rename from viewpager2/api/restricted_1.0.0-alpha03.txt
rename to viewpager2/viewpager2/api/restricted_1.0.0-alpha03.txt
diff --git a/viewpager2/api/restricted_1.0.0-alpha04.txt b/viewpager2/viewpager2/api/restricted_1.0.0-alpha04.txt
similarity index 100%
rename from viewpager2/api/restricted_1.0.0-alpha04.txt
rename to viewpager2/viewpager2/api/restricted_1.0.0-alpha04.txt
diff --git a/viewpager2/api/restricted_1.0.0-alpha05.txt b/viewpager2/viewpager2/api/restricted_1.0.0-alpha05.txt
similarity index 100%
rename from viewpager2/api/restricted_1.0.0-alpha05.txt
rename to viewpager2/viewpager2/api/restricted_1.0.0-alpha05.txt
diff --git a/viewpager2/api/restricted_1.0.0-alpha06.txt b/viewpager2/viewpager2/api/restricted_1.0.0-alpha06.txt
similarity index 100%
rename from viewpager2/api/restricted_1.0.0-alpha06.txt
rename to viewpager2/viewpager2/api/restricted_1.0.0-alpha06.txt
diff --git a/viewpager2/api/restricted_1.0.0-beta01.txt b/viewpager2/viewpager2/api/restricted_1.0.0-beta01.txt
similarity index 100%
rename from viewpager2/api/restricted_1.0.0-beta01.txt
rename to viewpager2/viewpager2/api/restricted_1.0.0-beta01.txt
diff --git a/viewpager2/api/restricted_1.0.0-beta02.txt b/viewpager2/viewpager2/api/restricted_1.0.0-beta02.txt
similarity index 100%
rename from viewpager2/api/restricted_1.0.0-beta02.txt
rename to viewpager2/viewpager2/api/restricted_1.0.0-beta02.txt
diff --git a/viewpager2/api/restricted_1.0.0-beta03.txt b/viewpager2/viewpager2/api/restricted_1.0.0-beta03.txt
similarity index 100%
rename from viewpager2/api/restricted_1.0.0-beta03.txt
rename to viewpager2/viewpager2/api/restricted_1.0.0-beta03.txt
diff --git a/viewpager2/api/restricted_1.0.0-beta04.txt b/viewpager2/viewpager2/api/restricted_1.0.0-beta04.txt
similarity index 100%
rename from viewpager2/api/restricted_1.0.0-beta04.txt
rename to viewpager2/viewpager2/api/restricted_1.0.0-beta04.txt
diff --git a/viewpager2/api/restricted_1.0.0-beta05.txt b/viewpager2/viewpager2/api/restricted_1.0.0-beta05.txt
similarity index 100%
rename from viewpager2/api/restricted_1.0.0-beta05.txt
rename to viewpager2/viewpager2/api/restricted_1.0.0-beta05.txt
diff --git a/viewpager2/api/restricted_1.0.0-beta06.txt b/viewpager2/viewpager2/api/restricted_1.0.0-beta06.txt
similarity index 100%
rename from viewpager2/api/restricted_1.0.0-beta06.txt
rename to viewpager2/viewpager2/api/restricted_1.0.0-beta06.txt
diff --git a/viewpager2/api/restricted_1.0.0-rc01.txt b/viewpager2/viewpager2/api/restricted_1.0.0-rc01.txt
similarity index 100%
rename from viewpager2/api/restricted_1.0.0-rc01.txt
rename to viewpager2/viewpager2/api/restricted_1.0.0-rc01.txt
diff --git a/viewpager2/api/restricted_1.1.0-alpha01.txt b/viewpager2/viewpager2/api/restricted_1.1.0-alpha01.txt
similarity index 100%
rename from viewpager2/api/restricted_1.1.0-alpha01.txt
rename to viewpager2/viewpager2/api/restricted_1.1.0-alpha01.txt
diff --git a/viewpager2/api/restricted_current.txt b/viewpager2/viewpager2/api/restricted_current.txt
similarity index 100%
rename from viewpager2/api/restricted_current.txt
rename to viewpager2/viewpager2/api/restricted_current.txt
diff --git a/viewpager2/build.gradle b/viewpager2/viewpager2/build.gradle
similarity index 100%
rename from viewpager2/build.gradle
rename to viewpager2/viewpager2/build.gradle
diff --git a/viewpager2/lint-baseline.xml b/viewpager2/viewpager2/lint-baseline.xml
similarity index 100%
rename from viewpager2/lint-baseline.xml
rename to viewpager2/viewpager2/lint-baseline.xml
diff --git a/viewpager2/src/androidTest/AndroidManifest.xml b/viewpager2/viewpager2/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from viewpager2/src/androidTest/AndroidManifest.xml
rename to viewpager2/viewpager2/src/androidTest/AndroidManifest.xml
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/test/ui/SparseAdapter.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/test/ui/SparseAdapter.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/test/ui/SparseAdapter.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/test/ui/SparseAdapter.kt
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/test/ui/TouchConsumingTextView.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/test/ui/TouchConsumingTextView.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/test/ui/TouchConsumingTextView.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/test/ui/TouchConsumingTextView.kt
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AccessibilityTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AccessibilityTest.kt
similarity index 96%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/AccessibilityTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AccessibilityTest.kt
index 0945a5d..17c5a12 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AccessibilityTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AccessibilityTest.kt
@@ -66,7 +66,7 @@
@SdkSuppress(minSdkVersion = 16)
fun test_onPerformPageAction() {
setUpTest(config.orientation).apply {
- setAdapterSync(viewAdapterProvider(stringSequence(6)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(6)))
val initialPage = viewPager.currentItem
assertBasicState(initialPage)
@@ -93,7 +93,7 @@
@Test
fun test_collectionInfo() {
setUpTest(config.orientation).apply {
- setAdapterSync(viewAdapterProvider(stringSequence(6)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(6)))
val initialPage = viewPager.currentItem
assertBasicState(initialPage)
@@ -124,7 +124,7 @@
@Test
fun test_onOrientationChange() {
setUpTest(config.orientation).apply {
- setAdapterSync(viewAdapterProvider(stringSequence(2)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(2)))
val initialPage = viewPager.currentItem
assertBasicState(initialPage)
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterDataSetChangeTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterDataSetChangeTest.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterDataSetChangeTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterDataSetChangeTest.kt
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterDataSetChangeWhileSmoothScrollTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterDataSetChangeWhileSmoothScrollTest.kt
similarity index 99%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterDataSetChangeWhileSmoothScrollTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterDataSetChangeWhileSmoothScrollTest.kt
index 3815b5a..847c44c 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterDataSetChangeWhileSmoothScrollTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterDataSetChangeWhileSmoothScrollTest.kt
@@ -102,7 +102,7 @@
test = setUpTest(config.orientation)
activityTestRule.runOnUiThread { test.viewPager.offscreenPageLimit = 1 }
dataSet = stringSequence(pageCount).toMutableList()
- test.setAdapterSync(config.adapterProvider(dataSet))
+ test.setAdapterSync(config.adapterProvider.provider(dataSet))
}
@Test
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterTest.kt
similarity index 98%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterTest.kt
index f2333f9..a61995a 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterTest.kt
@@ -49,7 +49,7 @@
@Test
fun test_setAdapter() {
val recorder = test.viewPager.addNewRecordingCallback()
- test.setAdapterSync(viewAdapterProvider(stringSequence(pageCount)))
+ test.setAdapterSync(viewAdapterProvider.provider(stringSequence(pageCount)))
test.assertBasicState(0)
test.viewPager.setCurrentItemSync(1, false, 2, SECONDS)
test.assertBasicState(1)
@@ -195,7 +195,7 @@
private fun setUpAdapterSync(pageCount: Int, initialPage: Int? = null) {
dataSet = stringSequence(pageCount).toMutableList()
- test.setAdapterSync(viewAdapterProvider(dataSet))
+ test.setAdapterSync(viewAdapterProvider.provider(dataSet))
if (initialPage != null) {
test.viewPager.setCurrentItemSync(initialPage, false, 2, SECONDS)
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
similarity index 93%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
index d724b7f..688625ca 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
@@ -599,9 +599,14 @@
typealias AdapterProvider = (TestActivity) -> RecyclerView.Adapter<out RecyclerView.ViewHolder>
-typealias AdapterProviderForItems = (items: List<String>) -> AdapterProvider
+data class AdapterProviderForItems(
+ val name: String,
+ val provider: (items: List<String>) -> AdapterProvider
+) {
+ override fun toString(): String = name
+}
-val fragmentAdapterProvider: AdapterProviderForItems = { items ->
+val fragmentAdapterProvider = AdapterProviderForItems("fragmentAdapterProvider") { items ->
{ activity: TestActivity ->
FragmentAdapter(
activity.supportFragmentManager,
@@ -616,35 +621,38 @@
* [FragmentStateAdapter.getItemId] and [FragmentStateAdapter.containsItem].
* Not suitable for testing [RecyclerView.Adapter.notifyDataSetChanged].
*/
-val fragmentAdapterProviderCustomIds: AdapterProviderForItems = { items ->
- { activity ->
- fragmentAdapterProvider(items)(activity).also {
- // more than position can represent, so a good test if ids are used consistently
- val offset = 3L * Int.MAX_VALUE
- val adapter = it as FragmentAdapter
- adapter.positionToItemId = { position -> position + offset }
- adapter.itemIdToContains = { itemId ->
- val position = itemId - offset
- position in (0 until adapter.itemCount)
+val fragmentAdapterProviderCustomIds =
+ AdapterProviderForItems("fragmentAdapterProviderCustomIds") { items ->
+ { activity ->
+ fragmentAdapterProvider.provider(items)(activity).also {
+ // more than position can represent, so a good test if ids are used consistently
+ val offset = 3L * Int.MAX_VALUE
+ val adapter = it as FragmentAdapter
+ adapter.positionToItemId = { position -> position + offset }
+ adapter.itemIdToContains = { itemId ->
+ val position = itemId - offset
+ position in (0 until adapter.itemCount)
+ }
}
}
}
-}
/**
* Same as [fragmentAdapterProvider] but with a custom implementation of
* [FragmentStateAdapter.getItemId] and [FragmentStateAdapter.containsItem].
* Suitable for testing [RecyclerView.Adapter.notifyDataSetChanged].
*/
-val fragmentAdapterProviderValueId: AdapterProviderForItems = { items ->
- { activity ->
- fragmentAdapterProvider(items)(activity).also {
- val adapter = it as FragmentAdapter
- adapter.positionToItemId = { position -> items[position].getId() }
- adapter.itemIdToContains = { itemId -> items.any { item -> item.getId() == itemId } }
+val fragmentAdapterProviderValueId =
+ AdapterProviderForItems("fragmentAdapterProviderValueId") { items ->
+ { activity ->
+ fragmentAdapterProvider.provider(items)(activity).also {
+ val adapter = it as FragmentAdapter
+ adapter.positionToItemId = { position -> items[position].getId() }
+ adapter.itemIdToContains =
+ { itemId -> items.any { item -> item.getId() == itemId } }
+ }
}
}
-}
/** Extracts the sole number from a [String] and converts it to a [Long] */
private fun (String).getId(): Long {
@@ -660,9 +668,9 @@
* [RecyclerView.Adapter.getItemId].
* Suitable for testing [RecyclerView.Adapter.notifyDataSetChanged].mu
*/
-val viewAdapterProviderValueId: AdapterProviderForItems = { items ->
+val viewAdapterProviderValueId = AdapterProviderForItems("viewAdapterProviderValueId") { items ->
{ activity ->
- viewAdapterProvider(items)(activity).also {
+ viewAdapterProvider.provider(items)(activity).also {
val adapter = it as ViewAdapter
adapter.positionToItemId = { position -> items[position].getId() }
adapter.setHasStableIds(true)
@@ -670,7 +678,8 @@
}
}
-val viewAdapterProvider: AdapterProviderForItems = { items -> { ViewAdapter(items) } }
+val viewAdapterProvider =
+ AdapterProviderForItems("viewAdapterProvider") { items -> { ViewAdapter(items) } }
fun stringSequence(pageCount: Int) = (0 until pageCount).map { it.toString() }
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BasicTest.java b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BasicTest.java
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/BasicTest.java
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BasicTest.java
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/CanScrollTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/CanScrollTest.kt
similarity index 88%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/CanScrollTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/CanScrollTest.kt
index e268559..045de41 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/CanScrollTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/CanScrollTest.kt
@@ -39,19 +39,19 @@
// given
setUpTest(ORIENTATION_HORIZONTAL).apply {
// when no pages
- setAdapterSync(viewAdapterProvider(stringSequence(0)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(0)))
// then can't scroll
assertScrollNone()
// when 1 page
- setAdapterSync(viewAdapterProvider(stringSequence(1)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(1)))
// then can't scroll
assertScrollNone()
// when 2 pages
- setAdapterSync(viewAdapterProvider(stringSequence(2)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(2)))
// then can scroll right
assertScrollRight()
@@ -84,19 +84,19 @@
localeUtil.setLocale(LocaleTestUtils.RTL_LANGUAGE)
setUpTest(ORIENTATION_HORIZONTAL).apply {
// when no pages
- setAdapterSync(viewAdapterProvider(stringSequence(0)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(0)))
// then can't scroll
assertScrollNone()
// when 1 page
- setAdapterSync(viewAdapterProvider(stringSequence(1)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(1)))
// then can't scroll
assertScrollNone()
// when 2 pages
- setAdapterSync(viewAdapterProvider(stringSequence(2)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(2)))
// then can scroll left
assertScrollLeft()
@@ -126,19 +126,19 @@
// given
setUpTest(ORIENTATION_VERTICAL).apply {
// when no pages
- setAdapterSync(viewAdapterProvider(stringSequence(0)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(0)))
// then can't scroll
assertScrollNone()
// when 1 page
- setAdapterSync(viewAdapterProvider(stringSequence(1)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(1)))
// then can't scroll
assertScrollNone()
// when 2 pages
- setAdapterSync(viewAdapterProvider(stringSequence(2)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(2)))
// then can scroll down
assertScrollDown()
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ChangeDataSetWhileScrollingTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ChangeDataSetWhileScrollingTest.kt
similarity index 98%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/ChangeDataSetWhileScrollingTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ChangeDataSetWhileScrollingTest.kt
index 7f22960..7a30f81 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ChangeDataSetWhileScrollingTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ChangeDataSetWhileScrollingTest.kt
@@ -37,7 +37,7 @@
fun test_regression01() {
setUpTest(orientation).apply {
val items = listOf("49", "51").toMutableList()
- setAdapterSync(adapterProvider(items))
+ setAdapterSync(adapterProvider.provider(items))
assertBasicState(0, items[0])
viewPager.post {
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DisableUserInputTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DisableUserInputTest.kt
similarity index 93%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/DisableUserInputTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DisableUserInputTest.kt
index fb2abd3..97443aa 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DisableUserInputTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DisableUserInputTest.kt
@@ -61,21 +61,22 @@
private lateinit var test: Context
private lateinit var adapterProvider: AdapterProvider
- private val touchConsumingViewAdapter: AdapterProviderForItems = { items ->
- {
- object : ViewAdapter(items) {
- override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
- super.onBindViewHolder(holder, position)
- (holder.itemView as TouchConsumingTextView).consumeTouches =
+ private val touchConsumingViewAdapter =
+ AdapterProviderForItems("touchConsumingViewAdapter") { items ->
+ {
+ object : ViewAdapter(items) {
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ super.onBindViewHolder(holder, position)
+ (holder.itemView as TouchConsumingTextView).consumeTouches =
config.childViewConsumesTouches
+ }
}
}
}
- }
override fun setUp() {
super.setUp()
- adapterProvider = touchConsumingViewAdapter(stringSequence(pageCount))
+ adapterProvider = touchConsumingViewAdapter.provider(stringSequence(pageCount))
test = setUpTest(config.orientation).also {
it.viewPager.isUserInputEnabled = false
it.setAdapterSync(adapterProvider)
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DragWhileSmoothScrollTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DragWhileSmoothScrollTest.kt
similarity index 99%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/DragWhileSmoothScrollTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DragWhileSmoothScrollTest.kt
index 0446457..5b9266c 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DragWhileSmoothScrollTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DragWhileSmoothScrollTest.kt
@@ -73,7 +73,7 @@
assertThat(config.distanceToTargetWhenStartDrag, greaterThan(0f))
val pageCount = max(config.startPage, config.targetPage) + 1
test = setUpTest(config.orientation)
- test.setAdapterSync(viewAdapterProvider(stringSequence(pageCount)))
+ test.setAdapterSync(viewAdapterProvider.provider(stringSequence(pageCount)))
test.viewPager.setCurrentItemSync(config.startPage, false, 2, SECONDS)
var recorder = test.viewPager.addNewRecordingCallback()
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/EditTextFocusTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/EditTextFocusTest.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/EditTextFocusTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/EditTextFocusTest.kt
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FakeDragTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FakeDragTest.kt
similarity index 99%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/FakeDragTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FakeDragTest.kt
index eb6eb42..6ee9599 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FakeDragTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FakeDragTest.kt
@@ -101,7 +101,7 @@
localeUtil.resetLocale()
localeUtil.setLocale(LocaleTestUtils.RTL_LANGUAGE)
}
- adapterProvider = viewAdapterProvider(stringSequence(pageCount))
+ adapterProvider = viewAdapterProvider.provider(stringSequence(pageCount))
test = setUpTest(config.orientation).also {
fakeDragger = PageSwiperFakeDrag(it.viewPager) { it.viewPager.pageSize }
it.viewPager.isUserInputEnabled = config.enableUserInput
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FragmentLifecycleTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FragmentLifecycleTest.kt
similarity index 97%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/FragmentLifecycleTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FragmentLifecycleTest.kt
index 51f84084..71064fd 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FragmentLifecycleTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FragmentLifecycleTest.kt
@@ -57,7 +57,7 @@
fun test_swipeBetweenPages() {
setUpTest(orientation).apply {
val expectedValues = stringSequence(totalPages).toMutableList()
- val adapter = adapterProvider(expectedValues.toList()) // immutable defensive copy
+ val adapter = adapterProvider.provider(expectedValues.toList()) // defensive copy
setAdapterSync(adapter)
var ix = 0
@@ -86,7 +86,7 @@
fun test_setCurrentItem() {
setUpTest(orientation).apply {
val expectedValues = stringSequence(totalPages).toMutableList()
- val adapter = adapterProvider(expectedValues.toList()) // immutable defensive copy
+ val adapter = adapterProvider.provider(expectedValues.toList()) // defensive copy
setAdapterSync(adapter)
performAssertions(expectedValues, 0)
@@ -114,7 +114,7 @@
fun test_dataSetChange() {
setUpTest(orientation).apply {
val items = stringSequence(totalPages).toMutableList()
- setAdapterSync(adapterProvider(items))
+ setAdapterSync(adapterProvider.provider(items))
val adapter = viewPager.adapter!!
performAssertions(items, 0)
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/HostFragmentBackStackTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/HostFragmentBackStackTest.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/HostFragmentBackStackTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/HostFragmentBackStackTest.kt
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ItemDecorationTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ItemDecorationTest.kt
similarity index 98%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/ItemDecorationTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ItemDecorationTest.kt
index a46284a..ed066f6 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ItemDecorationTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ItemDecorationTest.kt
@@ -61,7 +61,7 @@
) {
// given
setUpTest(orientation).run {
- setAdapterSync(adapterProvider(stringSequence(3)))
+ setAdapterSync(adapterProvider.provider(stringSequence(3)))
// sanity checks
assertBasicState(0)
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/MutableCollectionsTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/MutableCollectionsTest.kt
similarity index 99%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/MutableCollectionsTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/MutableCollectionsTest.kt
index ee8c165..c0840ce 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/MutableCollectionsTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/MutableCollectionsTest.kt
@@ -49,7 +49,7 @@
fun test() {
testConfig.apply {
setUpTest(orientation).apply {
- setAdapterSync(adapterProvider(items))
+ setAdapterSync(adapterProvider.provider(items))
verifyViewPagerContent(items) // sanity check
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/OffscreenPageLimitTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/OffscreenPageLimitTest.kt
similarity index 98%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/OffscreenPageLimitTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/OffscreenPageLimitTest.kt
index de156e2..2920809 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/OffscreenPageLimitTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/OffscreenPageLimitTest.kt
@@ -82,7 +82,7 @@
test.viewPager.offscreenPageLimit = config.offscreenPageLimit
}
val recorder = test.viewPager.addNewRecordingCallback()
- test.setAdapterSync(config.adapterProvider(stringSequence(pageCount)))
+ test.setAdapterSync(config.adapterProvider.provider(stringSequence(pageCount)))
// Do not perform self check (which checks number of shown + cached fragments) in
// this test, as that check is not valid in the presence of offscreen page limit
test.assertBasicState(firstPage, performSelfCheck = false)
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/OrientationTest.java b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/OrientationTest.java
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/OrientationTest.java
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/OrientationTest.java
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PaddingMarginDecorationTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PaddingMarginDecorationTest.kt
similarity index 96%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/PaddingMarginDecorationTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PaddingMarginDecorationTest.kt
index 666bbb0..82f3535 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PaddingMarginDecorationTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PaddingMarginDecorationTest.kt
@@ -133,12 +133,12 @@
}
private val adapterProvider: AdapterProviderForItems get() {
- return if (config.itemMarginPx > 0) {
- { items -> { MarginViewAdapter(config.itemMarginPx, items) } }
- } else {
- { items -> { ViewAdapter(items) } }
+ return AdapterProviderForItems("adapterProvider", if (config.itemMarginPx > 0) {
+ { items -> { MarginViewAdapter(config.itemMarginPx, items) } }
+ } else {
+ { items -> { ViewAdapter(items) } }
+ })
}
- }
class MarginViewAdapter(private val margin: Int, items: List<String>) : ViewAdapter(items) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
@@ -186,7 +186,7 @@
@Test
fun test_pageSize() {
- test.setAdapterSync(adapterProvider(stringSequence(1)))
+ test.setAdapterSync(adapterProvider.provider(stringSequence(1)))
val f = if (viewPager.isHorizontal) fLeft + fRight else fTop + fBottom
@@ -232,7 +232,7 @@
*/
@Test
fun test_swipeBetweenPages() {
- test.setAdapterSync(adapterProvider(stringSequence(2)))
+ test.setAdapterSync(adapterProvider.provider(stringSequence(2)))
listOf(1, 0).forEach { targetPage ->
// given
val initialPage = viewPager.currentItem
@@ -292,7 +292,7 @@
val totalPages = 2
val edgePages = setOf(0, totalPages - 1)
- test.setAdapterSync(adapterProvider(stringSequence(totalPages)))
+ test.setAdapterSync(adapterProvider.provider(stringSequence(totalPages)))
listOf(0, 1, 1).forEach { targetPage ->
// given
val initialPage = viewPager.currentItem
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageChangeCallbackTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageChangeCallbackTest.kt
similarity index 97%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageChangeCallbackTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageChangeCallbackTest.kt
index cc4bb92..fe9b258 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageChangeCallbackTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageChangeCallbackTest.kt
@@ -109,7 +109,7 @@
@Test
fun test_swipeBetweenPages() {
setUpTest(config.orientation).apply {
- setAdapterSync(viewAdapterProvider(stringSequence(4)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(4)))
listOf(1, 2, 3, 2, 1, 0).forEach { targetPage ->
// given
val initialPage = viewPager.currentItem
@@ -172,7 +172,7 @@
setUpTest(config.orientation).apply {
- setAdapterSync(viewAdapterProvider(stringSequence(totalPages)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(totalPages)))
listOf(0, 0, 1, 2, 2, 2, 1, 2, 2, 2, 1, 0, 0, 0).forEach { targetPage ->
// given
val initialPage = viewPager.currentItem
@@ -235,7 +235,7 @@
fun test_peekOnAdjacentPage_next() {
// given
setUpTest(config.orientation).apply {
- setAdapterSync(viewAdapterProvider(stringSequence(3)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(3)))
val callback = viewPager.addNewRecordingCallback()
val latch = viewPager.addWaitForScrolledLatch(0)
@@ -294,7 +294,7 @@
fun test_peekOnAdjacentPage_previous() {
// given
setUpTest(config.orientation).apply {
- setAdapterSync(viewAdapterProvider(stringSequence(3)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(3)))
viewPager.setCurrentItemSync(2, false, 1, SECONDS)
@@ -371,7 +371,7 @@
fun test_selectItemProgrammatically_smoothScroll() {
// given
setUpTest(config.orientation).apply {
- setAdapterSync(viewAdapterProvider(stringSequence(1000)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(1000)))
// when
listOf(6, 5, 6, 3, 10, 0, 0, 999, 999, 0).forEach { targetPage ->
@@ -412,7 +412,7 @@
fun test_multiplePageChanges() {
// given
setUpTest(config.orientation).apply {
- setAdapterSync(viewAdapterProvider(stringSequence(10)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(10)))
val targetPages = listOf(4, 9)
val callback = viewPager.addNewRecordingCallback()
val latch = viewPager.addWaitForScrolledLatch(targetPages.last(), true)
@@ -462,7 +462,7 @@
fun test_noSmoothScroll_after_smoothScroll() {
// given
setUpTest(config.orientation).apply {
- setAdapterSync(viewAdapterProvider(stringSequence(6)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(6)))
val targetPage = 4
val marker = 1
val callback = viewPager.addNewRecordingCallback()
@@ -580,7 +580,7 @@
// given
assertThat(targetPage, greaterThanOrEqualTo(4))
setUpTest(config.orientation).apply {
- val adapterProvider = viewAdapterProvider(stringSequence(5))
+ val adapterProvider = viewAdapterProvider.provider(stringSequence(5))
setAdapterSync(adapterProvider)
val marker = 1
val callback = viewPager.addNewRecordingCallback()
@@ -640,7 +640,7 @@
fun test_selectItemProgrammatically_noSmoothScroll() {
// given
setUpTest(config.orientation).apply {
- setAdapterSync(viewAdapterProvider(stringSequence(3)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(3)))
// when
listOf(2, 2, 0, 0, 1, 2, 1, 0).forEach { targetPage ->
@@ -672,7 +672,7 @@
fun test_swipeReleaseSwipeBack() {
// given
val test = setUpTest(config.orientation)
- test.setAdapterSync(viewAdapterProvider(stringSequence(3)))
+ test.setAdapterSync(viewAdapterProvider.provider(stringSequence(3)))
val currentPage = test.viewPager.currentItem
val halfPage = test.viewPager.pageSize / 2f
val pageSwiper = PageSwiperManual(test.viewPager)
@@ -746,7 +746,7 @@
private fun test_selectItemProgrammatically_noCallback(smoothScroll: Boolean) {
// given
setUpTest(config.orientation).apply {
- setAdapterSync(viewAdapterProvider(stringSequence(3)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(3)))
// when
listOf(2, 2, 0, 0, 1, 2, 1, 0).forEach { targetPage ->
@@ -788,7 +788,7 @@
@Test
fun test_getScrollState() {
val test = setUpTest(config.orientation)
- test.setAdapterSync(viewAdapterProvider(stringSequence(5)))
+ test.setAdapterSync(viewAdapterProvider.provider(stringSequence(5)))
// Test SCROLL_STATE_SETTLING
test_getScrollState(test, SCROLL_STATE_SETTLING, 1) {
@@ -852,7 +852,7 @@
// given
val test = setUpTest(config.orientation)
val recorder = test.viewPager.addNewRecordingCallback()
- val adapterProvider = viewAdapterProvider(stringSequence(3))
+ val adapterProvider = viewAdapterProvider.provider(stringSequence(3))
val marker = 1
fun expectedEvents(page: Int): List<Event> {
@@ -901,7 +901,7 @@
private fun test_setCurrentItem_outOfBounds(smoothScroll: Boolean) {
val test = setUpTest(config.orientation)
val n = 3
- test.setAdapterSync(viewAdapterProvider(stringSequence(n)))
+ test.setAdapterSync(viewAdapterProvider.provider(stringSequence(n)))
val adapterCount = test.viewPager.adapter!!.itemCount
listOf(-5, -1, n, n + 1, adapterCount, adapterCount + 1).forEach { targetPage ->
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageFillTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageFillTest.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageFillTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageFillTest.kt
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageTransformerItemAnimatorTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageTransformerItemAnimatorTest.kt
similarity index 97%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageTransformerItemAnimatorTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageTransformerItemAnimatorTest.kt
index 8dc6458..b0504d0 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageTransformerItemAnimatorTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageTransformerItemAnimatorTest.kt
@@ -42,7 +42,7 @@
@Test
fun test() {
setUpTest(ORIENTATION_HORIZONTAL).apply {
- setAdapterSync(viewAdapterProviderValueId(stringSequence(5)))
+ setAdapterSync(viewAdapterProviderValueId.provider(stringSequence(5)))
assertBasicState(0)
val rv = viewPager.getChildAt(0) as RecyclerView
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageTransformerTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageTransformerTest.kt
similarity index 99%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageTransformerTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageTransformerTest.kt
index 4d78da2..85ece6c 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageTransformerTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageTransformerTest.kt
@@ -125,7 +125,7 @@
fun test() {
// given
val test = setUpTest(config.orientation)
- test.setAdapterSync(viewAdapterProvider(stringSequence(100)))
+ test.setAdapterSync(viewAdapterProvider.provider(stringSequence(100)))
// when
config.pageList.forEach { targetPage ->
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/SetItemWhileScrollInProgressTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/SetItemWhileScrollInProgressTest.kt
similarity index 99%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/SetItemWhileScrollInProgressTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/SetItemWhileScrollInProgressTest.kt
index 8d6159b..e45e4d9 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/SetItemWhileScrollInProgressTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/SetItemWhileScrollInProgressTest.kt
@@ -138,7 +138,7 @@
config.apply {
// given
setUpTest(orientation).apply {
- setAdapterSync(viewAdapterProvider(stringSequence(totalPages)))
+ setAdapterSync(viewAdapterProvider.provider(stringSequence(totalPages)))
val callback = viewPager.addNewRecordingCallback()
var currentPage = viewPager.currentItem
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/SwipeTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/SwipeTest.kt
similarity index 98%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/SwipeTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/SwipeTest.kt
index 9cacdcd..91bf776 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/SwipeTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/SwipeTest.kt
@@ -40,7 +40,7 @@
testConfig.apply {
setUpTest(orientation).apply {
val expectedValues = stringSequence(totalPages).toMutableList()
- val adapter = adapterProvider(expectedValues.toList()) // immutable defensive copy
+ val adapter = adapterProvider.provider(expectedValues.toList()) // defensive copy
setAdapterSync(adapter)
assertBasicState(0)
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/TransientStateFragmentTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/TransientStateFragmentTest.kt
similarity index 97%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/TransientStateFragmentTest.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/TransientStateFragmentTest.kt
index ebe5a6a..cb29e66 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/TransientStateFragmentTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/TransientStateFragmentTest.kt
@@ -45,7 +45,7 @@
fun test_swipeBetweenPages() {
setUpTest(orientation).apply {
val expectedValues = stringSequence(totalPages)
- val adapter = adapterProvider(expectedValues)
+ val adapter = adapterProvider.provider(expectedValues)
val fragmentManager = activity.supportFragmentManager
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/BaseActivity.java b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/BaseActivity.java
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/BaseActivity.java
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/BaseActivity.java
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/FragmentAdapter.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/FragmentAdapter.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/FragmentAdapter.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/FragmentAdapter.kt
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/ManualSwipeInjector.java b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/ManualSwipeInjector.java
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/ManualSwipeInjector.java
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/ManualSwipeInjector.java
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiper.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiper.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiper.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiper.kt
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiperEspresso.java b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiperEspresso.java
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiperEspresso.java
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiperEspresso.java
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiperFakeDrag.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiperFakeDrag.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiperFakeDrag.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiperFakeDrag.kt
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiperManual.java b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiperManual.java
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiperManual.java
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiperManual.java
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageView.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageView.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageView.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageView.kt
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/SelfChecking.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/SelfChecking.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/SelfChecking.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/SelfChecking.kt
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/TestActivity.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/TestActivity.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/TestActivity.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/TestActivity.kt
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/TranslatedCoordinatesProvider.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/TranslatedCoordinatesProvider.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/TranslatedCoordinatesProvider.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/TranslatedCoordinatesProvider.kt
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/ViewAdapter.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/ViewAdapter.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/ViewAdapter.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/ViewAdapter.kt
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/WaitForInjectMotionEventsAction.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/WaitForInjectMotionEventsAction.kt
similarity index 100%
rename from viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/WaitForInjectMotionEventsAction.kt
rename to viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/WaitForInjectMotionEventsAction.kt
diff --git a/viewpager2/src/androidTest/res/layout/activity_test_layout.xml b/viewpager2/viewpager2/src/androidTest/res/layout/activity_test_layout.xml
similarity index 100%
rename from viewpager2/src/androidTest/res/layout/activity_test_layout.xml
rename to viewpager2/viewpager2/src/androidTest/res/layout/activity_test_layout.xml
diff --git a/viewpager2/src/androidTest/res/layout/item_test_layout.xml b/viewpager2/viewpager2/src/androidTest/res/layout/item_test_layout.xml
similarity index 100%
rename from viewpager2/src/androidTest/res/layout/item_test_layout.xml
rename to viewpager2/viewpager2/src/androidTest/res/layout/item_test_layout.xml
diff --git a/viewpager2/src/androidTest/res/layout/orientation_default.xml b/viewpager2/viewpager2/src/androidTest/res/layout/orientation_default.xml
similarity index 100%
rename from viewpager2/src/androidTest/res/layout/orientation_default.xml
rename to viewpager2/viewpager2/src/androidTest/res/layout/orientation_default.xml
diff --git a/viewpager2/src/androidTest/res/layout/orientation_horizontal.xml b/viewpager2/viewpager2/src/androidTest/res/layout/orientation_horizontal.xml
similarity index 100%
rename from viewpager2/src/androidTest/res/layout/orientation_horizontal.xml
rename to viewpager2/viewpager2/src/androidTest/res/layout/orientation_horizontal.xml
diff --git a/viewpager2/src/androidTest/res/layout/orientation_vertical.xml b/viewpager2/viewpager2/src/androidTest/res/layout/orientation_vertical.xml
similarity index 100%
rename from viewpager2/src/androidTest/res/layout/orientation_vertical.xml
rename to viewpager2/viewpager2/src/androidTest/res/layout/orientation_vertical.xml
diff --git a/viewpager2/src/androidTest/res/layout/vertical_scrollbars.xml b/viewpager2/viewpager2/src/androidTest/res/layout/vertical_scrollbars.xml
similarity index 100%
rename from viewpager2/src/androidTest/res/layout/vertical_scrollbars.xml
rename to viewpager2/viewpager2/src/androidTest/res/layout/vertical_scrollbars.xml
diff --git a/viewpager2/src/main/AndroidManifest.xml b/viewpager2/viewpager2/src/main/AndroidManifest.xml
similarity index 100%
rename from viewpager2/src/main/AndroidManifest.xml
rename to viewpager2/viewpager2/src/main/AndroidManifest.xml
diff --git a/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentStateAdapter.java b/viewpager2/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentStateAdapter.java
similarity index 99%
rename from viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentStateAdapter.java
rename to viewpager2/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentStateAdapter.java
index b40f192..a616e861 100644
--- a/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentStateAdapter.java
+++ b/viewpager2/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentStateAdapter.java
@@ -473,7 +473,6 @@
/**
* Default implementation works for collections that don't add, move, remove items.
* <p>
- * TODO(b/122670460): add lint rule
* When overriding, also override {@link #containsItem(long)}.
* <p>
* If the item is not a part of the collection, return {@link RecyclerView#NO_ID}.
@@ -481,6 +480,7 @@
* @param position Adapter position
* @return stable item id {@link RecyclerView.Adapter#hasStableIds()}
*/
+ // TODO(b/122670460): add lint rule
@Override
public long getItemId(int position) {
return position;
@@ -489,9 +489,9 @@
/**
* Default implementation works for collections that don't add, move, remove items.
* <p>
- * TODO(b/122670460): add lint rule
* When overriding, also override {@link #getItemId(int)}
*/
+ // TODO(b/122670460): add lint rule
public boolean containsItem(long itemId) {
return itemId >= 0 && itemId < getItemCount();
}
diff --git a/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentViewHolder.java b/viewpager2/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentViewHolder.java
similarity index 100%
rename from viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentViewHolder.java
rename to viewpager2/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentViewHolder.java
diff --git a/viewpager2/src/main/java/androidx/viewpager2/adapter/StatefulAdapter.java b/viewpager2/viewpager2/src/main/java/androidx/viewpager2/adapter/StatefulAdapter.java
similarity index 100%
rename from viewpager2/src/main/java/androidx/viewpager2/adapter/StatefulAdapter.java
rename to viewpager2/viewpager2/src/main/java/androidx/viewpager2/adapter/StatefulAdapter.java
diff --git a/viewpager2/src/main/java/androidx/viewpager2/widget/AnimateLayoutChangeDetector.java b/viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/AnimateLayoutChangeDetector.java
similarity index 100%
rename from viewpager2/src/main/java/androidx/viewpager2/widget/AnimateLayoutChangeDetector.java
rename to viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/AnimateLayoutChangeDetector.java
diff --git a/viewpager2/src/main/java/androidx/viewpager2/widget/CompositeOnPageChangeCallback.java b/viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/CompositeOnPageChangeCallback.java
similarity index 100%
rename from viewpager2/src/main/java/androidx/viewpager2/widget/CompositeOnPageChangeCallback.java
rename to viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/CompositeOnPageChangeCallback.java
diff --git a/viewpager2/src/main/java/androidx/viewpager2/widget/CompositePageTransformer.java b/viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/CompositePageTransformer.java
similarity index 100%
rename from viewpager2/src/main/java/androidx/viewpager2/widget/CompositePageTransformer.java
rename to viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/CompositePageTransformer.java
diff --git a/viewpager2/src/main/java/androidx/viewpager2/widget/FakeDrag.java b/viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/FakeDrag.java
similarity index 100%
rename from viewpager2/src/main/java/androidx/viewpager2/widget/FakeDrag.java
rename to viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/FakeDrag.java
diff --git a/viewpager2/src/main/java/androidx/viewpager2/widget/MarginPageTransformer.java b/viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/MarginPageTransformer.java
similarity index 100%
rename from viewpager2/src/main/java/androidx/viewpager2/widget/MarginPageTransformer.java
rename to viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/MarginPageTransformer.java
diff --git a/viewpager2/src/main/java/androidx/viewpager2/widget/PageTransformerAdapter.java b/viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/PageTransformerAdapter.java
similarity index 100%
rename from viewpager2/src/main/java/androidx/viewpager2/widget/PageTransformerAdapter.java
rename to viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/PageTransformerAdapter.java
diff --git a/viewpager2/src/main/java/androidx/viewpager2/widget/ScrollEventAdapter.java b/viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/ScrollEventAdapter.java
similarity index 100%
rename from viewpager2/src/main/java/androidx/viewpager2/widget/ScrollEventAdapter.java
rename to viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/ScrollEventAdapter.java
diff --git a/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java b/viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
similarity index 99%
rename from viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
rename to viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
index e69087b..32bdc64 100644
--- a/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
+++ b/viewpager2/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
@@ -582,8 +582,6 @@
* the current item and the specified item. Silently ignored if the adapter is not set or
* empty. Clamps item to the bounds of the adapter.
*
- * TODO(b/123069219): verify first layout behavior
- *
* @param item Item index to select
*/
public void setCurrentItem(int item) {
diff --git a/viewpager2/src/main/res/values/attrs.xml b/viewpager2/viewpager2/src/main/res/values/attrs.xml
similarity index 100%
rename from viewpager2/src/main/res/values/attrs.xml
rename to viewpager2/viewpager2/src/main/res/values/attrs.xml
diff --git a/work/workmanager-benchmark/build.gradle b/work/workmanager-benchmark/build.gradle
index 8dd3ba4..4c74f21 100644
--- a/work/workmanager-benchmark/build.gradle
+++ b/work/workmanager-benchmark/build.gradle
@@ -32,7 +32,7 @@
dependencies {
androidTestImplementation(project(':work:work-runtime-ktx'))
androidTestImplementation(project(":benchmark:benchmark-junit4"))
- androidTestImplementation("androidx.room:room-runtime:2.2.2")
+ androidTestImplementation("androidx.room:room-runtime:2.2.3")
androidTestImplementation(JUNIT)
androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
androidTestImplementation(ANDROIDX_TEST_CORE)
diff --git a/work/workmanager-gcm/build.gradle b/work/workmanager-gcm/build.gradle
index f960dec..e7f4a95 100644
--- a/work/workmanager-gcm/build.gradle
+++ b/work/workmanager-gcm/build.gradle
@@ -51,9 +51,9 @@
implementation(project(":room:room-runtime"))
androidTestImplementation(project(":room:room-testing"))
} else {
- annotationProcessor("androidx.room:room-compiler:2.2.2")
- implementation("androidx.room:room-runtime:2.2.2")
- androidTestImplementation("androidx.room:room-testing:2.2.2")
+ annotationProcessor("androidx.room:room-compiler:2.2.3")
+ implementation("androidx.room:room-runtime:2.2.3")
+ androidTestImplementation("androidx.room:room-testing:2.2.3")
}
androidTestImplementation(project(":work:work-runtime-ktx"))
diff --git a/work/workmanager-ktx/build.gradle b/work/workmanager-ktx/build.gradle
index e515cec..25ad0d8c 100644
--- a/work/workmanager-ktx/build.gradle
+++ b/work/workmanager-ktx/build.gradle
@@ -53,7 +53,7 @@
androidTestImplementation(ESPRESSO_CORE)
androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has its own MockMaker
androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has its own MockMaker
- androidTestImplementation("androidx.room:room-testing:2.2.2")
+ androidTestImplementation("androidx.room:room-testing:2.2.3")
testImplementation(JUNIT)
}
diff --git a/work/workmanager-testing/build.gradle b/work/workmanager-testing/build.gradle
index 84b62ad..42f84b7 100644
--- a/work/workmanager-testing/build.gradle
+++ b/work/workmanager-testing/build.gradle
@@ -38,7 +38,7 @@
dependencies {
api(project(':work:work-runtime-ktx'))
implementation("androidx.lifecycle:lifecycle-livedata-core:2.1.0")
- implementation("androidx.room:room-runtime:2.2.2")
+ implementation("androidx.room:room-runtime:2.2.3")
androidTestImplementation("androidx.arch.core:core-testing:2.1.0")
androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/work/workmanager/api/2.4.0-alpha01.txt b/work/workmanager/api/2.4.0-alpha01.txt
index 0ecdec1..105417e 100644
--- a/work/workmanager/api/2.4.0-alpha01.txt
+++ b/work/workmanager/api/2.4.0-alpha01.txt
@@ -120,6 +120,7 @@
public enum ExistingWorkPolicy {
enum_constant public static final androidx.work.ExistingWorkPolicy APPEND;
+ enum_constant public static final androidx.work.ExistingWorkPolicy APPEND_OR_REPLACE;
enum_constant public static final androidx.work.ExistingWorkPolicy KEEP;
enum_constant public static final androidx.work.ExistingWorkPolicy REPLACE;
}
diff --git a/work/workmanager/api/current.txt b/work/workmanager/api/current.txt
index 0ecdec1..105417e 100644
--- a/work/workmanager/api/current.txt
+++ b/work/workmanager/api/current.txt
@@ -120,6 +120,7 @@
public enum ExistingWorkPolicy {
enum_constant public static final androidx.work.ExistingWorkPolicy APPEND;
+ enum_constant public static final androidx.work.ExistingWorkPolicy APPEND_OR_REPLACE;
enum_constant public static final androidx.work.ExistingWorkPolicy KEEP;
enum_constant public static final androidx.work.ExistingWorkPolicy REPLACE;
}
diff --git a/work/workmanager/api/public_plus_experimental_2.4.0-alpha01.txt b/work/workmanager/api/public_plus_experimental_2.4.0-alpha01.txt
index 0ecdec1..105417e 100644
--- a/work/workmanager/api/public_plus_experimental_2.4.0-alpha01.txt
+++ b/work/workmanager/api/public_plus_experimental_2.4.0-alpha01.txt
@@ -120,6 +120,7 @@
public enum ExistingWorkPolicy {
enum_constant public static final androidx.work.ExistingWorkPolicy APPEND;
+ enum_constant public static final androidx.work.ExistingWorkPolicy APPEND_OR_REPLACE;
enum_constant public static final androidx.work.ExistingWorkPolicy KEEP;
enum_constant public static final androidx.work.ExistingWorkPolicy REPLACE;
}
diff --git a/work/workmanager/api/public_plus_experimental_current.txt b/work/workmanager/api/public_plus_experimental_current.txt
index 0ecdec1..105417e 100644
--- a/work/workmanager/api/public_plus_experimental_current.txt
+++ b/work/workmanager/api/public_plus_experimental_current.txt
@@ -120,6 +120,7 @@
public enum ExistingWorkPolicy {
enum_constant public static final androidx.work.ExistingWorkPolicy APPEND;
+ enum_constant public static final androidx.work.ExistingWorkPolicy APPEND_OR_REPLACE;
enum_constant public static final androidx.work.ExistingWorkPolicy KEEP;
enum_constant public static final androidx.work.ExistingWorkPolicy REPLACE;
}
diff --git a/work/workmanager/build.gradle b/work/workmanager/build.gradle
index 1c15e53..48a698e 100644
--- a/work/workmanager/build.gradle
+++ b/work/workmanager/build.gradle
@@ -62,9 +62,11 @@
}
dependencies {
- annotationProcessor("androidx.room:room-compiler:2.2.2")
- implementation("androidx.room:room-runtime:2.2.2")
- androidTestImplementation("androidx.room:room-testing:2.2.2")
+ annotationProcessor("androidx.room:room-compiler:2.2.3")
+ implementation("androidx.room:room-runtime:2.2.3")
+ androidTestImplementation("androidx.room:room-testing:2.2.3")
+ implementation("androidx.sqlite:sqlite:2.1.0-rc01")
+ implementation("androidx.sqlite:sqlite-framework:2.1.0-rc01")
api(GUAVA_LISTENABLE_FUTURE)
api("androidx.lifecycle:lifecycle-livedata:2.1.0")
implementation("androidx.core:core:1.1.0")
diff --git a/work/workmanager/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java b/work/workmanager/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
index f7b9e13..32f50ab 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
@@ -17,6 +17,7 @@
package androidx.work.impl;
import static androidx.work.ExistingWorkPolicy.APPEND;
+import static androidx.work.ExistingWorkPolicy.APPEND_OR_REPLACE;
import static androidx.work.ExistingWorkPolicy.KEEP;
import static androidx.work.ExistingWorkPolicy.REPLACE;
import static androidx.work.NetworkType.METERED;
@@ -908,6 +909,110 @@
@Test
@MediumTest
+ public void testBeginUniqueWork_insertsWithAppendOrReplaceWithFailedPreRequisites()
+ throws ExecutionException, InterruptedException {
+
+ when(mWorkManagerImpl.getSchedulers()).thenReturn(Collections.<Scheduler>emptyList());
+ final String uniqueName = "myname";
+ OneTimeWorkRequest preRequisiteRequest = new OneTimeWorkRequest.Builder(TestWorker.class)
+ .setInitialState(FAILED)
+ .build();
+
+ mWorkManagerImpl.beginUniqueWork(uniqueName, APPEND_OR_REPLACE, preRequisiteRequest)
+ .enqueue()
+ .getResult()
+ .get();
+
+ OneTimeWorkRequest appendRequest = new OneTimeWorkRequest.Builder(TestWorker.class)
+ .build();
+
+ mWorkManagerImpl.beginUniqueWork(uniqueName, APPEND_OR_REPLACE, appendRequest)
+ .enqueue()
+ .getResult()
+ .get();
+
+ WorkSpecDao workSpecDao = mDatabase.workSpecDao();
+ DependencyDao dependencyDao = mDatabase.dependencyDao();
+
+ WorkSpec deleted = workSpecDao.getWorkSpec(preRequisiteRequest.getStringId());
+ assertThat(deleted, is(nullValue()));
+ WorkSpec appended = workSpecDao.getWorkSpec(appendRequest.getStringId());
+ List<String> preRequisites = dependencyDao.getPrerequisites(appendRequest.getStringId());
+ assertThat(appended.state, is(ENQUEUED));
+ assertThat(preRequisites.size(), is(0));
+ }
+
+ @Test
+ @MediumTest
+ public void testBeginUniqueWork_insertsWithAppendOrReplaceWithCancelledPreRequisites()
+ throws ExecutionException, InterruptedException {
+
+ when(mWorkManagerImpl.getSchedulers()).thenReturn(Collections.<Scheduler>emptyList());
+ final String uniqueName = "myname";
+ OneTimeWorkRequest preRequisiteRequest = new OneTimeWorkRequest.Builder(TestWorker.class)
+ .setInitialState(CANCELLED)
+ .build();
+
+ mWorkManagerImpl.beginUniqueWork(uniqueName, APPEND_OR_REPLACE, preRequisiteRequest)
+ .enqueue()
+ .getResult()
+ .get();
+
+ OneTimeWorkRequest appendRequest = new OneTimeWorkRequest.Builder(TestWorker.class)
+ .build();
+
+ mWorkManagerImpl.beginUniqueWork(uniqueName, APPEND_OR_REPLACE, appendRequest)
+ .enqueue()
+ .getResult()
+ .get();
+
+ WorkSpecDao workSpecDao = mDatabase.workSpecDao();
+ DependencyDao dependencyDao = mDatabase.dependencyDao();
+
+ WorkSpec deleted = workSpecDao.getWorkSpec(preRequisiteRequest.getStringId());
+ assertThat(deleted, is(nullValue()));
+ WorkSpec appended = workSpecDao.getWorkSpec(appendRequest.getStringId());
+ List<String> preRequisites = dependencyDao.getPrerequisites(appendRequest.getStringId());
+ assertThat(appended.state, is(ENQUEUED));
+ assertThat(preRequisites.size(), is(0));
+ }
+
+ @Test
+ @MediumTest
+ public void testBeginUniqueWork_appendsWork_whenUsingAppendOrReplace()
+ throws ExecutionException, InterruptedException {
+
+ when(mWorkManagerImpl.getSchedulers()).thenReturn(Collections.<Scheduler>emptyList());
+ final String uniqueName = "myname";
+ OneTimeWorkRequest preRequisiteRequest = new OneTimeWorkRequest.Builder(TestWorker.class)
+ .build();
+
+ mWorkManagerImpl.beginUniqueWork(uniqueName, APPEND_OR_REPLACE, preRequisiteRequest)
+ .enqueue()
+ .getResult()
+ .get();
+
+ OneTimeWorkRequest appendRequest = new OneTimeWorkRequest.Builder(TestWorker.class)
+ .build();
+
+ mWorkManagerImpl.beginUniqueWork(uniqueName, APPEND_OR_REPLACE, appendRequest)
+ .enqueue()
+ .getResult()
+ .get();
+
+ WorkSpecDao workSpecDao = mDatabase.workSpecDao();
+ DependencyDao dependencyDao = mDatabase.dependencyDao();
+
+ WorkSpec preRequisite = workSpecDao.getWorkSpec(preRequisiteRequest.getStringId());
+ WorkSpec appended = workSpecDao.getWorkSpec(appendRequest.getStringId());
+ List<String> preRequisites = dependencyDao.getPrerequisites(appendRequest.getStringId());
+ assertThat(appended.state, is(BLOCKED));
+ assertThat(preRequisites.size(), is(1));
+ assertThat(preRequisites, containsInAnyOrder(preRequisite.id));
+ }
+
+ @Test
+ @MediumTest
public void testBeginUniqueWork_insertsExistingWorkWhenNothingToAppendTo()
throws ExecutionException, InterruptedException {
diff --git a/work/workmanager/src/main/java/androidx/work/Data.java b/work/workmanager/src/main/java/androidx/work/Data.java
index f18dfd6..19f52f2 100644
--- a/work/workmanager/src/main/java/androidx/work/Data.java
+++ b/work/workmanager/src/main/java/androidx/work/Data.java
@@ -343,9 +343,8 @@
* {@link #MAX_DATA_BYTES}
*/
@NonNull
- @SuppressWarnings("AmbiguousMethodReference")
public byte[] toByteArray() {
- return Data.toByteArray(this);
+ return Data.toByteArrayInternal(this);
}
/**
@@ -384,7 +383,7 @@
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@TypeConverter
- public static @NonNull byte[] toByteArray(@NonNull Data data) {
+ public static @NonNull byte[] toByteArrayInternal(@NonNull Data data) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = null;
try {
@@ -843,7 +842,7 @@
Data data = new Data(mValues);
// Make sure we catch Data objects that are too large at build() instead of later. This
// method will throw an exception if data is too big.
- Data.toByteArray(data);
+ Data.toByteArrayInternal(data);
return data;
}
}
diff --git a/work/workmanager/src/main/java/androidx/work/ExistingWorkPolicy.java b/work/workmanager/src/main/java/androidx/work/ExistingWorkPolicy.java
index eb2a507..5161c30 100644
--- a/work/workmanager/src/main/java/androidx/work/ExistingWorkPolicy.java
+++ b/work/workmanager/src/main/java/androidx/work/ExistingWorkPolicy.java
@@ -39,6 +39,20 @@
* If there is existing pending (uncompleted) work with the same unique name, append the
* newly-specified work as a child of all the leaves of that work sequence. Otherwise, insert
* the newly-specified work as the start of a new sequence.
+ * <br/>
+ * <b>Note:</b> When using APPEND with failed or cancelled prerequisites, newly enqueued work
+ * will also be marked as failed or cancelled respectively. Use
+ * {@link ExistingWorkPolicy#APPEND_OR_REPLACE} to create a new chain of work.
*/
- APPEND
+ APPEND,
+
+ /**
+ * If there is existing pending (uncompleted) work with the same unique name, append the
+ * newly-specified work as the child of all the leaves of that work sequence. Otherwise, insert
+ * the newly-specified work as the start of a new sequence.
+ * <br/>
+ * <b>Note:</b> If there are failed or cancelled prerequisites, these prerequisites are
+ * <i>dropped</i> and the newly-specified work is the start of a new sequence.
+ */
+ APPEND_OR_REPLACE,
}
diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java
index aa4c086..83a9ff9 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java
@@ -36,6 +36,8 @@
import androidx.room.RoomDatabase;
import androidx.room.TypeConverters;
import androidx.sqlite.db.SupportSQLiteDatabase;
+import androidx.sqlite.db.SupportSQLiteOpenHelper;
+import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory;
import androidx.work.Data;
import androidx.work.impl.model.Dependency;
import androidx.work.impl.model.DependencyDao;
@@ -100,7 +102,7 @@
*/
@NonNull
public static WorkDatabase create(
- @NonNull Context context,
+ @NonNull final Context context,
@NonNull Executor queryExecutor,
boolean useTestDatabase) {
RoomDatabase.Builder<WorkDatabase> builder;
@@ -108,8 +110,23 @@
builder = Room.inMemoryDatabaseBuilder(context, WorkDatabase.class)
.allowMainThreadQueries();
} else {
- String path = WorkDatabasePathHelper.getDatabasePath(context).getPath();
- builder = Room.databaseBuilder(context, WorkDatabase.class, path);
+ String name = WorkDatabasePathHelper.getWorkDatabaseName();
+ builder = Room.databaseBuilder(context, WorkDatabase.class, name);
+ builder.openHelperFactory(new SupportSQLiteOpenHelper.Factory() {
+ @NonNull
+ @Override
+ public SupportSQLiteOpenHelper create(
+ @NonNull SupportSQLiteOpenHelper.Configuration configuration) {
+ SupportSQLiteOpenHelper.Configuration.Builder configBuilder =
+ SupportSQLiteOpenHelper.Configuration.builder(context);
+ configBuilder.name(configuration.name)
+ .callback(configuration.callback)
+ .noBackupDirectory(true);
+ FrameworkSQLiteOpenHelperFactory factory =
+ new FrameworkSQLiteOpenHelperFactory();
+ return factory.create(configBuilder.build());
+ }
+ });
}
return builder.setQueryExecutor(queryExecutor)
diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabasePathHelper.java b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabasePathHelper.java
index aafcb32..0b4bf2b 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabasePathHelper.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabasePathHelper.java
@@ -47,26 +47,11 @@
private static final String[] DATABASE_EXTRA_FILES = new String[]{"-journal", "-shm", "-wal"};
/**
- * @param context The application {@link Context}
- * @return The database path before migration to the no-backup directory.
+ * @return The name of the database.
*/
@NonNull
- public static File getDefaultDatabasePath(@NonNull Context context) {
- return context.getDatabasePath(WORK_DATABASE_NAME);
- }
-
- /**
- * @param context The application {@link Context}
- * @return The the migrated database path.
- */
- @NonNull
- public static File getDatabasePath(@NonNull Context context) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- // No notion of a backup directory exists.
- return getDefaultDatabasePath(context);
- } else {
- return getNoBackupPath(context, WORK_DATABASE_NAME);
- }
+ public static String getWorkDatabaseName() {
+ return WORK_DATABASE_NAME;
}
/**
@@ -123,6 +108,31 @@
}
/**
+ * @param context The application {@link Context}
+ * @return The database path before migration to the no-backup directory.
+ */
+ @NonNull
+ @VisibleForTesting
+ public static File getDefaultDatabasePath(@NonNull Context context) {
+ return context.getDatabasePath(WORK_DATABASE_NAME);
+ }
+
+ /**
+ * @param context The application {@link Context}
+ * @return The the migrated database path.
+ */
+ @NonNull
+ @VisibleForTesting
+ public static File getDatabasePath(@NonNull Context context) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ // No notion of a backup directory exists.
+ return getDefaultDatabasePath(context);
+ } else {
+ return getNoBackupPath(context, WORK_DATABASE_NAME);
+ }
+ }
+
+ /**
* Return the path for a {@link File} path in the {@link Context#getNoBackupFilesDir()}
* identified by the {@link String} fragment.
*
diff --git a/work/workmanager/src/main/java/androidx/work/impl/utils/EnqueueRunnable.java b/work/workmanager/src/main/java/androidx/work/impl/utils/EnqueueRunnable.java
index 82c885b..31a703f 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/utils/EnqueueRunnable.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/utils/EnqueueRunnable.java
@@ -17,6 +17,7 @@
package androidx.work.impl.utils;
import static androidx.work.ExistingWorkPolicy.APPEND;
+import static androidx.work.ExistingWorkPolicy.APPEND_OR_REPLACE;
import static androidx.work.ExistingWorkPolicy.KEEP;
import static androidx.work.WorkInfo.State.BLOCKED;
import static androidx.work.WorkInfo.State.CANCELLED;
@@ -56,6 +57,7 @@
import androidx.work.impl.workers.ConstraintTrackingWorker;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -224,7 +226,7 @@
if (!existingWorkSpecIdAndStates.isEmpty()) {
// If appending, these are the new prerequisites.
- if (existingWorkPolicy == APPEND) {
+ if (existingWorkPolicy == APPEND || existingWorkPolicy == APPEND_OR_REPLACE) {
DependencyDao dependencyDao = workDatabase.dependencyDao();
List<String> newPrerequisiteIds = new ArrayList<>();
for (WorkSpec.IdAndState idAndState : existingWorkSpecIdAndStates) {
@@ -238,6 +240,21 @@
newPrerequisiteIds.add(idAndState.id);
}
}
+ if (existingWorkPolicy == APPEND_OR_REPLACE) {
+ if (hasCancelledPrerequisites || hasFailedPrerequisites) {
+ // Delete all WorkSpecs with this name
+ WorkSpecDao workSpecDao = workDatabase.workSpecDao();
+ List<WorkSpec.IdAndState> idAndStates =
+ workSpecDao.getWorkSpecIdAndStatesForName(name);
+ for (WorkSpec.IdAndState idAndState : idAndStates) {
+ workSpecDao.delete(idAndState.id);
+ }
+ // Treat this as a new chain of work.
+ newPrerequisiteIds = Collections.emptyList();
+ hasCancelledPrerequisites = false;
+ hasFailedPrerequisites = false;
+ }
+ }
prerequisiteIds = newPrerequisiteIds.toArray(prerequisiteIds);
hasPrerequisite = (prerequisiteIds.length > 0);
} else {
diff --git a/work/workmanager/src/test/java/androidx/work/DataTest.java b/work/workmanager/src/test/java/androidx/work/DataTest.java
index 3019697..e31ffbc 100644
--- a/work/workmanager/src/test/java/androidx/work/DataTest.java
+++ b/work/workmanager/src/test/java/androidx/work/DataTest.java
@@ -80,7 +80,7 @@
.putIntArray(KEY2, expectedValue2)
.build();
- byte[] byteArray = Data.toByteArray(data);
+ byte[] byteArray = Data.toByteArrayInternal(data);
Data restoredData = Data.fromByteArray(byteArray);
assertThat(restoredData, is(notNullValue()));