Merge "No functional changes, just an effort to cleanup some code to decrease complexity." into oc-mr1-jetpack-dev
diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml
index 69b75b4..d6a1399 100644
--- a/.idea/codeStyleSettings.xml
+++ b/.idea/codeStyleSettings.xml
@@ -91,6 +91,13 @@
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
+ <JetCodeStyleSettings>
+ <option name="PACKAGES_TO_USE_STAR_IMPORTS">
+ <value />
+ </option>
+ <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
+ <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
+ </JetCodeStyleSettings>
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
@@ -305,9 +312,14 @@
</rules>
</arrangement>
</codeStyleSettings>
+ <codeStyleSettings language="kotlin">
+ <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+ <option name="CALL_PARAMETERS_WRAP" value="1" />
+ <option name="METHOD_PARAMETERS_WRAP" value="5" />
+ <option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
+ </codeStyleSettings>
</value>
</option>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
- <option name="PREFERRED_PROJECT_CODE_STYLE" value="AndroidStyle" />
</component>
</project>
\ No newline at end of file
diff --git a/OWNERS b/OWNERS
index 049932f..0de3634 100644
--- a/OWNERS
+++ b/OWNERS
@@ -5,6 +5,7 @@
clarabayarri@google.com
ilake@google.com
kirillg@google.com
+kkam@google.com
mount@google.com
sergeyv@google.com
yboyar@google.com
\ No newline at end of file
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index ecc61dd..7a349d5 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,5 +1,6 @@
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT} -c ${REPO_ROOT}/frameworks/support/development/checkstyle/config/support-lib.xml -p development/checkstyle/prebuilt/com.android.support.checkstyle.jar
+ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES}
[Builtin Hooks]
commit_msg_changeid_field = true
diff --git a/annotations/src/main/java/android/support/annotation/IntDef.java b/annotations/src/main/java/android/support/annotation/IntDef.java
index f621b7f..9945726 100644
--- a/annotations/src/main/java/android/support/annotation/IntDef.java
+++ b/annotations/src/main/java/android/support/annotation/IntDef.java
@@ -46,12 +46,14 @@
* flag = true,
* value = {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
* </code></pre>
+ *
+ * @see LongDef
*/
@Retention(SOURCE)
@Target({ANNOTATION_TYPE})
public @interface IntDef {
/** Defines the allowed constants for this element */
- long[] value() default {};
+ int[] value() default {};
/** Defines whether the constants can be used as a flag, or just as an enum (the default) */
boolean flag() default false;
diff --git a/annotations/src/main/java/android/support/annotation/LongDef.java b/annotations/src/main/java/android/support/annotation/LongDef.java
new file mode 100644
index 0000000..3dea338
--- /dev/null
+++ b/annotations/src/main/java/android/support/annotation/LongDef.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 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 android.support.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that the annotated long element represents
+ * a logical type and that its value should be one of the explicitly
+ * named constants. If the LongDef#flag() attribute is set to true,
+ * multiple constants can be combined.
+ * <p>
+ * Example:
+ * <pre><code>
+ * @Retention(SOURCE)
+ * @LongDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
+ * public @interface NavigationMode {}
+ * public static final long NAVIGATION_MODE_STANDARD = 0;
+ * public static final long NAVIGATION_MODE_LIST = 1;
+ * public static final long NAVIGATION_MODE_TABS = 2;
+ * ...
+ * public abstract void setNavigationMode(@NavigationMode long mode);
+ * @NavigationMode
+ * public abstract long getNavigationMode();
+ * </code></pre>
+ * For a flag, set the flag attribute:
+ * <pre><code>
+ * @LongDef(
+ * flag = true,
+ * value = {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
+ * </code></pre>
+ *
+ * @see IntDef
+ */
+@Retention(SOURCE)
+@Target({ANNOTATION_TYPE})
+public @interface LongDef {
+ /** Defines the allowed constants for this element */
+ long[] value() default {};
+
+ /** Defines whether the constants can be used as a flag, or just as an enum (the default) */
+ boolean flag() default false;
+}
\ No newline at end of file
diff --git a/app-toolkit/common/build.gradle b/app-toolkit/common/build.gradle
index 9604210..bd10317 100644
--- a/app-toolkit/common/build.gradle
+++ b/app-toolkit/common/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
import android.support.SupportLibraryExtension;
@@ -25,12 +26,10 @@
dependencies {
compile libs.support.annotations
- testCompile libs.junit
- testCompile libs.mockito_core
+ testCompile(JUNIT)
+ testCompile(MOCKITO_CORE)
}
-createAndroidCheckstyle(project)
-
supportLibrary {
name = "Android Arch-Common"
publish = true
diff --git a/app-toolkit/core-testing/build.gradle b/app-toolkit/core-testing/build.gradle
index adb93e6..dca8810 100644
--- a/app-toolkit/core-testing/build.gradle
+++ b/app-toolkit/core-testing/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
import android.support.SupportLibraryExtension
@@ -29,21 +30,18 @@
}
dependencies {
- api project(":arch:runtime")
+ api(project(":arch:runtime"))
api libs.support.annotations
- api libs.junit
- api libs.mockito_core, { exclude group: 'net.bytebuddy' }
+ api(JUNIT)
+ api(MOCKITO_CORE, libs.exclude_bytebuddy)
- testImplementation libs.junit
- testImplementation libs.support.annotations
+ testImplementation(JUNIT)
- androidTestImplementation libs.junit
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
+ androidTestImplementation(JUNIT)
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
}
-createAndroidCheckstyle(project)
-
supportLibrary {
name = "Android Core-Testing"
publish = true
diff --git a/app-toolkit/dependencies.gradle b/app-toolkit/dependencies.gradle
index e760149..b794c10 100644
--- a/app-toolkit/dependencies.gradle
+++ b/app-toolkit/dependencies.gradle
@@ -22,33 +22,7 @@
ffLibs = libs
}
def ffVersions = [:]
-ffVersions.kotlin = "1.1.51"
-ffVersions.auto_common = "0.6"
-ffVersions.javapoet = "1.8.0"
-ffVersions.compile_testing = "0.11"
ffVersions.support_lib = "26.1.0"
-ffVersions.intellij_annotations = "12.0"
-ffVersions.rxjava2 = "2.0.6"
-ffVersions.reactivestreams = "1.0.0"
-// this Xerial version is newer than we want but we need it to fix
-// https://github.com/xerial/sqlite-jdbc/issues/97
-// https://github.com/xerial/sqlite-jdbc/issues/267
-ffVersions.xerial = "3.20.1"
-ffVersions.antlr = "4.5.3"
-ffVersions.commons_codec = "1.10"
-ffVersions.gson = "2.8.0"
-ffVersions.guava = "21.0"
-ffVersions.jsr250 = "1.2"
-
-ffLibs.kotlin = [
- stdlib : "org.jetbrains.kotlin:kotlin-stdlib:$ffVersions.kotlin",
-]
-ffLibs.auto_common = "com.google.auto:auto-common:$ffVersions.auto_common"
-ffLibs.apache = [
- commons : [
- codec : "commons-codec:commons-codec:$ffVersions.commons_codec"
- ]
-]
def getSupportLib(String name, String version, String artifactName = null) {
def sourceProject = findProject(name)
@@ -74,17 +48,6 @@
exclude group: 'android.arch.lifecycle'
}
-ffLibs.javapoet = "com.squareup:javapoet:$ffVersions.javapoet"
-ffLibs.antlr = "org.antlr:antlr4:$ffVersions.antlr"
-ffLibs.xerial = "org.xerial:sqlite-jdbc:$ffVersions.xerial"
-ffLibs.google_compile_testing = "com.google.testing.compile:compile-testing:$ffVersions.compile_testing"
-ffLibs.ij_annotations = "com.intellij:annotations:$ffVersions.intellij_annotations"
-ffLibs.reactive_streams = "org.reactivestreams:reactive-streams:$ffVersions.reactivestreams"
-ffLibs.rx_java = "io.reactivex.rxjava2:rxjava:$ffVersions.rxjava2"
-ffLibs.gson = "com.google.code.gson:gson:$ffVersions.gson"
-ffLibs.guava= "com.google.guava:guava:$ffVersions.guava"
-ffLibs.jsr250 = "javax.annotation:javax.annotation-api:$ffVersions.jsr250"
-
ext.tools = [:]
ext.tools.current_sdk = gradle.ext.currentSdk
ext.tools.build_tools_version = rootProject.ext.buildToolsVersion
diff --git a/app-toolkit/init.gradle b/app-toolkit/init.gradle
index 1d6b752..3e20eaa 100644
--- a/app-toolkit/init.gradle
+++ b/app-toolkit/init.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import android.support.DacOptions
import android.support.LibraryVersions
import org.gradle.internal.os.OperatingSystem
@@ -67,10 +68,7 @@
if (ext.inAppToolkitProject) {
// always build offline docs for flatfoot specific builds.
- ext.docs.dac = [
- libraryroot: "android/arch",
- dataname: "ARCH_DATA"
- ]
+ ext.docsDac = new DacOptions("android/arch", "ARCH_DATA")
repos.addMavenRepositories(repositories)
init.setupRepoOutAndBuildNumber()
init.configureSubProjects()
@@ -110,21 +108,6 @@
task.enabled = false
}
}
- } else {
- def checkApi = project.tasks.create("checkVersion") {
- doFirst {
- if (project.version == null
- || project.version == LibraryVersions.SUPPORT_LIBRARY.toString()) {
- throw new GradleException("bad version for $project with $project.version")
- }
- }
- }
-
- project.tasks.whenTaskAdded { task ->
- if (task instanceof Upload) {
- task.dependsOn checkApi
- }
- }
}
project.tasks.whenTaskAdded { task ->
@@ -136,69 +119,3 @@
}
}
}
-
-def createKotlinCheckstyle(Project project) {
- def fs = files();
- if (project.sourceSets.hasProperty('main')) {
- fs += files(project.sourceSets.main.allJava.srcDirs.collect { fileTree(it) })
- }
- if (project.sourceSets.hasProperty('test')) {
- fs += files(project.sourceSets.test.allJava.srcDirs.collect { fileTree(it) })
- }
- if (project.hasProperty('android')) {
- fs += files(project.android.sourceSets.main.java.getSrcDirs().collect {fileTree(it)})
- fs += files(project.android.sourceSets.test.java.getSrcDirs().collect {fileTree(it)})
- fs += files(project.android.sourceSets.androidTest.java.getSrcDirs().collect {fileTree(it)})
- }
- fs = fs.filter{file -> file.name.endsWith(".kt")}
- def kotlinCheckstyle = createCheckstyleTask(project, 'checkstyleKotlin',
- "${project.rootProject.ext.supportRootFolder}/app-toolkit/kotlin-checkstyle.xml",
- fs.files)
-
- project.tasks.findByName("check").dependsOn(kotlinCheckstyle)
- // poor man's line length check
- def lineCheck = project.tasks.create(name : "lineLengthCheck") {
- fs.each { sourceDir ->
- fileTree(dir : sourceDir, include : "**/*.kt").each{ file ->
- file.readLines().eachWithIndex { line, index ->
- if (line.size() > 100) {
- project.logger.error("line too long: file: $file" +
- " index:$index line: $line")
- }
- }
- }
- }
- }
- kotlinCheckstyle.dependsOn(lineCheck)
-}
-
-def createAndroidCheckstyle(Project project) {
- def fs = files()
- if (project.hasProperty('android')) {
- fs += files(project.android.sourceSets.main.java.getSrcDirs().collect {fileTree(it)})
- }
- if (project.sourceSets.hasProperty('main')) {
- fs += files(project.sourceSets.main.allJava)
- }
- fs = fs.filter{file -> file.name.endsWith(".java")}
-
- def checkStyle = createCheckstyleTask(project, 'checkstyleAndroid',
- "${project.rootProject.ext.checkoutRoot}/prebuilts/checkstyle/android-style.xml",
- fs.files)
- project.tasks.findByName("check").dependsOn(checkStyle)
-}
-
-def createCheckstyleTask(project, taskName, configFile, inputFiles) {
- def arguments = ['-c', configFile]
- arguments.addAll(inputFiles)
- def checkStyle = project.tasks.create(name : taskName, type: JavaExec) {
- inputs.files(inputFiles).skipWhenEmpty()
- main = "com.puppycrawl.tools.checkstyle.Main"
- args = arguments
- classpath = files(file("${project.rootProject.ext.checkoutRoot}/prebuilts/checkstyle/checkstyle.jar").path)
- }
- return checkStyle;
-}
-
-ext.createKotlinCheckstyle = this.&createKotlinCheckstyle
-ext.createAndroidCheckstyle = this.&createAndroidCheckstyle
diff --git a/app-toolkit/runtime/build.gradle b/app-toolkit/runtime/build.gradle
index 3b46384..83d4293 100644
--- a/app-toolkit/runtime/build.gradle
+++ b/app-toolkit/runtime/build.gradle
@@ -30,11 +30,9 @@
dependencies {
api libs.support.annotations
- api project(":arch:common")
+ api(project(":arch:common"))
}
-createAndroidCheckstyle(project)
-
supportLibrary {
name = "Android Arch-Runtime"
publish = true
diff --git a/app-toolkit/runtime/lint-baseline.xml b/app-toolkit/runtime/lint-baseline.xml
deleted file mode 100644
index 2cadde1..0000000
--- a/app-toolkit/runtime/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0">
-
-</issues>
diff --git a/app-toolkit/runtime/src/main/java/android/arch/core/executor/ArchTaskExecutor.java b/app-toolkit/runtime/src/main/java/android/arch/core/executor/ArchTaskExecutor.java
index 2401a73..6276ee3 100644
--- a/app-toolkit/runtime/src/main/java/android/arch/core/executor/ArchTaskExecutor.java
+++ b/app-toolkit/runtime/src/main/java/android/arch/core/executor/ArchTaskExecutor.java
@@ -64,6 +64,7 @@
*
* @return The singleton ArchTaskExecutor.
*/
+ @NonNull
public static ArchTaskExecutor getInstance() {
if (sInstance != null) {
return sInstance;
diff --git a/app-toolkit/runtime/src/main/java/android/arch/core/executor/TaskExecutor.java b/app-toolkit/runtime/src/main/java/android/arch/core/executor/TaskExecutor.java
index 055b476..7175801 100644
--- a/app-toolkit/runtime/src/main/java/android/arch/core/executor/TaskExecutor.java
+++ b/app-toolkit/runtime/src/main/java/android/arch/core/executor/TaskExecutor.java
@@ -16,6 +16,7 @@
package android.arch.core.executor;
+import android.support.annotation.NonNull;
import android.support.annotation.RestrictTo;
/**
@@ -33,14 +34,14 @@
*
* @param runnable The runnable to run in the disk IO thread pool.
*/
- public abstract void executeOnDiskIO(Runnable runnable);
+ public abstract void executeOnDiskIO(@NonNull Runnable runnable);
/**
* Posts the given task to the main thread.
*
* @param runnable The runnable to run on the main thread.
*/
- public abstract void postToMainThread(Runnable runnable);
+ public abstract void postToMainThread(@NonNull Runnable runnable);
/**
* Executes the given task on the main thread.
@@ -49,7 +50,7 @@
*
* @param runnable The runnable to run on the main thread.
*/
- public void executeOnMainThread(Runnable runnable) {
+ public void executeOnMainThread(@NonNull Runnable runnable) {
if (isMainThread()) {
runnable.run();
} else {
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index 9c0d8af..718110f 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -12,6 +12,10 @@
classpath build_libs.kotlin.gradle_plugin
}
}
+def runningInBuildServer = System.env.DIST_DIR != null && System.env.OUT_DIR != null
+if (runningInBuildServer) {
+ System.setProperty("kotlin.compiler.execution.strategy", "in-process")
+}
apply from: "build_dependencies.gradle"
diff --git a/buildSrc/build_dependencies.gradle b/buildSrc/build_dependencies.gradle
index dc41841..be135b9 100644
--- a/buildSrc/build_dependencies.gradle
+++ b/buildSrc/build_dependencies.gradle
@@ -27,8 +27,8 @@
// jarjar plugin
build_libs.jarjar_gradle = 'org.anarres.jarjar:jarjar-gradle:1.0.0'
-build_libs.error_prone = 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.10'
+build_libs.error_prone = 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.13'
build_libs.jacoco = 'org.jacoco:org.jacoco.core:0.7.8'
-build_libs.kotlin = [gradle_plugin: "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.51"]
+build_libs.kotlin = [gradle_plugin: "org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.0"]
rootProject.ext['build_libs'] = build_libs
diff --git a/buildSrc/dependencies.gradle b/buildSrc/dependencies.gradle
index b61cfc6..48d3eb9 100644
--- a/buildSrc/dependencies.gradle
+++ b/buildSrc/dependencies.gradle
@@ -16,14 +16,13 @@
// Add ext.libs for library versions
def libs = [:]
-// Testing dependencies
-libs.mockito_core = 'org.mockito:mockito-core:2.7.6'
-libs.dexmaker_mockito = 'com.linkedin.dexmaker:dexmaker-mockito:2.2.0'
-libs.junit = 'junit:junit:4.12'
-libs.test_runner = 'com.android.support.test:runner:1.0.1'
-libs.test_rules = 'com.android.support.test:rules:1.0.1'
-libs.espresso_core = 'com.android.support.test.espresso:espresso-core:3.0.1'
-libs.espresso_contrib = 'com.android.support.test.espresso:espresso-contrib:3.0.1'
+libs.exclude_bytebuddy = {
+ exclude group: 'net.bytebuddy'
+}
+
+libs.exclude_support = {
+ exclude group: 'com.android.support'
+}
//arch components
libs.arch_lifecycle_runtime = "android.arch.lifecycle:runtime:1.0.3@aar"
diff --git a/buildSrc/diff_and_docs.gradle b/buildSrc/diff_and_docs.gradle
deleted file mode 100644
index 2fcc893..0000000
--- a/buildSrc/diff_and_docs.gradle
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-import android.support.Version
-import android.support.checkapi.ApiXmlConversionTask
-import android.support.checkapi.CheckApiTask
-import android.support.checkapi.UpdateApiTask
-import android.support.doclava.DoclavaTask
-import android.support.jdiff.JDiffTask
-import com.android.build.gradle.api.LibraryVariant
-import groovy.io.FileType
-import groovy.transform.Field
-import org.gradle.api.tasks.compile.JavaCompile
-
-// Set up platform API files for federation.
-if (project.androidApiTxt != null) {
- task generateSdkApi(type: Copy) {
- description = 'Copies the API files for the current SDK.'
-
- // Export the API files so this looks like a DoclavaTask.
- ext.apiFile = new File(project.docsDir, 'release/sdk_current.txt')
- ext.removedApiFile = new File(project.docsDir, 'release/sdk_removed.txt')
-
- from project.androidApiTxt.absolutePath
- into apiFile.parent
- rename { apiFile.name }
-
- // Register the fake removed file as an output.
- outputs.file removedApiFile
-
- doLast {
- removedApiFile.createNewFile()
- }
- }
-} else {
- task generateSdkApi(type: DoclavaTask, dependsOn: [configurations.doclava]) {
- description = 'Generates API files for the current SDK.'
-
- docletpath = configurations.doclava.resolve()
- destinationDir = project.docsDir
-
- classpath = project.androidJar
- source zipTree(project.androidSrcJar)
-
- apiFile = new File(project.docsDir, 'release/sdk_current.txt')
- removedApiFile = new File(project.docsDir, 'release/sdk_removed.txt')
- generateDocs = false
-
- options {
- addStringOption "stubpackages", "android.*"
- }
- }
-}
-
-// configuration file for setting up api diffs and api docs
-void registerAndroidProjectForDocsTask(Task task, LibraryVariant releaseVariant) {
- task.dependsOn releaseVariant.javaCompile
- task.source {
- // Exclude generated R.java files that don't belong to this project.
- String packageDir = releaseVariant.getApplicationId().replace('.', '/')
- return releaseVariant.javaCompile.source.filter { File file ->
- return !file.name.equals('R.java') || file.parent.endsWith(packageDir)
- }
- }
- task.classpath += releaseVariant.getCompileClasspath(null) +
- files(releaseVariant.javaCompile.destinationDir)
-}
-
-// configuration file for setting up api diffs and api docs
-void registerJavaProjectForDocsTask(Task task, JavaCompile javaCompileTask) {
- task.dependsOn javaCompileTask
- task.source javaCompileTask.source
- task.classpath += files(javaCompileTask.classpath) +
- files(javaCompileTask.destinationDir)
-}
-
-// Generates online docs.
-task generateDocs(type: DoclavaTask, dependsOn: [configurations.doclava, generateSdkApi]) {
- ext.artifacts = []
- ext.sinces = []
-
- def offlineDocs = project.docs.offline
- group = JavaBasePlugin.DOCUMENTATION_GROUP
- description = 'Generates d.android.com-style documentation. To generate offline docs use ' +
- '\'-PofflineDocs=true\' parameter.'
-
- docletpath = configurations.doclava.resolve()
- destinationDir = new File(project.docsDir, offlineDocs ? "offline" : "online")
-
- // Base classpath is Android SDK, sub-projects add their own.
- classpath = project.ext.androidJar
-
- // Default hidden errors + hidden superclass (111) and
- // deprecation mismatch (113) to match framework docs.
- final def hidden = [105, 106, 107, 111, 112, 113, 115, 116, 121]
-
- doclavaErrors = (101..122) - hidden
- doclavaWarnings = []
- doclavaHidden += hidden
-
- // Track API change history prior to split versioning.
- def apiFilePattern = /(\d+\.\d+\.\d).txt/
- File apiDir = new File(supportRootFolder, 'api')
- apiDir.eachFileMatch FileType.FILES, ~apiFilePattern, { File apiFile ->
- def apiLevel = (apiFile.name =~ apiFilePattern)[0][1]
- sinces.add([apiFile.absolutePath, apiLevel])
- }
-
- options {
- addStringOption 'templatedir',
- "${supportRootFolder}/../../external/doclava/res/assets/templates-sdk"
- addStringOption 'samplesdir', "${supportRootFolder}/samples"
- addMultilineMultiValueOption("federate").setValue([
- ['Android', 'https://developer.android.com']
- ])
- addMultilineMultiValueOption("federationapi").setValue([
- ['Android', generateSdkApi.apiFile.absolutePath]
- ])
- addMultilineMultiValueOption("hdf").setValue([
- ['android.whichdoc', 'online'],
- ['android.hasSamples', 'true'],
- ['dac', 'true']
- ])
-
- // Specific to reference docs.
- if (!offlineDocs) {
- addStringOption "toroot", "/"
- addBooleanOption "devsite", true
- addStringOption "dac_libraryroot", project.docs.dac.libraryroot
- addStringOption "dac_dataname", project.docs.dac.dataname
- }
- }
-
- exclude '**/BuildConfig.java'
-
- doFirst {
- if (artifacts.size() > 0) {
- options.addMultilineMultiValueOption("artifact").setValue(artifacts)
- }
- if (sinces.size() > 0) {
- options.addMultilineMultiValueOption("since").setValue(sinces)
- }
- }
-}
-
-// Generates a distribution artifact for online docs.
-task distDocs(type: Zip, dependsOn: generateDocs) {
- group = JavaBasePlugin.DOCUMENTATION_GROUP
- description = 'Generates distribution artifact for d.android.com-style documentation.'
-
- from generateDocs.destinationDir
- destinationDir project.distDir
- baseName = "android-support-docs"
- version = project.buildNumber
-
- doLast {
- logger.lifecycle("'Wrote API reference to ${archivePath}")
- }
-}
-
-@Field def MSG_HIDE_API =
- "If you are adding APIs that should be excluded from the public API surface,\n" +
- "consider using package or private visibility. If the API must have public\n" +
- "visibility, you may exclude it from public API by using the @hide javadoc\n" +
- "annotation paired with the @RestrictTo(LIBRARY_GROUP) code annotation."
-
-// Check that the API we're building hasn't broken compatibility with the
-// previously released version. These types of changes are forbidden.
-@Field def CHECK_API_CONFIG_RELEASE = [
- onFailMessage:
- "Compatibility with previously released public APIs has been broken. Please\n" +
- "verify your change with Support API Council and provide error output,\n" +
- "including the error messages and associated SHAs.\n" +
- "\n" +
- "If you are removing APIs, they must be deprecated first before being removed\n" +
- "in a subsequent release.\n" +
- "\n" + MSG_HIDE_API,
- errors: (7..18),
- warnings: [],
- hidden: (2..6) + (19..30)
-]
-
-// Check that the API we're building hasn't changed from the development
-// version. These types of changes require an explicit API file update.
-@Field def CHECK_API_CONFIG_DEVELOP = [
- onFailMessage:
- "Public API definition has changed. Please run ./gradlew updateApi to confirm\n" +
- "these changes are intentional by updating the public API definition.\n" +
- "\n" + MSG_HIDE_API,
- errors: (2..30)-[22],
- warnings: [],
- hidden: [22]
-]
-
-// This is a patch or finalized release. Check that the API we're building
-// hasn't changed from the current.
-@Field def CHECK_API_CONFIG_PATCH = [
- onFailMessage:
- "Public API definition may not change in finalized or patch releases.\n" +
- "\n" + MSG_HIDE_API,
- errors: (2..30)-[22],
- warnings: [],
- hidden: [22]
-]
-
-CheckApiTask createCheckApiTask(Project project, String taskName, def checkApiConfig,
- File oldApi, File newApi, File whitelist = null) {
- return project.tasks.create(name: taskName, type: CheckApiTask.class) {
- doclavaClasspath = project.generateApi.docletpath
-
- onFailMessage = checkApiConfig.onFailMessage
- checkApiErrors = checkApiConfig.errors
- checkApiWarnings = checkApiConfig.warnings
- checkApiHidden = checkApiConfig.hidden
-
- newApiFile = newApi
- oldApiFile = oldApi
-
- whitelistErrorsFile = whitelist
-
- doFirst {
- logger.lifecycle "Verifying ${newApi.name} against ${oldApi ? oldApi.name : "nothing"}..."
- }
- }
-}
-
-DoclavaTask createGenerateApiTask(Project project) {
- // Generates API files
- return project.tasks.create(name: "generateApi", type: DoclavaTask.class,
- dependsOn: configurations.doclava) {
- docletpath = configurations.doclava.resolve()
- destinationDir = project.docsDir
-
- // Base classpath is Android SDK, sub-projects add their own.
- classpath = rootProject.ext.androidJar
- apiFile = new File(project.docsDir, 'release/' + project.name + '/current.txt')
- generateDocs = false
-
- options {
- addBooleanOption "stubsourceonly", true
- }
- exclude '**/BuildConfig.java'
- exclude '**/R.java'
- }
-}
-
-/**
- * Returns the API file for the specified reference version.
- *
- * @param refApi the reference API version, ex. 25.0.0-SNAPSHOT
- * @return the most recently released API file
- */
-File getApiFile(File rootDir, Version refVersion, boolean forceRelease = false) {
- File apiDir = new File(rootDir, 'api')
-
- if (!refVersion.isSnapshot() || forceRelease) {
- // Release API file is always X.Y.0.txt.
- return new File(apiDir, "$refVersion.major.$refVersion.minor.0.txt")
- }
-
- // Non-release API file is always current.txt.
- return new File(apiDir, 'current.txt')
-}
-
-File getLastReleasedApiFile(File rootFolder, String refApi) {
- Version refVersion = new Version(refApi)
- File apiDir = new File(rootFolder, 'api')
-
- File lastFile = null
- Version lastVersion = null
-
- // Only look at released versions and snapshots thereof, ex. X.Y.0.txt.
- apiDir.eachFileMatch FileType.FILES, ~/(\d+)\.(\d+)\.0\.txt/, { File file ->
- Version version = new Version(stripExtension(file.name))
- if ((lastFile == null || lastVersion < version) && version < refVersion) {
- lastFile = file
- lastVersion = version
- }
- }
-
- return lastFile
-}
-
-boolean hasApiFolder(Project project) {
- new File(project.projectDir, "api").exists()
-}
-
-String stripExtension(String fileName) {
- return fileName[0..fileName.lastIndexOf('.') - 1]
-}
-
-void initializeApiChecksForProject(Project project) {
- if (!project.hasProperty("docsDir")) {
- project.ext.docsDir = new File(rootProject.docsDir, project.name)
- }
- def artifact = project.group + ":" + project.name + ":" + project.version
- def version = new Version(project.version)
- def workingDir = project.projectDir
-
- DoclavaTask generateApi = createGenerateApiTask(project)
- createVerifyUpdateApiAllowedTask(project)
-
- // Make sure the API surface has not broken since the last release.
- File lastReleasedApiFile = getLastReleasedApiFile(workingDir, project.version)
-
- def whitelistFile = lastReleasedApiFile == null ? null : new File(
- lastReleasedApiFile.parentFile, stripExtension(lastReleasedApiFile.name) + ".ignore")
- def checkApiRelease = createCheckApiTask(project, "checkApiRelease", CHECK_API_CONFIG_RELEASE,
- lastReleasedApiFile, generateApi.apiFile, whitelistFile).dependsOn(generateApi)
-
- // Allow a comma-delimited list of whitelisted errors.
- if (project.hasProperty("ignore")) {
- checkApiRelease.whitelistErrors = ignore.split(',')
- }
-
- // Check whether the development API surface has changed.
- def verifyConfig = version.isPatch() ? CHECK_API_CONFIG_PATCH : CHECK_API_CONFIG_DEVELOP
- File currentApiFile = getApiFile(workingDir, new Version(project.version))
- def checkApi = createCheckApiTask(project, "checkApi", verifyConfig,
- currentApiFile, project.generateApi.apiFile)
- .dependsOn(generateApi, checkApiRelease)
-
- checkApi.group JavaBasePlugin.VERIFICATION_GROUP
- checkApi.description 'Verify the API surface.'
-
- createUpdateApiTask(project)
- createNewApiXmlTask(project)
- createOldApiXml(project)
- createGenerateDiffsTask(project)
-
- // Track API change history.
- def apiFilePattern = /(\d+\.\d+\.\d).txt/
- File apiDir = new File(project.projectDir, 'api')
- apiDir.eachFileMatch FileType.FILES, ~apiFilePattern, { File apiFile ->
- def apiLevel = (apiFile.name =~ apiFilePattern)[0][1]
- rootProject.generateDocs.sinces.add([apiFile.absolutePath, apiLevel])
- }
-
- // Associate current API surface with the Maven artifact.
- rootProject.generateDocs.artifacts.add([generateApi.apiFile.absolutePath, artifact])
- rootProject.generateDocs.dependsOn generateApi
-
- rootProject.createArchive.dependsOn checkApi
-}
-
-Task createVerifyUpdateApiAllowedTask(Project project) {
- project.tasks.create(name: "verifyUpdateApiAllowed") {
- // This could be moved to doFirst inside updateApi, but using it as a
- // dependency with no inputs forces it to run even when updateApi is a
- // no-op.
- doLast {
- def rootFolder = project.projectDir
- Version version = new Version(project.version)
-
- if (version.isPatch()) {
- throw new GradleException("Public APIs may not be modified in patch releases.")
- } else if (version.isSnapshot() && getApiFile(rootFolder, version, true).exists()) {
- throw new GradleException("Inconsistent version. Public API file already exists.")
- } else if (!version.isSnapshot() && getApiFile(rootFolder, version).exists()
- && !project.hasProperty("force")) {
- throw new GradleException("Public APIs may not be modified in finalized releases.")
- }
- }
- }
-}
-
-UpdateApiTask createUpdateApiTask(Project project) {
- project.tasks.create(name: "updateApi", type: UpdateApiTask,
- dependsOn: [project.checkApiRelease, project.verifyUpdateApiAllowed]) {
- group JavaBasePlugin.VERIFICATION_GROUP
- description 'Updates the candidate API file to incorporate valid changes.'
- newApiFile = project.checkApiRelease.newApiFile
- oldApiFile = getApiFile(project.projectDir, new Version(project.version))
- whitelistErrors = project.checkApiRelease.whitelistErrors
- whitelistErrorsFile = project.checkApiRelease.whitelistErrorsFile
-
- doFirst {
- // Replace the expected whitelist with the detected whitelist.
- whitelistErrors = project.checkApiRelease.detectedWhitelistErrors
- }
- }
-}
-
-/**
- * Converts the <code>toApi</code>.txt file (or current.txt if not explicitly
- * defined using -PtoApi=<file>) to XML format for use by JDiff.
- */
-ApiXmlConversionTask createNewApiXmlTask(Project project) {
- project.tasks.create(name: "newApiXml", type: ApiXmlConversionTask, dependsOn: configurations.doclava) {
- classpath configurations.doclava.resolve()
-
- if (project.hasProperty("toApi")) {
- // Use an explicit API file.
- inputApiFile = new File(project.projectDir, "api/${toApi}.txt")
- } else {
- // Use the current API file (e.g. current.txt).
- inputApiFile = project.generateApi.apiFile
- dependsOn project.generateApi
- }
-
- outputApiXmlFile = new File(project.docsDir,
- "release/" + stripExtension(inputApiFile.name) + ".xml")
- }
-}
-
-/**
- * Converts the <code>fromApi</code>.txt file (or the most recently released
- * X.Y.Z.txt if not explicitly defined using -PfromAPi=<file>) to XML format
- * for use by JDiff.
- */
-ApiXmlConversionTask createOldApiXml(Project project) {
- project.tasks.create(name: "oldApiXml", type: ApiXmlConversionTask, dependsOn: configurations.doclava) {
- classpath configurations.doclava.resolve()
-
- def rootFolder = project.projectDir
- if (project.hasProperty("fromApi")) {
- // Use an explicit API file.
- inputApiFile = new File(rootFolder, "api/${fromApi}.txt")
- } else if (project.hasProperty("toApi") && toApi.matches(~/(\d+\.){2}\d+/)) {
- // If toApi matches released API (X.Y.Z) format, use the most recently
- // released API file prior to toApi.
- inputApiFile = getLastReleasedApiFile(rootFolder, toApi)
- } else {
- // Use the most recently released API file.
- inputApiFile = getApiFile(rootFolder, new Version(project.version))
- }
-
- outputApiXmlFile = new File(project.docsDir,
- "release/" + stripExtension(inputApiFile.name) + ".xml")
- }
-}
-
-/**
- * Generates API diffs.
- * <p>
- * By default, diffs are generated for the delta between current.txt and the
- * next most recent X.Y.Z.txt API file. Behavior may be changed by specifying
- * one or both of -PtoApi and -PfromApi.
- * <p>
- * If both fromApi and toApi are specified, diffs will be generated for
- * fromApi -> toApi. For example, 25.0.0 -> 26.0.0 diffs could be generated by
- * using:
- * <br><code>
- * ./gradlew generateDiffs -PfromApi=25.0.0 -PtoApi=26.0.0
- * </code>
- * <p>
- * If only toApi is specified, it MUST be specified as X.Y.Z and diffs will be
- * generated for (release before toApi) -> toApi. For example, 24.2.0 -> 25.0.0
- * diffs could be generated by using:
- * <br><code>
- * ./gradlew generateDiffs -PtoApi=25.0.0
- * </code>
- * <p>
- * If only fromApi is specified, diffs will be generated for fromApi -> current.
- * For example, lastApiReview -> current diffs could be generated by using:
- * <br><code>
- * ./gradlew generateDiffs -PfromApi=lastApiReview
- * </code>
- * <p>
- */
-JDiffTask createGenerateDiffsTask(Project project) {
- project.tasks.create(name: "generateDiffs", type: JDiffTask,
- dependsOn: [configurations.jdiff, configurations.doclava,
- project.oldApiXml, project.newApiXml, rootProject.generateDocs]) {
- // Base classpath is Android SDK, sub-projects add their own.
- classpath = rootProject.ext.androidJar
-
- // JDiff properties.
- oldApiXmlFile = project.oldApiXml.outputApiXmlFile
- newApiXmlFile = project.newApiXml.outputApiXmlFile
-
- String newApi = newApiXmlFile.name
- int lastDot = newApi.lastIndexOf('.')
- newApi = newApi.substring(0, lastDot)
-
- if (project == rootProject) {
- newJavadocPrefix = "../../../../reference/"
- destinationDir = new File(rootProject.docsDir, "online/sdk/support_api_diff/$newApi")
- } else {
- newJavadocPrefix = "../../../../../reference/"
- destinationDir = new File(rootProject.docsDir,
- "online/sdk/support_api_diff/$project.name/$newApi")
- }
-
- // Javadoc properties.
- docletpath = configurations.jdiff.resolve()
- title = "Support Library API Differences Report"
-
- exclude '**/BuildConfig.java'
- exclude '**/R.java'
- }
-}
-
-boolean hasJavaSources(releaseVariant) {
- def fs = releaseVariant.javaCompile.source.filter { file ->
- file.name != "R.java" && file.name != "BuildConfig.java"
- }
- return !fs.isEmpty();
-}
-
-subprojects { subProject ->
- subProject.afterEvaluate { project ->
- if (project.hasProperty("noDocs") && project.noDocs) {
- logger.warn("Project $project.name specified noDocs, ignoring API tasks.")
- return
- }
- if (project.hasProperty("supportLibrary") && !project.supportLibrary.publish) {
- logger.warn("Project $project.name is not published, ignoring API tasks.")
- return
- }
- if (project.hasProperty('android') && project.android.hasProperty('libraryVariants')) {
- project.android.libraryVariants.all { variant ->
- if (variant.name == 'release') {
- registerAndroidProjectForDocsTask(rootProject.generateDocs, variant)
- if (!hasJavaSources(variant)) {
- return
- }
- if (!hasApiFolder(project)) {
- logger.warn("Project $project.name doesn't have an api folder, " +
- "ignoring API tasks.")
- return
- }
- initializeApiChecksForProject(project)
- registerAndroidProjectForDocsTask(project.generateApi, variant)
- registerAndroidProjectForDocsTask(project.generateDiffs, variant)
- }
- }
- } else if (project.hasProperty("compileJava")) {
- registerJavaProjectForDocsTask(rootProject.generateDocs, project.compileJava)
- if (!hasApiFolder(project)) {
- logger.warn("Project $project.name doesn't have an api folder, " +
- "ignoring API tasks.")
- return
- }
- project.afterEvaluate {
- initializeApiChecksForProject(project)
- registerJavaProjectForDocsTask(project.generateApi, project.compileJava)
- registerJavaProjectForDocsTask(project.generateDiffs, project.compileJava)
- }
- }
- }
-}
diff --git a/buildSrc/init.gradle b/buildSrc/init.gradle
index ccbd35a..a0df393 100644
--- a/buildSrc/init.gradle
+++ b/buildSrc/init.gradle
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+
+import android.support.DacOptions
+import android.support.DiffAndDocs
import android.support.LibraryVersions
import com.android.build.gradle.internal.coverage.JacocoPlugin
import com.android.build.gradle.internal.coverage.JacocoReportTask
@@ -33,12 +36,7 @@
ext.runningInBuildServer = System.env.DIST_DIR != null && System.env.OUT_DIR != null
apply from: "${supportRoot}/buildSrc/dependencies.gradle"
-ext.docs = [:]
-ext.docs.offline = rootProject.getProperties().containsKey("offlineDocs")
-ext.docs.dac = [
- libraryroot: "android/support",
- dataname: "SUPPORT_DATA"
-]
+ext.docsDac = new DacOptions("android/support", "SUPPORT_DATA")
def enableDoclavaAndJDiff(p) {
p.configurations {
@@ -52,7 +50,7 @@
jdiff libs.xml_parser_apis
jdiff libs.xerces_impl
}
- apply from: "${ext.supportRootFolder}/buildSrc/diff_and_docs.gradle"
+ DiffAndDocs.configureDiffAndDocs(rootProject, createArchive, supportRootFolder)
}
def getFullSdkPath() {
@@ -64,7 +62,7 @@
}
def setSdkInLocalPropertiesFile() {
- ext.buildToolsVersion = '27.0.0'
+ ext.buildToolsVersion = '27.0.1'
final String fullSdkPath = getFullSdkPath();
if (file(fullSdkPath).exists()) {
gradle.ext.currentSdk = 26
diff --git a/buildSrc/src/main/groovy/android/support/doclava/DoclavaJavadocOptionFileOption.java b/buildSrc/src/main/groovy/android/support/doclava/DoclavaJavadocOptionFileOption.java
deleted file mode 100644
index db3f318..0000000
--- a/buildSrc/src/main/groovy/android/support/doclava/DoclavaJavadocOptionFileOption.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2014 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 android.support.doclava;
-
-import org.gradle.external.javadoc.internal.AbstractJavadocOptionFileOption;
-import org.gradle.external.javadoc.internal.JavadocOptionFileWriterContext;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Iterator;
-
-/**
- * This class is used to hold complex argument(s) to doclava
- */
-public class DoclavaJavadocOptionFileOption extends
- AbstractJavadocOptionFileOption<Iterable<String>> {
-
- public DoclavaJavadocOptionFileOption(String option) {
- super(option, null);
- }
-
- public DoclavaJavadocOptionFileOption(String option, Iterable<String> value) {
- super(option, value);
- }
-
- @Override
- public void write(JavadocOptionFileWriterContext writerContext) throws IOException {
- writerContext.writeOptionHeader(getOption());
-
- final Iterable<String> args = getValue();
- if (args != null) {
- final Iterator<String> iter = args.iterator();
- while (true) {
- writerContext.writeValue(iter.next());
- if (!iter.hasNext()) {
- break;
- }
- writerContext.write(" ");
- }
- }
-
- writerContext.newLine();
- }
-
- /**
- * @return a deep copy of the option
- */
- public DoclavaJavadocOptionFileOption duplicate() {
- final Iterable<String> value = getValue();
- final ArrayList<String> valueCopy;
- if (value != null) {
- valueCopy = new ArrayList<>();
- for (String item : value) {
- valueCopy.add(item);
- }
- } else {
- valueCopy = null;
- }
- return new DoclavaJavadocOptionFileOption(getOption(), valueCopy);
- }
-}
diff --git a/buildSrc/src/main/groovy/android/support/doclava/DoclavaTask.groovy b/buildSrc/src/main/groovy/android/support/doclava/DoclavaTask.groovy
deleted file mode 100644
index 651446f..0000000
--- a/buildSrc/src/main/groovy/android/support/doclava/DoclavaTask.groovy
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.support.doclava
-
-import org.gradle.api.tasks.Input
-import org.gradle.api.tasks.InputFiles
-import org.gradle.api.tasks.javadoc.Javadoc
-import org.gradle.api.tasks.Optional
-import org.gradle.api.tasks.OutputDirectory
-import org.gradle.api.tasks.OutputFile
-import org.gradle.external.javadoc.JavadocOptionFileOption
-
-public class DoclavaTask extends Javadoc {
-
- // external/doclava/src/com/google/doclava/Errors.java
- public static final def DEFAULT_DOCLAVA_ERRORS = Collections.unmodifiableSet([
- 101, // unresolved link
- 103, // unknown tag
- 104, // unknown param name
- ] as Set)
-
- public static final def DEFAULT_DOCLAVA_WARNINGS = Collections.unmodifiableSet([
- 121, // hidden type param
- ] as Set)
-
-
- public static final def DEFAULT_DOCLAVA_HIDDEN = Collections.unmodifiableSet([
- 111, // hidden super class
- 113, // @deprecation mismatch
- ] as Set)
-
-
- // All lowercase name to match MinimalJavadocOptions#docletpath
- private Collection<File> mDocletpath
-
- // doclava error types which will cause the build to fail
- @Input
- Collection doclavaErrors = DEFAULT_DOCLAVA_ERRORS
- @Input
- Collection doclavaWarnings = DEFAULT_DOCLAVA_WARNINGS
- // spammy doclava warnings which we want to hide
- @Input
- Collection doclavaHidden = DEFAULT_DOCLAVA_HIDDEN
-
- /**
- * If non-null, the list of packages that will be treated as if they were
- * marked with {@literal @hide}.<br>
- * Packages names will be matched exactly; sub-packages are not automatically recognized.
- */
- @Optional
- @Input
- Collection hiddenPackages
-
- /**
- * If non-null and not-empty, the whitelist of packages that will be present in the generated
- * stubs; if null or empty, then all packages have stubs generated.<br>
- * Wildcards are accepted.
- */
- @Optional
- @Input
- Set<String> stubPackages
-
- @Input
- boolean generateDocs = true
-
- /**
- * If non-null, the location of where to place the generated api file.
- * If this is non-null, then {@link #removedApiFile} must be non-null as well.
- */
- @Optional
- @OutputFile
- File apiFile
-
- /**
- * If non-null, the location of where to place the generated removed api file.
- * If this is non-null, then {@link #apiFile} must be non-null as well.
- */
- @Optional
- @OutputFile
- File removedApiFile
-
- /**
- * If non-null, the location of the generated keep list.
- */
- @Optional
- @OutputFile
- File keepListFile
-
- /**
- * If non-null, the location to put the generated stub sources.
- */
- @Optional
- @OutputDirectory
- File stubsDir
-
- public DoclavaTask() {
- failOnError = true
- options.doclet = "com.google.doclava.Doclava"
- options.encoding("UTF-8")
- options.quiet()
- // doclava doesn't understand '-doctitle'
- title = null
- maxMemory = "1280m"
- // If none of generateDocs, apiFile, keepListFile, or stubJarsDir are true, then there is
- // no work to do.
- onlyIf( { getGenerateDocs() ||
- getApiFile() != null ||
- getKeepListFile() != null ||
- getStubsDir() != null } )
- }
-
- /**
- * The doclet path which has the {@code com.gogole.doclava.Doclava} class.
- * This option will override any doclet path set in this instance's {@link #options JavadocOptions}.
- * @see MinimalJavadocOptions#getDocletpath()
- */
- @InputFiles
- public Collection<File> getDocletpath() {
- return mDocletpath
- }
-
- /**
- * Sets the doclet path which has the {@code com.gogole.doclava.Doclava} class.
- * This option will override any doclet path set in this instance's {@link #options JavadocOptions}.
- * @see MinimalJavadocOptions#setDocletpath(java.util.List)
- */
- public void setDocletpath(Collection<File> docletpath) {
- mDocletpath = docletpath
- // Go ahead and keep the docletpath in our JavadocOptions object in sync.
- options.docletpath = docletpath as List
- }
-
- public void setDoclavaErrors(Collection errors) {
- // Make it serializable.
- doclavaErrors = errors as int[]
- }
-
- public void setDoclavaWarnings(Collection warnings) {
- // Make it serializable.
- doclavaWarnings = warnings as int[]
- }
-
- public void setDoclavaHidden(Collection hidden) {
- // Make it serializable.
- doclavaHidden = hidden as int[]
- }
-
- /**
- * "Configures" this DoclavaTask with parameters that might not be at their final values
- * until this task is run.
- */
- private configureDoclava() {
- options.docletpath = getDocletpath() as List
-
- // configure doclava error/warning/hide levels
- JavadocOptionFileOption hide = options.addMultilineMultiValueOption("hide")
- hide.setValue(getDoclavaHidden().collect({ [it.toString()] }))
-
- JavadocOptionFileOption warning = options.addMultilineMultiValueOption("warning")
- warning.setValue(getDoclavaWarnings().collect({ [it.toString()] }))
-
- JavadocOptionFileOption error = options.addMultilineMultiValueOption("error")
- error.setValue(getDoclavaErrors().collect({ [it.toString()] }))
-
- Collection hiddenPackages = getHiddenPackages()
- if (hiddenPackages) {
- JavadocOptionFileOption hidePackage =
- options.addMultilineMultiValueOption("hidePackage")
- hidePackage.setValue(hiddenPackages.collect({ [it.toString()] }))
- }
-
- if (!getGenerateDocs()) {
- options.addOption(new DoclavaJavadocOptionFileOption('nodocs'))
- }
-
- // If requested, generate the API files.
- File apiFile = getApiFile()
- if (apiFile != null) {
- options.addStringOption('api', apiFile.absolutePath)
-
- File removedApiFile = getRemovedApiFile()
- if (removedApiFile != null) {
- options.addStringOption('removedApi', removedApiFile.absolutePath)
- }
- }
-
- // If requested, generate the keep list.
- File keepListFile = getKeepListFile()
- if (keepListFile != null) {
- options.addStringOption('proguard', keepListFile.absolutePath)
- }
- // If requested, generate stubs.
- File stubsDir = getStubsDir()
- if (stubsDir != null) {
- options.addStringOption('stubs', stubsDir.absolutePath)
- Set<String> stubPackages = getStubPackages()
- if (stubPackages) {
- options.addStringOption('stubpackages', stubPackages.join(':'))
- }
- }
- // Always treat this as an Android docs task.
- options.addOption(new DoclavaJavadocOptionFileOption('android'))
- }
-
- @Override
- public void generate() {
- configureDoclava()
- super.generate()
- }
-}
diff --git a/buildSrc/src/main/java/android/support/LibraryVersions.java b/buildSrc/src/main/java/android/support/LibraryVersions.java
index 27a52bd..c8dd1e3 100644
--- a/buildSrc/src/main/java/android/support/LibraryVersions.java
+++ b/buildSrc/src/main/java/android/support/LibraryVersions.java
@@ -43,7 +43,7 @@
/**
* Version code for RecyclerView & Room paging
*/
- public static final Version PAGING = new Version("1.0.0-alpha3");
+ public static final Version PAGING = new Version("1.0.0-alpha4-1");
private static final Version LIFECYCLES = new Version("1.0.3");
diff --git a/buildSrc/src/main/java/android/support/checkapi/UpdateApiTask.java b/buildSrc/src/main/java/android/support/checkapi/UpdateApiTask.java
index de2db91..15e9104 100644
--- a/buildSrc/src/main/java/android/support/checkapi/UpdateApiTask.java
+++ b/buildSrc/src/main/java/android/support/checkapi/UpdateApiTask.java
@@ -29,7 +29,6 @@
import java.io.File;
import java.nio.charset.Charset;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
/**
@@ -120,11 +119,6 @@
}
if (mWhitelistErrorsFile != null && !mWhitelistErrors.isEmpty()) {
- if (mWhitelistErrorsFile.exists()) {
- List<String> lines =
- Files.readLines(mWhitelistErrorsFile, Charset.defaultCharset());
- mWhitelistErrors.removeAll(lines);
- }
try (BufferedWriter writer = Files.newWriter(
mWhitelistErrorsFile, Charset.defaultCharset())) {
for (String error : mWhitelistErrors) {
diff --git a/buildSrc/src/main/kotlin/android/support/DiffAndDocs.kt b/buildSrc/src/main/kotlin/android/support/DiffAndDocs.kt
new file mode 100644
index 0000000..4c57721
--- /dev/null
+++ b/buildSrc/src/main/kotlin/android/support/DiffAndDocs.kt
@@ -0,0 +1,663 @@
+/*
+ * 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 android.support
+
+import android.support.checkapi.ApiXmlConversionTask
+import android.support.checkapi.CheckApiTask
+import android.support.checkapi.UpdateApiTask
+import android.support.doclava.DoclavaTask
+import android.support.jdiff.JDiffTask
+import com.android.build.gradle.LibraryExtension
+import com.android.build.gradle.api.LibraryVariant
+import org.gradle.api.GradleException
+import org.gradle.api.Project
+import org.gradle.api.Task
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.file.FileCollection
+import org.gradle.api.plugins.JavaBasePlugin
+import org.gradle.api.tasks.Copy
+import org.gradle.api.tasks.TaskContainer
+import org.gradle.api.tasks.bundling.Zip
+import org.gradle.api.tasks.compile.JavaCompile
+import org.gradle.api.tasks.javadoc.Javadoc
+import java.io.File
+
+data class DacOptions(val libraryroot: String, val dataname: String)
+
+object DiffAndDocs {
+ @JvmStatic
+ fun configureDiffAndDocs(
+ root: Project,
+ createArchiveTask: Task,
+ supportRootFolder: File) = configure(root, createArchiveTask, supportRootFolder)
+}
+
+private data class CheckApiConfig(
+ val onFailMessage: String,
+ val errors: List<Int>,
+ val warnings: List<Int>,
+ val hidden: List<Int>)
+
+private const val MSG_HIDE_API =
+ "If you are adding APIs that should be excluded from the public API surface,\n" +
+ "consider using package or private visibility. If the API must have public\n" +
+ "visibility, you may exclude it from public API by using the @hide javadoc\n" +
+ "annotation paired with the @RestrictTo(LIBRARY_GROUP) code annotation."
+
+private fun hasJavaSources(variant: LibraryVariant) = !variant.javaCompile.source
+ .filter { file -> file.name != "R.java" && file.name != "BuildConfig.java" }
+ .isEmpty
+
+private val CHECK_API_CONFIG_RELEASE = CheckApiConfig(
+ onFailMessage =
+ "Compatibility with previously released public APIs has been broken. Please\n" +
+ "verify your change with Support API Council and provide error output,\n" +
+ "including the error messages and associated SHAs.\n" +
+ "\n" +
+ "If you are removing APIs, they must be deprecated first before being removed\n" +
+ "in a subsequent release.\n" +
+ "\n" + MSG_HIDE_API,
+ errors = (7..18).toList(),
+ warnings = emptyList(),
+ hidden = (2..6) + (19..30)
+)
+
+// Check that the API we're building hasn't changed from the development
+// version. These types of changes require an explicit API file update.
+private val CHECK_API_CONFIG_DEVELOP = CheckApiConfig(
+ onFailMessage =
+ "Public API definition has changed. Please run ./gradlew updateApi to confirm\n" +
+ "these changes are intentional by updating the public API definition.\n" +
+ "\n" + MSG_HIDE_API,
+ errors = (2..30) - listOf(22),
+ warnings = emptyList(),
+ hidden = listOf(22)
+)
+
+// This is a patch or finalized release. Check that the API we're building
+// hasn't changed from the current.
+private val CHECK_API_CONFIG_PATCH = CHECK_API_CONFIG_DEVELOP.copy(
+ onFailMessage = "Public API definition may not change in finalized or patch releases.\n" +
+ "\n" + MSG_HIDE_API)
+
+private fun hasApiFolder(project: Project) = File(project.projectDir, "api").exists()
+
+private fun stripExtension(fileName: String) = fileName.substringBeforeLast('.')
+
+private fun getLastReleasedApiFile(rootFolder: File, refApi: String): File? {
+ val refVersion = Version(refApi)
+ val apiDir = File(rootFolder, "api")
+
+ var lastFile: File? = null
+ var lastVersion: Version? = null
+ val regex = Regex("(\\d+)\\.(\\d+)\\.0\\.txt")
+ // Only look at released versions and snapshots thereof, ex. X.Y.0.txt.
+ apiDir.listFiles().filter { file ->
+ regex.matches(file.name) && file.isFile
+ }.forEach { file ->
+ val version = Version(stripExtension(file.name))
+
+ if ((lastFile == null || lastVersion!! < version) && version < refVersion) {
+ lastFile = file
+ lastVersion = version
+ }
+ }
+ return lastFile
+}
+
+private fun getApiFile(rootDir: File, refVersion: Version): File {
+ return getApiFile(rootDir, refVersion, false)
+}
+
+/**
+ * Returns the API file for the specified reference version.
+ *
+ * @param refVersion the reference API version, ex. 25.0.0-SNAPSHOT
+ * @return the most recently released API file
+ */
+private fun getApiFile(rootDir: File, refVersion: Version, forceRelease: Boolean = false): File {
+ val apiDir = File(rootDir, "api")
+
+ if (!refVersion.isSnapshot || forceRelease) {
+ // Release API file is always X.Y.0.txt.
+ return File(apiDir, "${refVersion.major}.${refVersion.minor}.0.txt")
+ }
+
+ // Non-release API file is always current.txt.
+ return File(apiDir, "current.txt")
+}
+
+private fun createVerifyUpdateApiAllowedTask(project: Project) =
+ project.tasks.createWithConfig("verifyUpdateApiAllowed") {
+ // This could be moved to doFirst inside updateApi, but using it as a
+ // dependency with no inputs forces it to run even when updateApi is a
+ // no-op.
+ doLast {
+ val rootFolder = project.projectDir
+ val version = Version(project.version as String)
+
+ if (version.isPatch) {
+ throw GradleException("Public APIs may not be modified in patch releases.")
+ } else if (version.isSnapshot && getApiFile(rootFolder,
+ version,
+ true).exists()) {
+ throw GradleException("Inconsistent version. Public API file already exists.")
+ } else if (!version.isSnapshot && getApiFile(rootFolder, version).exists()
+ && !project.hasProperty("force")) {
+ throw GradleException("Public APIs may not be modified in finalized releases.")
+ }
+ }
+ }
+
+// Generates API files
+private fun createGenerateApiTask(project: Project, docletpathParam: Collection<File>) =
+ project.tasks.createWithConfig("generateApi", DoclavaTask::class.java) {
+ setDocletpath(docletpathParam)
+ destinationDir = project.docsDir()
+ // Base classpath is Android SDK, sub-projects add their own.
+ classpath = project.androidJar()
+ apiFile = File(project.docsDir(), "release/${project.name}/current.txt")
+ generateDocs = false
+
+ coreJavadocOptions {
+ addBooleanOption("stubsourceonly", true)
+ }
+
+ exclude("**/BuildConfig.java")
+ exclude("**/R.java")
+ }
+
+private fun createCheckApiTask(
+ project: Project,
+ taskName: String,
+ docletpath: Collection<File>,
+ checkApiConfig: CheckApiConfig,
+ oldApi: File?,
+ newApi: File,
+ whitelist: File? = null) =
+ project.tasks.createWithConfig(taskName, CheckApiTask::class.java) {
+ doclavaClasspath = docletpath
+ onFailMessage = checkApiConfig.onFailMessage
+ checkApiErrors = checkApiConfig.errors
+ checkApiWarnings = checkApiConfig.warnings
+ checkApiHidden = checkApiConfig.hidden
+ newApiFile = newApi
+ oldApiFile = oldApi
+ whitelistErrorsFile = whitelist
+ doFirst {
+ logger.lifecycle("Verifying ${newApi.name} " +
+ "against ${oldApi?.name ?: "nothing"}...")
+ }
+ }
+
+// configuration file for setting up api diffs and api docs
+private fun registerJavaProjectForDocsTask(task: Javadoc, javaCompileTask: JavaCompile) {
+ task.dependsOn(javaCompileTask)
+ task.source(javaCompileTask.source)
+ val project = task.project
+ task.classpath += project.files(javaCompileTask.classpath) +
+ project.files(javaCompileTask.destinationDir)
+}
+
+// configuration file for setting up api diffs and api docs
+private fun registerAndroidProjectForDocsTask(task: Javadoc, releaseVariant: LibraryVariant) {
+ task.dependsOn(releaseVariant.javaCompile)
+ val packageDir = releaseVariant.applicationId.replace('.', '/')
+ val sources = releaseVariant.javaCompile.source.filter { file ->
+ file.name != "R.java" || file.parent.endsWith(packageDir)
+ }
+ task.source(sources)
+ task.classpath += releaseVariant.getCompileClasspath(null) +
+ task.project.files(releaseVariant.javaCompile.destinationDir)
+}
+
+private fun createUpdateApiTask(project: Project, checkApiRelease: CheckApiTask) =
+ project.tasks.createWithConfig("updateApi", UpdateApiTask::class.java) {
+ group = JavaBasePlugin.VERIFICATION_GROUP
+ description = "Updates the candidate API file to incorporate valid changes."
+ newApiFile = checkApiRelease.newApiFile
+ oldApiFile = getApiFile(project.projectDir, project.version())
+ whitelistErrors = checkApiRelease.whitelistErrors
+ whitelistErrorsFile = checkApiRelease.whitelistErrorsFile
+
+ doFirst {
+ // Replace the expected whitelist with the detected whitelist.
+ whitelistErrors = checkApiRelease.detectedWhitelistErrors
+ }
+ }
+
+/**
+ * Converts the <code>fromApi</code>.txt file (or the most recently released
+ * X.Y.Z.txt if not explicitly defined using -PfromAPi=<file>) to XML format
+ * for use by JDiff.
+ */
+private fun createOldApiXml(project: Project, doclavaConfig: Configuration) =
+ project.tasks.createWithConfig("oldApiXml", ApiXmlConversionTask::class.java) {
+ val regex = Regex("(\\d+\\.){2}\\d+")
+ val toApi = project.processProperty("toApi")
+ val fromApi = project.processProperty("fromApi")
+ classpath = project.files(doclavaConfig.resolve())
+ val rootFolder = project.projectDir
+ if (fromApi != null) {
+ // Use an explicit API file.
+ inputApiFile = File(rootFolder, "api/$fromApi.txt")
+ } else if (toApi != null && regex.matches(toApi)) {
+ // If toApi matches released API (X.Y.Z) format, use the most recently
+ // released API file prior to toApi.
+ inputApiFile = getLastReleasedApiFile(rootFolder, toApi)
+ } else {
+ // Use the most recently released API file.
+ inputApiFile = getApiFile(rootFolder, project.version())
+ }
+
+ outputApiXmlFile = File(project.docsDir(),
+ "release/${stripExtension(inputApiFile.name)}.xml")
+
+ dependsOn(doclavaConfig)
+ }
+
+/**
+ * Converts the <code>toApi</code>.txt file (or current.txt if not explicitly
+ * defined using -PtoApi=<file>) to XML format for use by JDiff.
+ */
+private fun createNewApiXmlTask(
+ project: Project,
+ generateApi: DoclavaTask,
+ doclavaConfig: Configuration) =
+ project.tasks.createWithConfig("newApiXml", ApiXmlConversionTask::class.java) {
+ classpath = project.files(doclavaConfig.resolve())
+ val toApi = project.processProperty("toApi")
+
+ if (toApi != null) {
+ // Use an explicit API file.
+ inputApiFile = File(project.projectDir, "api/$toApi.txt")
+ } else {
+ // Use the current API file (e.g. current.txt).
+ inputApiFile = generateApi.apiFile
+ dependsOn(generateApi, doclavaConfig)
+ }
+
+ outputApiXmlFile = File(project.docsDir(),
+ "release/${stripExtension(inputApiFile.name)}.xml")
+ }
+
+/**
+ * Generates API diffs.
+ * <p>
+ * By default, diffs are generated for the delta between current.txt and the
+ * next most recent X.Y.Z.txt API file. Behavior may be changed by specifying
+ * one or both of -PtoApi and -PfromApi.
+ * <p>
+ * If both fromApi and toApi are specified, diffs will be generated for
+ * fromApi -> toApi. For example, 25.0.0 -> 26.0.0 diffs could be generated by
+ * using:
+ * <br><code>
+ * ./gradlew generateDiffs -PfromApi=25.0.0 -PtoApi=26.0.0
+ * </code>
+ * <p>
+ * If only toApi is specified, it MUST be specified as X.Y.Z and diffs will be
+ * generated for (release before toApi) -> toApi. For example, 24.2.0 -> 25.0.0
+ * diffs could be generated by using:
+ * <br><code>
+ * ./gradlew generateDiffs -PtoApi=25.0.0
+ * </code>
+ * <p>
+ * If only fromApi is specified, diffs will be generated for fromApi -> current.
+ * For example, lastApiReview -> current diffs could be generated by using:
+ * <br><code>
+ * ./gradlew generateDiffs -PfromApi=lastApiReview
+ * </code>
+ * <p>
+ */
+private fun createGenerateDiffsTask(
+ project: Project,
+ oldApiTask: ApiXmlConversionTask,
+ newApiTask: ApiXmlConversionTask,
+ jdiffConfig: Configuration) =
+ project.tasks.createWithConfig("generateDiffs", JDiffTask::class.java) {
+ // Base classpath is Android SDK, sub-projects add their own.
+ classpath = project.androidJar()
+
+ // JDiff properties.
+ oldApiXmlFile = oldApiTask.outputApiXmlFile
+ newApiXmlFile = newApiTask.outputApiXmlFile
+
+ val newApi = newApiXmlFile.name.substringBeforeLast('.')
+ val docsDir = project.rootProject.docsDir()
+
+ newJavadocPrefix = "../../../../../reference/"
+ destinationDir = File(docsDir, "online/sdk/support_api_diff/${project.name}/$newApi")
+
+ // Javadoc properties.
+ docletpath = jdiffConfig.resolve()
+ title = "Support Library API Differences Report"
+
+ exclude("**/BuildConfig.java", "**/R.java")
+ dependsOn(oldApiTask, newApiTask, jdiffConfig)
+ }
+
+// Generates a distribution artifact for online docs.
+private fun createDistDocsTask(project: Project, generateDocs: DoclavaTask) =
+ project.tasks.createWithConfig("distDocs", Zip::class.java) {
+ dependsOn(generateDocs)
+ group = JavaBasePlugin.DOCUMENTATION_GROUP
+ description = "Generates distribution artifact for d.android.com-style documentation."
+ from(generateDocs.destinationDir)
+ baseName = "android-support-docs"
+ version = project.buildNumber()
+
+ doLast {
+ logger.lifecycle("'Wrote API reference to $archivePath")
+ }
+ }
+
+// Set up platform API files for federation.
+private fun createGenerateSdkApiTask(project: Project, doclavaConfig: Configuration): Task =
+ if (project.androidApiTxt() != null) {
+ project.tasks.createWithConfig("generateSdkApi", Copy::class.java) {
+ description = "Copies the API files for the current SDK."
+ // Export the API files so this looks like a DoclavaTask.
+ from(project.androidApiTxt()!!.absolutePath)
+ val apiFile = sdkApiFile(project)
+ into(apiFile.parent)
+ rename { apiFile.name }
+ // Register the fake removed file as an output.
+ val removedApiFile = removedSdkApiFile(project)
+ outputs.file(removedApiFile)
+ doLast { removedApiFile.createNewFile() }
+ }
+ } else {
+ project.tasks.createWithConfig("generateSdkApi", DoclavaTask::class.java) {
+ dependsOn(doclavaConfig)
+ description = "Generates API files for the current SDK."
+ setDocletpath(doclavaConfig.resolve())
+ destinationDir = project.docsDir()
+ classpath = project.androidJar()
+ source(project.zipTree(project.androidSrcJar()))
+ apiFile = sdkApiFile(project)
+ removedApiFile = removedSdkApiFile(project)
+ generateDocs = false
+ coreJavadocOptions {
+ addStringOption("stubpackages", "android.*")
+ }
+ }
+ }
+
+private fun createGenerateDocsTask(
+ project: Project,
+ generateSdkApiTask: Task,
+ doclavaConfig: Configuration,
+ supportRootFolder: File) =
+ project.tasks.createWithConfig("generateDocs", GenerateDocsTask::class.java) {
+ dependsOn(generateSdkApiTask, doclavaConfig)
+ group = JavaBasePlugin.DOCUMENTATION_GROUP
+ description = "Generates d.android.com-style documentation. To generate offline docs " +
+ "use \'-PofflineDocs=true\' parameter."
+
+ setDocletpath(doclavaConfig.resolve())
+ val offline = project.processProperty("offlineDocs") != null
+ destinationDir = File(project.docsDir(), if (offline) "offline" else "online")
+ classpath = project.androidJar()
+ val hidden = listOf<Int>(105, 106, 107, 111, 112, 113, 115, 116, 121)
+ doclavaErrors = ((101..122) - hidden).toSet()
+ doclavaWarnings = emptySet()
+ doclavaHidden += hidden
+
+ addSinceFilesFrom(supportRootFolder)
+
+ coreJavadocOptions {
+ addStringOption("templatedir",
+ "$supportRootFolder/../../external/doclava/res/assets/templates-sdk")
+ addStringOption("samplesdir", "$supportRootFolder/samples")
+ addMultilineMultiValueOption("federate").value = listOf(
+ listOf("Android", "https://developer.android.com")
+ )
+ addMultilineMultiValueOption("federationapi").value = listOf(
+ listOf("Android", sdkApiFile(project).absolutePath)
+ )
+ addMultilineMultiValueOption("hdf").value = listOf(
+ listOf("android.whichdoc", "online"),
+ listOf("android.hasSamples", "true"),
+ listOf("dac", "true")
+ )
+
+ // Specific to reference docs.
+ if (!offline) {
+ addStringOption("toroot", "/")
+ addBooleanOption("devsite", true)
+ addStringOption("dac_libraryroot", project.docsDac().libraryroot)
+ addStringOption("dac_dataname", project.docsDac().dataname)
+ }
+
+ exclude("**/BuildConfig.java")
+ }
+
+ addArtifactsAndSince()
+ }
+
+private fun initializeApiChecksForProject(
+ project: Project,
+ generateDocs: GenerateDocsTask,
+ createArchive: Task): Pair<DoclavaTask, JDiffTask> {
+ if (!project.hasProperty("docsDir")) {
+ project.extensions.add("docsDir", File(project.rootProject.docsDir(), project.name))
+ }
+ val artifact = "${project.group}:${project.name}:${project.version}"
+ val version = project.version()
+ val workingDir = project.projectDir
+
+ val doclavaConfiguration = project.rootProject.configurations.getByName("doclava")
+ val docletClasspath = doclavaConfiguration.resolve()
+ val generateApi = createGenerateApiTask(project, docletClasspath)
+ generateApi.dependsOn(doclavaConfiguration)
+ val verifyUpdateTask = createVerifyUpdateApiAllowedTask(project)
+
+ // Make sure the API surface has not broken since the last release.
+ val lastReleasedApiFile = getLastReleasedApiFile(workingDir, version.toString())
+
+ val whitelistFile = lastReleasedApiFile?.let { apiFile ->
+ File(lastReleasedApiFile.parentFile, stripExtension(apiFile.name) + ".ignore")
+ }
+ val checkApiRelease = createCheckApiTask(project,
+ "checkApiRelease",
+ docletClasspath,
+ CHECK_API_CONFIG_RELEASE,
+ lastReleasedApiFile,
+ generateApi.apiFile!!,
+ whitelistFile)
+ checkApiRelease.dependsOn(generateApi)
+
+ // Allow a comma-delimited list of whitelisted errors.
+ if (project.hasProperty("ignore")) {
+ checkApiRelease.whitelistErrors = (project.properties["ignore"] as String)
+ .split(',').toSet()
+ }
+
+ // Check whether the development API surface has changed.
+ val verifyConfig = if (version.isPatch) CHECK_API_CONFIG_PATCH else CHECK_API_CONFIG_DEVELOP
+ val currentApiFile = getApiFile(workingDir, version)
+ val checkApi = createCheckApiTask(project,
+ "checkApi",
+ docletClasspath,
+ verifyConfig,
+ currentApiFile,
+ generateApi.apiFile!!,
+ null)
+ checkApi.dependsOn(generateApi, checkApiRelease)
+
+ checkApi.group = JavaBasePlugin.VERIFICATION_GROUP
+ checkApi.description = "Verify the API surface."
+
+ val updateApiTask = createUpdateApiTask(project, checkApiRelease)
+ updateApiTask.dependsOn(checkApiRelease, verifyUpdateTask)
+ val newApiTask = createNewApiXmlTask(project, generateApi, doclavaConfiguration)
+ val oldApiTask = createOldApiXml(project, doclavaConfiguration)
+
+ val jdiffConfiguration = project.rootProject.configurations.getByName("jdiff")
+ val generateDiffTask = createGenerateDiffsTask(project,
+ oldApiTask,
+ newApiTask,
+ jdiffConfiguration)
+ generateDiffTask.dependsOn(generateDocs)
+
+ // Track API change history.
+ generateDocs.addSinceFilesFrom(project.projectDir)
+
+ // Associate current API surface with the Maven artifact.
+ generateDocs.addArtifact(generateApi.apiFile!!.absolutePath, artifact)
+ generateDocs.dependsOn(generateApi)
+ createArchive.dependsOn(checkApi)
+ return (generateApi to generateDiffTask)
+}
+
+private open class GenerateDocsTask : DoclavaTask() {
+
+ private data class Since(val path: String, val apiLevel: String)
+ private data class Artifact(val path: String, val artifact: String)
+
+ private val sinces = mutableListOf<Since>()
+ private val artifacts = mutableListOf<Artifact>()
+
+ fun addArtifactsAndSince() {
+ doFirst {
+ coreJavadocOptions {
+ if (sinces.isNotEmpty()) {
+ addMultilineMultiValueOption("since").value = sinces.map { (path, apiLevel) ->
+ listOf(path, apiLevel)
+ }
+ }
+
+ if (artifacts.isNotEmpty()) {
+ addMultilineMultiValueOption("artifact").value = artifacts.map { artifact ->
+ listOf(artifact.path, artifact.artifact)
+ }
+ }
+ }
+ }
+ }
+
+ fun addSinceFilesFrom(dir: File) {
+ val regex = Regex("(\\d+\\.\\d+\\.\\d).txt")
+ val apiDir = File(dir, "api")
+ apiDir.listFiles { file ->
+ file.isFile && regex.matches(file.name)
+ }.forEach { apiFile ->
+ val matchResult = regex.matchEntire(apiFile.name)!!
+ sinces.add(Since(apiFile.absolutePath, matchResult.groups[1]!!.value))
+ }
+ }
+
+ fun addArtifact(path: String, artifact: String) = artifacts.add(Artifact(path, artifact))
+}
+
+private fun configure(root: Project, createArchiveTask: Task, supportRootFolder: File) {
+ val doclavaConfiguration = root.configurations.getByName("doclava")
+ val generateSdkApiTask = createGenerateSdkApiTask(root, doclavaConfiguration)
+
+ val generateDocsTask = createGenerateDocsTask(root, generateSdkApiTask,
+ doclavaConfiguration, supportRootFolder)
+ createDistDocsTask(root, generateDocsTask)
+
+ root.subprojects { subProject ->
+ subProject.afterEvaluate { project ->
+ val extension = if (project.hasProperty("supportLibrary")) {
+ project.properties["supportLibrary"] as SupportLibraryExtension
+ } else {
+ null
+ }
+ if (extension == null || !extension.publish) {
+ project.logger.info("Project ${project.name} is not published, ignoring API tasks.")
+ return@afterEvaluate
+ }
+
+ if (!extension.generateDocs) {
+ project.logger.info("Project ${project.name} specified generateDocs = false, " +
+ "ignoring API tasks.")
+ return@afterEvaluate
+ }
+
+ val library = project.extensions.findByType(LibraryExtension::class.java)
+ if (library != null) {
+ library.libraryVariants.all { variant ->
+ if (variant.name == "release") {
+ registerAndroidProjectForDocsTask(generateDocsTask, variant)
+ if (!hasJavaSources(variant)) {
+ return@all
+ }
+ if (!hasApiFolder(project)) {
+ project.logger.info("Project ${project.name} doesn't have " +
+ "an api folder, ignoring API tasks.")
+ return@all
+ }
+ val (generateApi, generateDiffs) = initializeApiChecksForProject(project,
+ generateDocsTask, createArchiveTask)
+ registerAndroidProjectForDocsTask(generateApi, variant)
+ registerAndroidProjectForDocsTask(generateDiffs, variant)
+ }
+ }
+ } else if (project.hasProperty("compileJava")) {
+ val compileJava = project.properties["compileJava"] as JavaCompile
+ registerJavaProjectForDocsTask(generateDocsTask, compileJava)
+ if (!hasApiFolder(project)) {
+ project.logger.info("Project ${project.name} doesn't have an api folder, " +
+ "ignoring API tasks.")
+ return@afterEvaluate
+ }
+ project.afterEvaluate { proj ->
+ val (generateApi, generateDiffs) = initializeApiChecksForProject(proj,
+ generateDocsTask,
+ createArchiveTask)
+ registerJavaProjectForDocsTask(generateApi, compileJava)
+ registerJavaProjectForDocsTask(generateDiffs, compileJava)
+ }
+ }
+ }
+ }
+}
+
+private fun sdkApiFile(project: Project) = File(project.docsDir(), "release/sdk_current.txt")
+private fun removedSdkApiFile(project: Project) = File(project.docsDir(), "release/sdk_removed.txt")
+
+private fun TaskContainer.createWithConfig(name: String, config: Task.() -> Unit) =
+ create(name) { task -> task.config() }
+
+private fun <T : Task> TaskContainer.createWithConfig(
+ name: String, taskClass: Class<T>,
+ config: T.() -> Unit) =
+ create(name, taskClass) { task -> task.config() }
+
+// Nasty part. Get rid of that eventually!
+private fun Project.docsDir(): File = properties["docsDir"] as File
+
+private fun Project.androidJar() = rootProject.properties["androidJar"] as FileCollection
+
+private fun Project.androidSrcJar() = rootProject.properties["androidSrcJar"] as File
+
+private fun Project.version() = Version(project.properties["version"] as String)
+
+private fun Project.buildNumber() = properties["buildNumber"] as String
+
+private fun Project.androidApiTxt() = properties["androidApiTxt"] as? File
+
+private fun Project.docsDac() = properties["docsDac"] as DacOptions
+
+private fun Project.processProperty(name: String) =
+ if (hasProperty(name)) {
+ properties[name] as String
+ } else {
+ null
+ }
diff --git a/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt b/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
index b347415..5eaa7dd 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
@@ -24,7 +24,7 @@
import org.gradle.api.Plugin
import org.gradle.api.Project
import java.io.File
-import java.util.*
+import java.util.Properties
/**
* Support library specific com.android.library plugin that sets common configurations needed for
@@ -37,6 +37,8 @@
SupportLibraryExtension::class.java, project)
apply(project, supportLibraryExtension)
+ val isCoreSupportLibrary = project.rootProject.name == "support"
+
project.afterEvaluate {
val library = project.extensions.findByType(LibraryExtension::class.java)
?: return@afterEvaluate
@@ -55,11 +57,11 @@
// Java 8 is only fully supported on API 24+ and not all Java 8 features are binary
// compatible with API < 24, so use Java 7 for both source AND target.
- val javaVersion: JavaVersion;
+ val javaVersion: JavaVersion
if (supportLibraryExtension.java8Library) {
if (library.defaultConfig.minSdkVersion.apiLevel < 24) {
throw IllegalArgumentException("Libraries can only support Java 8 if "
- + "minSdkVersion is 24 or higher");
+ + "minSdkVersion is 24 or higher")
}
javaVersion = JavaVersion.VERSION_1_8
} else {
@@ -75,6 +77,21 @@
project.apply(mapOf("plugin" to "com.android.library"))
project.apply(mapOf("plugin" to ErrorProneBasePlugin::class.java))
+ project.configurations.all { configuration ->
+ if (isCoreSupportLibrary) {
+ // In projects which compile as part of the "core" support libraries (which include
+ // the annotations), replace any transitive pointer to the deployed Maven
+ // coordinate version of annotations with a reference to the local project. These
+ // usually originate from test dependencies and otherwise cause multiple copies on
+ // the classpath. We do not do this for non-"core" projects as they need to
+ // depend on the Maven coordinate variant.
+ configuration.resolutionStrategy.dependencySubstitution.apply {
+ substitute(module("com.android.support:support-annotations"))
+ .with(project(":support-annotations"))
+ }
+ }
+ }
+
val library = project.extensions.findByType(LibraryExtension::class.java)
?: throw Exception("Failed to find Android extension")
@@ -111,7 +128,7 @@
library.libraryVariants.all { libraryVariant ->
if (libraryVariant.getBuildType().getName().equals("errorProne")) {
@Suppress("DEPRECATION")
- libraryVariant.getJavaCompile().setToolChain(toolChain);
+ libraryVariant.getJavaCompile().setToolChain(toolChain)
@Suppress("DEPRECATION")
val compilerArgs = libraryVariant.getJavaCompile().options.compilerArgs
@@ -119,12 +136,16 @@
"-XDcompilePolicy=simple", // Workaround for b/36098770
// Enforce the following checks.
+ "-Xep:RestrictTo:OFF",
+ "-Xep:ParameterNotNullable:ERROR",
"-Xep:MissingOverride:ERROR",
+ "-Xep:JdkObsolete:ERROR",
"-Xep:NarrowingCompoundAssignment:ERROR",
"-Xep:ClassNewInstance:ERROR",
"-Xep:ClassCanBeStatic:ERROR",
"-Xep:SynchronizeOnNonFinalField:ERROR",
- "-Xep:OperatorPrecedence:ERROR"
+ "-Xep:OperatorPrecedence:ERROR",
+ "-Xep:IntLongMath:ERROR"
)
}
}
@@ -155,7 +176,7 @@
// Set baseline file for all legacy lint warnings.
if (System.getenv("GRADLE_PLUGIN_VERSION") != null) {
lintOptions.check("NewApi")
- } else {
+ } else if (baseline.exists()) {
lintOptions.baseline(baseline)
}
}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/android/support/SupportLibraryExtension.kt b/buildSrc/src/main/kotlin/android/support/SupportLibraryExtension.kt
index 088e169..d5519c7 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportLibraryExtension.kt
+++ b/buildSrc/src/main/kotlin/android/support/SupportLibraryExtension.kt
@@ -34,6 +34,13 @@
var java8Library = false
var legacySourceLocation = false
var publish = false
+ /**
+ * This flag works only if publish flag is "true".
+ * It is useful for modules that are used for tooling. For example room annotation
+ * processor module is published, but we don't want to expose any docs, because we don't
+ * support using it as a library.
+ */
+ var generateDocs = true
fun license(closure: Closure<*>): License {
val license = project.configure(License(), closure) as License
@@ -47,7 +54,8 @@
companion object {
@JvmField
- val ARCHITECTURE_URL = "https://developer.android.com/topic/libraries/architecture/index.html"
+ val ARCHITECTURE_URL
+ = "https://developer.android.com/topic/libraries/architecture/index.html"
@JvmField
val SUPPORT_URL = "http://developer.android.com/tools/extras/support-library.html"
}
diff --git a/buildSrc/src/main/kotlin/android/support/dependencies/Dependencies.kt b/buildSrc/src/main/kotlin/android/support/dependencies/Dependencies.kt
new file mode 100644
index 0000000..e32cacd
--- /dev/null
+++ b/buildSrc/src/main/kotlin/android/support/dependencies/Dependencies.kt
@@ -0,0 +1,43 @@
+/*
+ * 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 android.support.dependencies
+
+const val AUTO_COMMON = "com.google.auto:auto-common:0.6"
+const val ANTLR = "org.antlr:antlr4:4.5.3"
+const val APACHE_COMMONS_CODEC = "commons-codec:commons-codec:1.10"
+const val DEXMAKER_MOCKITO = "com.linkedin.dexmaker:dexmaker-mockito:2.2.0"
+const val ESPRESSO_CONTRIB = "com.android.support.test.espresso:espresso-contrib:3.0.1"
+const val ESPRESSO_CORE = "com.android.support.test.espresso:espresso-core:3.0.1"
+const val GOOGLE_COMPILE_TESTING = "com.google.testing.compile:compile-testing:0.11"
+const val GSON = "com.google.code.gson:gson:2.8.0"
+const val GUAVA = "com.google.guava:guava:21.0"
+const val INTELLIJ_ANNOTATIONS = "com.intellij:annotations:12.0"
+const val JAVAPOET = "com.squareup:javapoet:1.8.0"
+const val JSR250 = "javax.annotation:javax.annotation-api:1.2"
+const val JUNIT = "junit:junit:4.12"
+const val KOTLIN_STDLIB = "org.jetbrains.kotlin:kotlin-stdlib:1.2.0"
+const val MOCKITO_CORE = "org.mockito:mockito-core:2.7.6"
+const val REACTIVE_STREAMS = "org.reactivestreams:reactive-streams:1.0.0"
+const val RX_JAVA = "io.reactivex.rxjava2:rxjava:2.0.6"
+const val TEST_RUNNER = "com.android.support.test:runner:1.0.1"
+const val TEST_RULES = "com.android.support.test:rules:1.0.1"
+/**
+ * this Xerial version is newer than we want but we need it to fix
+ * https://github.com/xerial/sqlite-jdbc/issues/97
+ * https://github.com/xerial/sqlite-jdbc/issues/267
+ */
+const val XERIAL = "org.xerial:sqlite-jdbc:3.20.1"
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/android/support/doclava/DoclavaJavadocOptionFileOption.kt b/buildSrc/src/main/kotlin/android/support/doclava/DoclavaJavadocOptionFileOption.kt
new file mode 100644
index 0000000..828fb25
--- /dev/null
+++ b/buildSrc/src/main/kotlin/android/support/doclava/DoclavaJavadocOptionFileOption.kt
@@ -0,0 +1,61 @@
+/*
+ * 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 android.support.doclava
+
+import org.gradle.external.javadoc.internal.AbstractJavadocOptionFileOption
+import org.gradle.external.javadoc.internal.JavadocOptionFileWriterContext
+import java.io.IOException
+import java.util.ArrayList
+
+//TODO: remove this once https://github.com/gradle/gradle/issues/2354 is fixed
+class DoclavaJavadocOptionFileOption : AbstractJavadocOptionFileOption<Iterable<String>> {
+
+ constructor(option: String) : super(option, null)
+
+ constructor(option: String, value: Iterable<String>?) : super(option, value)
+
+ @Throws(IOException::class)
+ override fun write(writerContext: JavadocOptionFileWriterContext) {
+ writerContext.writeOptionHeader(getOption())
+ val args = getValue()
+ if (args != null) {
+ val iter = args.iterator()
+ while (true) {
+ writerContext.writeValue(iter.next())
+ if (!iter.hasNext()) {
+ break
+ }
+ writerContext.write(" ")
+ }
+ }
+ writerContext.newLine()
+ }
+ /**
+ * @return a deep copy of the option
+ */
+ override fun duplicate(): DoclavaJavadocOptionFileOption {
+ val value = getValue()
+ val valueCopy: ArrayList<String>?
+ if (value != null) {
+ valueCopy = ArrayList()
+ valueCopy += value
+ } else {
+ valueCopy = null
+ }
+ return DoclavaJavadocOptionFileOption(getOption(), valueCopy)
+ }
+}
diff --git a/buildSrc/src/main/kotlin/android/support/doclava/DoclavaTask.kt b/buildSrc/src/main/kotlin/android/support/doclava/DoclavaTask.kt
new file mode 100644
index 0000000..48a98f9
--- /dev/null
+++ b/buildSrc/src/main/kotlin/android/support/doclava/DoclavaTask.kt
@@ -0,0 +1,213 @@
+/*
+ * 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 android.support.doclava
+
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.Optional
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.OutputFile
+import org.gradle.api.tasks.javadoc.Javadoc
+import org.gradle.external.javadoc.CoreJavadocOptions
+import java.io.File
+
+// external/doclava/src/com/google/doclava/Errors.java
+private val DEFAULT_DOCLAVA_ERRORS = setOf<Int>(
+ 101, // unresolved link
+ 103, // unknown tag
+ 104 // unknown param name
+)
+
+private val DEFAULT_DOCLAVA_WARNINGS = setOf<Int>(121 /* hidden type param */)
+
+private val DEFAULT_DOCLAVA_HIDDEN = setOf<Int>(
+ 111, // hidden super class
+ 113 // @deprecation mismatch
+)
+
+private fun <E> CoreJavadocOptions.addMultilineMultiValueOption(
+ name: String, values: Collection<E>) {
+ addMultilineMultiValueOption(name).setValue(values.map { listOf(it.toString()) })
+}
+
+open class DoclavaTask : Javadoc() {
+
+ // All lowercase name to match MinimalJavadocOptions#docletpath
+ private var docletpath: List<File> = emptyList()
+
+ // doclava error types which will cause the build to fail
+ @Input
+ var doclavaErrors = DEFAULT_DOCLAVA_ERRORS
+
+ @Input
+ var doclavaWarnings = DEFAULT_DOCLAVA_WARNINGS
+
+ // spammy doclava warnings which we want to hide
+ @Input
+ var doclavaHidden = DEFAULT_DOCLAVA_HIDDEN
+
+ /**
+ * If non-null, the list of packages that will be treated as if they were
+ * marked with {@literal @hide}.<br>
+ * Packages names will be matched exactly; sub-packages are not automatically recognized.
+ */
+ @Optional
+ @Input
+ var hiddenPackages: Collection<String>? = null
+
+ /**
+ * If non-null and not-empty, the whitelist of packages that will be present in the generated
+ * stubs; if null or empty, then all packages have stubs generated.<br>
+ * Wildcards are accepted.
+ */
+ @Optional
+ @Input
+ var stubPackages: Set<String>? = null
+
+ @Input
+ var generateDocs = true
+
+ /**
+ * If non-null, the location of where to place the generated api file.
+ * If this is non-null, then {@link #removedApiFile} must be non-null as well.
+ */
+ @Optional
+ @OutputFile
+ var apiFile: File? = null
+
+ /**
+ * If non-null, the location of where to place the generated removed api file.
+ * If this is non-null, then {@link #apiFile} must be non-null as well.
+ */
+ @Optional
+ @OutputFile
+ var removedApiFile: File? = null
+
+ /**
+ * If non-null, the location of the generated keep list.
+ */
+ @Optional
+ @OutputFile
+ var keepListFile: File? = null
+
+ /**
+ * If non-null, the location to put the generated stub sources.
+ */
+ @Optional
+ @OutputDirectory
+ var stubsDir: File? = null
+
+ init {
+ setFailOnError(true)
+ options.doclet = "com.google.doclava.Doclava"
+ options.encoding("UTF-8")
+ options.quiet()
+ // doclava doesn't understand '-doctitle'
+ title = null
+ maxMemory = "1280m"
+ // If none of generateDocs, apiFile, keepListFile, or stubJarsDir are true, then there is
+ // no work to do.
+ onlyIf({ generateDocs || apiFile != null || keepListFile != null || stubsDir != null })
+ }
+
+ /**
+ * The doclet path which has the {@code com.gogole.doclava.Doclava} class.
+ * This option will override any doclet path set in this instance's {@link #options JavadocOptions}.
+ * @see MinimalJavadocOptions#getDocletpath()
+ */
+ @InputFiles
+ fun getDocletpath(): List<File> {
+ return docletpath
+ }
+
+ /**
+ * Sets the doclet path which has the {@code com.gogole.doclava.Doclava} class.
+ * This option will override any doclet path set in this instance's {@link #options JavadocOptions}.
+ * @see MinimalJavadocOptions#setDocletpath(java.util.List)
+ */
+ fun setDocletpath(docletpath: Collection<File>) {
+ this.docletpath = docletpath.toList()
+ // Go ahead and keep the docletpath in our JavadocOptions object in sync.
+ options.docletpath = docletpath.toList()
+ }
+
+ fun setDoclavaErrors(errors: List<Int> ) {
+ // Make it serializable.
+ doclavaErrors = errors.toSet()
+ }
+
+ fun setDoclavaWarnings(warnings: List<Int>) {
+ // Make it serializable.
+ doclavaWarnings = warnings.toSet()
+ }
+
+ fun setDoclavaHidden(hidden: List<Int>) {
+ // Make it serializable.
+ doclavaHidden = hidden.toSet()
+ }
+
+ /**
+ * "Configures" this DoclavaTask with parameters that might not be at their final values
+ * until this task is run.
+ */
+ private fun configureDoclava() = (options as CoreJavadocOptions).apply {
+
+ docletpath = this@DoclavaTask.docletpath
+
+ // configure doclava error/warning/hide levels
+ addMultilineMultiValueOption("hide", doclavaHidden)
+ addMultilineMultiValueOption("warning", doclavaWarnings)
+ addMultilineMultiValueOption("error", doclavaErrors)
+
+ if (hiddenPackages != null) {
+ addMultilineMultiValueOption("hidePackage", hiddenPackages!!)
+ }
+
+ if (!generateDocs) {
+ addOption(DoclavaJavadocOptionFileOption("nodocs"))
+ }
+
+ // If requested, generate the API files.
+ if (apiFile != null) {
+ addFileOption("api", apiFile)
+ addFileOption("removedApi", removedApiFile)
+ }
+
+ // If requested, generate the keep list.
+ addFileOption("proguard", keepListFile)
+
+ // If requested, generate stubs.
+ if (stubsDir != null) {
+ addFileOption("stubs", stubsDir)
+ val stubs = stubPackages
+ if (stubs != null) {
+ addStringOption("stubpackages", stubs.joinToString(":"))
+ }
+ }
+ // Always treat this as an Android docs task.
+ addOption(DoclavaJavadocOptionFileOption("android"))
+ }
+
+ fun coreJavadocOptions(configure: CoreJavadocOptions.() -> Unit) =
+ (options as CoreJavadocOptions).configure()
+
+ override fun generate() {
+ configureDoclava()
+ super.generate()
+ }
+}
+
diff --git a/car/AndroidManifest.xml b/car/AndroidManifest.xml
index 4e6d80f..854e097 100644
--- a/car/AndroidManifest.xml
+++ b/car/AndroidManifest.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.support.car">
+ package="androidx.car">
</manifest>
diff --git a/car/build.gradle b/car/build.gradle
index c1be3a3..3970df9 100644
--- a/car/build.gradle
+++ b/car/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
plugins {
@@ -11,11 +12,11 @@
api project(':support-v4')
api project(':recyclerview-v7')
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_contrib, { exclude group: 'com.android.support' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(ESPRESSO_CONTRIB, libs.exclude_support)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
}
android {
diff --git a/car/lint-baseline.xml b/car/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/car/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/car/res/drawable/car_borderless_button_text_color.xml b/car/res/drawable/car_borderless_button_text_color.xml
new file mode 100644
index 0000000..ff27db5
--- /dev/null
+++ b/car/res/drawable/car_borderless_button_text_color.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 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.
+-->
+<!-- Default text colors for car buttons when enabled/disabled. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@color/car_grey_700" android:state_enabled="false"/>
+ <item android:color="?android:attr/colorPrimary"/>
+</selector>
diff --git a/car/res/drawable/car_button_background.xml b/car/res/drawable/car_button_background.xml
index 3b139d9..1a8995c 100644
--- a/car/res/drawable/car_button_background.xml
+++ b/car/res/drawable/car_button_background.xml
@@ -18,14 +18,14 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false">
<shape android:shape="rectangle">
- <corners android:radius="@dimen/car_button_radius" />
+ <corners android:radius="@dimen/car_button_radius"/>
<solid android:color="@color/car_grey_300"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
- <corners android:radius="@dimen/car_button_radius" />
- <solid android:color="@color/car_highlight"/>
+ <corners android:radius="@dimen/car_button_radius"/>
+ <solid android:color="?android:attr/colorPrimary"/>
</shape>
</item>
</selector>
diff --git a/car/res/drawable/car_button_text_color.xml b/car/res/drawable/car_button_text_color.xml
index b14ec68..bb8c681 100644
--- a/car/res/drawable/car_button_text_color.xml
+++ b/car/res/drawable/car_button_text_color.xml
@@ -16,6 +16,6 @@
-->
<!-- Default text colors for car buttons when enabled/disabled. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:color="@color/car_grey_700" />
+ <item android:color="@color/car_grey_700" android:state_enabled="false"/>
<item android:color="@color/car_action1"/>
</selector>
diff --git a/car/res/layout/car_drawer.xml b/car/res/layout/car_drawer.xml
index 812acb4..c4ce405 100644
--- a/car/res/layout/car_drawer.xml
+++ b/car/res/layout/car_drawer.xml
@@ -23,7 +23,7 @@
android:background="@color/car_card"
android:paddingTop="@dimen/car_app_bar_height" >
- <android.support.car.widget.PagedListView
+ <androidx.car.widget.PagedListView
android:id="@+id/drawer_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/car/res/layout/car_paged_list_card.xml b/car/res/layout/car_paged_list_card.xml
new file mode 100644
index 0000000..fe5de89
--- /dev/null
+++ b/car/res/layout/car_paged_list_card.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 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.
+ -->
+<android.support.v7.widget.CardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginBottom="@dimen/car_padding_1"
+ app:cardCornerRadius="@dimen/car_radius_1"
+ app:cardBackgroundColor="@color/car_card">
+
+ <include layout="@layout/car_paged_list_item_content" />
+
+</android.support.v7.widget.CardView>
diff --git a/v14/preference/res/values-v21/styles.xml b/car/res/layout/car_paged_list_item.xml
similarity index 66%
rename from v14/preference/res/values-v21/styles.xml
rename to car/res/layout/car_paged_list_item.xml
index 9a85987..c0861d9 100644
--- a/v14/preference/res/values-v21/styles.xml
+++ b/car/res/layout/car_paged_list_item.xml
@@ -12,9 +12,14 @@
~ 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
+ ~ limitations under the License.
-->
-<resources>
- <dimen name="preference_no_icon_padding_start">72dp</dimen>
-</resources>
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:background="@color/car_card">
+ <include layout="@layout/car_paged_list_item_content" />
+
+</FrameLayout>
diff --git a/car/res/layout/car_paged_list_item_content.xml b/car/res/layout/car_paged_list_item_content.xml
new file mode 100644
index 0000000..0e6b809
--- /dev/null
+++ b/car/res/layout/car_paged_list_item_content.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 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.
+ -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+
+ <!-- Primary Action. -->
+ <ImageView
+ android:id="@+id/primary_icon"
+ android:layout_width="@dimen/car_single_line_list_item_height"
+ android:layout_height="@dimen/car_single_line_list_item_height"
+ android:layout_centerVertical="true"/>
+
+ <!-- Text. -->
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_toStartOf="@id/supplemental_actions"
+ android:singleLine="true"
+ android:ellipsize="end"/>
+ <TextView
+ android:id="@+id/body"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_toStartOf="@id/supplemental_actions"/>
+
+ <!-- Supplemental action(s) - supports either 1 supplemental icon or up to 2 action buttons. -->
+ <LinearLayout
+ android:id="@+id/supplemental_actions"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:layout_marginEnd="@dimen/car_keyline_1"
+ android:layout_centerVertical="true"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+ <!-- End icon with divider. -->
+ <View
+ android:id="@+id/supplemental_icon_divider"
+ android:layout_width="@dimen/car_vertical_line_divider_width"
+ android:layout_height="@dimen/car_vertical_line_divider_height"
+ android:layout_marginStart="@dimen/car_padding_4"
+ android:background="@color/car_list_divider"/>
+ <ImageView
+ android:id="@+id/supplemental_icon"
+ android:layout_width="@dimen/car_primary_icon_size"
+ android:layout_height="@dimen/car_primary_icon_size"
+ android:layout_marginStart="@dimen/car_padding_4"
+ android:scaleType="fitCenter"/>
+
+ <!-- Up to 2 action buttons with dividers. -->
+ <View
+ android:id="@+id/action2_divider"
+ android:layout_width="@dimen/car_vertical_line_divider_width"
+ android:layout_height="@dimen/car_vertical_line_divider_height"
+ android:layout_marginStart="@dimen/car_padding_4"
+ android:background="@color/car_list_divider"/>
+ <Button
+ android:id="@+id/action2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/car_padding_4"
+ android:ellipsize="end"
+ android:maxLength="@integer/car_borderless_button_text_length_limit"
+ android:maxLines="1"
+ android:background="@color/car_card"
+ style="@style/CarButton.Borderless"/>
+ <View
+ android:id="@+id/action1_divider"
+ android:layout_width="@dimen/car_vertical_line_divider_width"
+ android:layout_height="@dimen/car_vertical_line_divider_height"
+ android:layout_marginStart="@dimen/car_padding_4"
+ android:background="@color/car_list_divider"/>
+ <Button
+ android:id="@+id/action1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/car_padding_4"
+ android:ellipsize="end"
+ android:maxLength="@integer/car_borderless_button_text_length_limit"
+ android:maxLines="1"
+ android:background="@color/car_card"
+ style="@style/CarButton.Borderless"/>
+ </LinearLayout>
+</RelativeLayout>
diff --git a/car/res/layout/car_paged_recycler_view.xml b/car/res/layout/car_paged_recycler_view.xml
index 47a82ff..d3ca4a3 100644
--- a/car/res/layout/car_paged_recycler_view.xml
+++ b/car/res/layout/car_paged_recycler_view.xml
@@ -19,14 +19,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.car.widget.CarRecyclerView
+ <androidx.car.widget.CarRecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- Putting this as the last child so that it can intercept any touch events on the
scroll buttons. -->
- <android.support.car.widget.PagedScrollBarView
+ <androidx.car.widget.PagedScrollBarView
android:id="@+id/paged_scroll_view"
android:layout_width="@dimen/car_margin"
android:layout_height="match_parent"
diff --git a/car/res/layout/car_paged_scrollbar_buttons.xml b/car/res/layout/car_paged_scrollbar_buttons.xml
index 7dd213a..75d9414 100644
--- a/car/res/layout/car_paged_scrollbar_buttons.xml
+++ b/car/res/layout/car_paged_scrollbar_buttons.xml
@@ -29,7 +29,6 @@
android:background="@drawable/car_pagination_background"
android:focusable="false"
android:hapticFeedbackEnabled="false"
- android:scaleType="center"
android:src="@drawable/ic_up" />
<FrameLayout
@@ -37,8 +36,8 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
- android:layout_marginBottom="@dimen/car_paged_list_view_scrollbar_thumb_margin"
- android:layout_marginTop="@dimen/car_paged_list_view_scrollbar_thumb_margin" >
+ android:layout_marginBottom="@dimen/car_scroll_bar_thumb_margin"
+ android:layout_marginTop="@dimen/car_scroll_bar_thumb_margin" >
<ImageView
android:id="@+id/scrollbar_thumb"
@@ -55,6 +54,5 @@
android:background="@drawable/car_pagination_background"
android:focusable="false"
android:hapticFeedbackEnabled="false"
- android:scaleType="center"
android:src="@drawable/ic_down" />
</LinearLayout>
diff --git a/car/res/values-h1752dp/dimens.xml b/car/res/values-h1752dp/dimens.xml
index 93aa85f..4b6a23d 100644
--- a/car/res/values-h1752dp/dimens.xml
+++ b/car/res/values-h1752dp/dimens.xml
@@ -14,8 +14,8 @@
limitations under the License.
-->
<resources>
+ <!-- Car Component Dimensions -->
<!-- Type Sizings -->
- <dimen name="car_title_size">32sp</dimen>
<dimen name="car_title2_size">40sp</dimen>
<dimen name="car_headline1_size">56sp</dimen>
<dimen name="car_headline2_size">50sp</dimen>
@@ -23,16 +23,31 @@
<dimen name="car_body2_size">32sp</dimen>
<dimen name="car_action1_size">32sp</dimen>
- <!-- Car Component Dimensions -->
- <!-- Application Bar Height -->
- <dimen name="car_app_bar_height">112dp</dimen>
-
- <dimen name="car_touch_target">96dp</dimen>
-
- <!-- Icon dimensions -->
+ <!-- Icons and Buttons -->
+ <!-- Icons -->
<dimen name="car_primary_icon_size">56dp</dimen>
<dimen name="car_secondary_icon_size">36dp</dimen>
- <!-- Line heights -->
+ <!-- Avatars -->
+ <dimen name="car_avatar_size">96dp</dimen>
+
+ <!-- Minimum touch target size. -->
+ <dimen name="car_touch_target_size">96dp</dimen>
+
+ <!-- Application Bar -->
+ <dimen name="car_app_bar_height">112dp</dimen>
+
+ <!-- List Items -->
+ <dimen name="car_single_line_list_item_height">128dp</dimen>
<dimen name="car_double_line_list_item_height">128dp</dimen>
+
+ <!-- Cards -->
+ <dimen name="car_card_header_height">96dp</dimen>
+ <dimen name="car_card_action_bar_height">96dp</dimen>
+
+ <!-- Slide Up Menu -->
+ <dimen name="car_slide_up_menu_initial_height">128dp</dimen>
+
+ <!-- Sub Header -->
+ <dimen name="car_sub_header_height">96dp</dimen>
</resources>
diff --git a/car/res/values-h684dp/dimens.xml b/car/res/values-h684dp/dimens.xml
index 72b04f2..039d377 100644
--- a/car/res/values-h684dp/dimens.xml
+++ b/car/res/values-h684dp/dimens.xml
@@ -15,13 +15,27 @@
-->
<resources>
<!-- Car Component Dimensions -->
+ <!-- Application Bar -->
<dimen name="car_app_bar_height">96dp</dimen>
- <!-- List and Drawer Dimensions -->
+ <!-- List Items -->
+ <dimen name="car_single_line_list_item_height">116dp</dimen>
+ <dimen name="car_double_line_list_item_height">116dp</dimen>
+
+ <!-- Slide Up Menu -->
+ <dimen name="car_slide_up_menu_initial_height">116dp</dimen>
+
+ <!-- Scroll Bar -->
+ <dimen name="car_scroll_bar_padding">@dimen/car_padding_4</dimen>
+
+ <!-- Scroll Bar Thumb -->
+ <dimen name="car_scroll_bar_thumb_margin">@dimen/car_padding_2</dimen>
+
+ <!-- Scroll Bar Buttons -->
+ <dimen name="car_scroll_bar_button_size">76dp</dimen>
+
+ <!-- Drawer Dimensions -->
<dimen name="car_drawer_list_item_icon_size">108dp</dimen>
<dimen name="car_drawer_list_item_small_icon_size">56dp</dimen>
<dimen name="car_drawer_list_item_end_icon_size">56dp</dimen>
-
- <!-- Line heights -->
- <dimen name="car_double_line_list_item_height">116dp</dimen>
</resources>
diff --git a/car/res/values-night/colors.xml b/car/res/values-night/colors.xml
index 2ca5b02..12eb594 100644
--- a/car/res/values-night/colors.xml
+++ b/car/res/values-night/colors.xml
@@ -16,6 +16,7 @@
-->
<resources>
<color name="car_title">@color/car_title_light</color>
+ <color name="car_title2">@color/car_title2_light</color>
<color name="car_body1">@color/car_body1_light</color>
<color name="car_body2">@color/car_body2_light</color>
diff --git a/car/res/values-w1280dp/dimens.xml b/car/res/values-w1280dp/dimens.xml
index ea46dcf..418e51f 100644
--- a/car/res/values-w1280dp/dimens.xml
+++ b/car/res/values-w1280dp/dimens.xml
@@ -14,14 +14,11 @@
limitations under the License.
-->
<resources>
- <dimen name="car_screen_margin_size">148dp</dimen>
- <dimen name="car_scroll_bar_button_size">76dp</dimen>
-
- <dimen name="car_keyline_1">32dp</dimen>
- <dimen name="car_keyline_2">108dp</dimen>
- <dimen name="car_keyline_3">128dp</dimen>
- <dimen name="car_keyline_4">168dp</dimen>
- <dimen name="car_keyline_1_neg">32dp</dimen>
- <dimen name="car_keyline_2_neg">108dp</dimen>
- <dimen name="car_keyline_3_neg">128dp</dimen>
+ <!-- Framework -->
+ <!-- Margin -->
+ <dimen name="car_margin">148dp</dimen>
+
+ <!-- Keylines -->
+ <dimen name="car_keyline_4">182dp</dimen>
+ <dimen name="car_keyline_4_neg">-182dp</dimen>
</resources>
diff --git a/car/res/values-w840dp/integers.xml b/car/res/values-w1280dp/integers.xml
similarity index 84%
rename from car/res/values-w840dp/integers.xml
rename to car/res/values-w1280dp/integers.xml
index 38c0440..62fcf37 100644
--- a/car/res/values-w840dp/integers.xml
+++ b/car/res/values-w1280dp/integers.xml
@@ -14,6 +14,10 @@
limitations under the License.
-->
<resources>
- <integer name="car_screen_num_of_columns">12</integer>
+ <!-- Application Components -->
+ <!-- Cards -->
<integer name="column_card_default_column_span">8</integer>
+
+ <!-- Dialogs -->
+ <integer name="car_dialog_column_number">8</integer>
</resources>
diff --git a/car/res/values-w1920dp/dimens.xml b/car/res/values-w1920dp/dimens.xml
index 9914613..b02ec00 100644
--- a/car/res/values-w1920dp/dimens.xml
+++ b/car/res/values-w1920dp/dimens.xml
@@ -14,5 +14,16 @@
limitations under the License.
-->
<resources>
- <dimen name="car_keyline_4">184dp</dimen>
+ <!-- Framework -->
+ <!-- Margin -->
+ <dimen name="car_margin">192dp</dimen>
+
+ <!-- Gutters -->
+ <dimen name="car_gutter_size">32dp</dimen>
+
+ <!-- Keylines -->
+ <dimen name="car_keyline_1">48dp</dimen>
+ <dimen name="car_keyline_3">152dp</dimen>
+ <dimen name="car_keyline_1_neg">-48dp</dimen>
+ <dimen name="car_keyline_3_neg">-152dp</dimen>
</resources>
diff --git a/car/res/values-w1024dp/dimens.xml b/car/res/values-w1920dp/integers.xml
similarity index 86%
rename from car/res/values-w1024dp/dimens.xml
rename to car/res/values-w1920dp/integers.xml
index b1ae5ba..6519af5 100644
--- a/car/res/values-w1024dp/dimens.xml
+++ b/car/res/values-w1920dp/integers.xml
@@ -14,5 +14,7 @@
limitations under the License.
-->
<resources>
- <dimen name="car_screen_margin_size">112dp</dimen>
+ <!-- Framework -->
+ <!-- Columns -->
+ <integer name="car_column_number">16</integer>
</resources>
diff --git a/car/res/values-w480dp/dimens.xml b/car/res/values-w480dp/dimens.xml
deleted file mode 100644
index 4077e0d..0000000
--- a/car/res/values-w480dp/dimens.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-<resources>
- <dimen name="car_screen_margin_size">24dp</dimen>
-</resources>
diff --git a/car/res/values-w600dp/integers.xml b/car/res/values-w600dp/integers.xml
deleted file mode 100644
index 5dcd8df..0000000
--- a/car/res/values-w600dp/integers.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-<resources>
- <integer name="car_screen_num_of_columns">8</integer>
- <integer name="column_card_default_column_span">6</integer>
-</resources>
diff --git a/car/res/values-w690dp/dimens.xml b/car/res/values-w690dp/dimens.xml
index edf6c59..2d43ac8 100644
--- a/car/res/values-w690dp/dimens.xml
+++ b/car/res/values-w690dp/dimens.xml
@@ -14,11 +14,7 @@
limitations under the License.
-->
<resources>
- <dimen name="car_keyline_1">24dp</dimen>
- <dimen name="car_keyline_2">96dp</dimen>
- <dimen name="car_keyline_3">112dp</dimen>
- <dimen name="car_keyline_4">148dp</dimen>
- <dimen name="car_keyline_1_neg">-24dp</dimen>
- <dimen name="car_keyline_2_neg">-96dp</dimen>
- <dimen name="car_keyline_3_neg">-112dp</dimen>
+ <!-- Framework -->
+ <!-- Margin -->
+ <dimen name="car_margin">112dp</dimen>
</resources>
diff --git a/car/res/values-w1024dp/dimens.xml b/car/res/values-w690dp/integers.xml
similarity index 62%
copy from car/res/values-w1024dp/dimens.xml
copy to car/res/values-w690dp/integers.xml
index b1ae5ba..0eb5837 100644
--- a/car/res/values-w1024dp/dimens.xml
+++ b/car/res/values-w690dp/integers.xml
@@ -14,5 +14,17 @@
limitations under the License.
-->
<resources>
- <dimen name="car_screen_margin_size">112dp</dimen>
+ <!-- Framework -->
+ <!-- Columns -->
+ <integer name="car_column_number">12</integer>
+
+ <!-- Application Components -->
+ <!-- Cards -->
+ <integer name="column_card_default_column_span">12</integer>
+
+ <!-- Dialogs -->
+ <integer name="car_dialog_column_number">10</integer>
+
+ <!-- Slide Up Menu -->
+ <integer name="car_slide_up_menu_column_number">12</integer>
</resources>
diff --git a/car/res/values-w720dp/dimens.xml b/car/res/values-w720dp/dimens.xml
deleted file mode 100644
index b1ae5ba..0000000
--- a/car/res/values-w720dp/dimens.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-<resources>
- <dimen name="car_screen_margin_size">112dp</dimen>
-</resources>
diff --git a/car/res/values-w840dp/dimens.xml b/car/res/values-w930dp/dimens.xml
similarity index 68%
rename from car/res/values-w840dp/dimens.xml
rename to car/res/values-w930dp/dimens.xml
index 8b4d992..6d7714e 100644
--- a/car/res/values-w840dp/dimens.xml
+++ b/car/res/values-w930dp/dimens.xml
@@ -14,8 +14,17 @@
limitations under the License.
-->
<resources>
+ <!-- Framework -->
+ <!-- Gutters -->
+ <dimen name="car_gutter_size">24dp</dimen>
+
+ <!-- Keylines -->
<dimen name="car_keyline_1">32dp</dimen>
<dimen name="car_keyline_2">108dp</dimen>
<dimen name="car_keyline_3">128dp</dimen>
- <dimen name="car_screen_gutter_size">24dp</dimen>
+ <dimen name="car_keyline_4">168dp</dimen>
+ <dimen name="car_keyline_1_neg">-32dp</dimen>
+ <dimen name="car_keyline_2_neg">-108dp</dimen>
+ <dimen name="car_keyline_3_neg">-128dp</dimen>
+ <dimen name="car_keyline_4_neg">-168dp</dimen>
</resources>
diff --git a/car/res/values-w1024dp/dimens.xml b/car/res/values-w930dp/integers.xml
similarity index 76%
copy from car/res/values-w1024dp/dimens.xml
copy to car/res/values-w930dp/integers.xml
index b1ae5ba..60ddfa1 100644
--- a/car/res/values-w1024dp/dimens.xml
+++ b/car/res/values-w930dp/integers.xml
@@ -14,5 +14,10 @@
limitations under the License.
-->
<resources>
- <dimen name="car_screen_margin_size">112dp</dimen>
+ <!-- Application Components -->
+ <!-- Cards -->
+ <integer name="column_card_default_column_span">10</integer>
+
+ <!-- Dialogs -->
+ <integer name="car_dialog_column_number">10</integer>
</resources>
diff --git a/car/res/values/attrs.xml b/car/res/values/attrs.xml
index 0ba8f55..01ed95f 100644
--- a/car/res/values/attrs.xml
+++ b/car/res/values/attrs.xml
@@ -28,8 +28,24 @@
<!-- Set to true/false to offset rows as they slide off screen. Defaults to true -->
<attr name="offsetRows" format="boolean" />
<!-- Whether or not to offset the list view by the width of scroll bar. Setting this to
- true will ensure that any views within the list will not overlap the scroll bar. -->
+ true will ensure that any views within the list will not overlap the scroll bar.
+ Deprecated: use gutter instead. If gutter is specified, this value is ignored.-->
<attr name="offsetScrollBar" format="boolean" />
+ <!-- Whether to include a gutter to the start, end or both sides of the list view items.
+ The gutter width will be the width of the scrollbar, and by default will be set to
+ both. -->
+ <attr name="gutter" format="enum">
+ <!-- No gutter on either side, the list view items will extend the full width of the
+ PagedListView. -->
+ <enum name="none" value="0" />
+ <!-- Include a gutter on the start side only (i.e. the side with the scrollbar). -->
+ <enum name="start" value="1" />
+ <!-- Include a gutter on the end side only (i.e. the opposite side to the
+ scrollbar). -->
+ <enum name="end" value="2" />
+ <!-- Include a gutter on both sides of the list view items. -->
+ <enum name="both" value="3" />
+ </attr>
<!-- Whether to display the scrollbar or not. Defaults to true. -->
<attr name="scrollBarEnabled" format="boolean" />
<!-- Whether or not to show a diving line between each item of the list. -->
@@ -43,7 +59,8 @@
<!-- A starting margin before the drawing of the dividing line. This margin will be an
offset from the view specified by "alignDividerStartTo" if given. -->
<attr name="dividerStartMargin" format="dimension" />
- <!-- The width of the margin on the right side of the list -->
+ <!-- The width of the margin on the right side of the list.
+ Deprecated: use gutter instead. If gutter is specified, this value is ignored.-->
<attr name="listEndMargin" format="dimension" />
<!-- An optional spacing between items in the list -->
<attr name="itemSpacing" format="dimension" />
diff --git a/car/res/values/colors.xml b/car/res/values/colors.xml
index 00c6cf9..5b90125 100644
--- a/car/res/values/colors.xml
+++ b/car/res/values/colors.xml
@@ -63,6 +63,10 @@
<color name="car_title_dark">@color/car_grey_900</color>
<color name="car_title">@color/car_title_dark</color>
+ <color name="car_title2_light">@color/car_grey_100</color>
+ <color name="car_title2_dark">@color/car_grey_900</color>
+ <color name="car_title2">@color/car_title2_dark</color>
+
<color name="car_headline1_light">@color/car_grey_100</color>
<color name="car_headline1_dark">@color/car_grey_800</color>
<color name="car_headline1">@color/car_headline1_dark</color>
diff --git a/car/res/values/dimens.xml b/car/res/values/dimens.xml
index c42437d..8e8621c 100644
--- a/car/res/values/dimens.xml
+++ b/car/res/values/dimens.xml
@@ -14,28 +14,22 @@
limitations under the License.
-->
<resources>
- <!-- Keylines for content. -->
- <dimen name="car_keyline_1">48dp</dimen>
- <dimen name="car_keyline_2">108dp</dimen>
- <dimen name="car_keyline_3">152dp</dimen>
- <dimen name="car_keyline_4">182dp</dimen>
- <dimen name="car_keyline_1_neg">-48dp</dimen>
- <dimen name="car_keyline_2_neg">-108dp</dimen>
- <dimen name="car_keyline_3_neg">-152dp</dimen>
+ <!-- Framework -->
+ <!-- Margin -->
+ <dimen name="car_margin">20dp</dimen>
- <!-- Type Sizings -->
- <dimen name="car_title_size">26sp</dimen>
- <dimen name="car_title2_size">32sp</dimen>
- <dimen name="car_headline1_size">45sp</dimen>
- <dimen name="car_headline2_size">36sp</dimen>
- <dimen name="car_headline3_size">24sp</dimen>
- <dimen name="car_headline4_size">20sp</dimen>
- <dimen name="car_body1_size">32sp</dimen>
- <dimen name="car_body2_size">26sp</dimen>
- <dimen name="car_body3_size">16sp</dimen>
- <dimen name="car_body4_size">14sp</dimen>
- <dimen name="car_body5_size">18sp</dimen>
- <dimen name="car_action1_size">26sp</dimen>
+ <!-- Gutters -->
+ <dimen name="car_gutter_size">16dp</dimen>
+
+ <!-- Keylines -->
+ <dimen name="car_keyline_1">24dp</dimen>
+ <dimen name="car_keyline_2">96dp</dimen>
+ <dimen name="car_keyline_3">112dp</dimen>
+ <dimen name="car_keyline_4">148dp</dimen>
+ <dimen name="car_keyline_1_neg">-24dp</dimen>
+ <dimen name="car_keyline_2_neg">-96dp</dimen>
+ <dimen name="car_keyline_3_neg">-112dp</dimen>
+ <dimen name="car_keyline_4_neg">-148dp</dimen>
<!-- Paddings -->
<dimen name="car_padding_1">4dp</dimen>
@@ -50,71 +44,106 @@
<dimen name="car_radius_3">16dp</dimen>
<dimen name="car_radius_5">100dp</dimen>
- <!-- Margin -->
- <dimen name="car_margin">112dp</dimen>
-
<!-- Car Component Dimensions -->
- <!-- Application Bar Height -->
- <dimen name="car_app_bar_height">80dp</dimen>
+ <!-- Type Sizings -->
+ <dimen name="car_title_size">32sp</dimen>
+ <dimen name="car_title2_size">32sp</dimen>
+ <dimen name="car_headline1_size">45sp</dimen>
+ <dimen name="car_headline2_size">36sp</dimen>
+ <dimen name="car_headline3_size">24sp</dimen>
+ <dimen name="car_headline4_size">20sp</dimen>
+ <dimen name="car_body1_size">32sp</dimen>
+ <dimen name="car_body2_size">26sp</dimen>
+ <dimen name="car_body3_size">16sp</dimen>
+ <dimen name="car_body4_size">14sp</dimen>
+ <dimen name="car_body5_size">18sp</dimen>
+ <dimen name="car_action1_size">26sp</dimen>
- <!-- The height of the bar that contains an applications action buttons. -->
- <dimen name="car_action_bar_height">128dp</dimen>
-
- <!-- Minimum touch target size. -->
- <dimen name="car_touch_target">76dp</dimen>
-
- <!-- Button Dimensions -->
- <dimen name="car_button_height">64dp</dimen>
- <dimen name="car_button_min_width">158dp</dimen>
- <dimen name="car_button_horizontal_padding">@dimen/car_padding_4</dimen>
- <dimen name="car_button_radius">@dimen/car_radius_1</dimen>
-
- <!-- Icon dimensions -->
+ <!-- Icons and Buttons -->
+ <!-- Icons -->
<dimen name="car_primary_icon_size">44dp</dimen>
<dimen name="car_secondary_icon_size">24dp</dimen>
- <!-- Line heights -->
+ <!-- Avatars -->
+ <dimen name="car_avatar_size">56dp</dimen>
+
+ <!-- Minimum touch target size. -->
+ <dimen name="car_touch_target_size">76dp</dimen>
+
+ <!-- Buttons -->
+ <dimen name="car_button_height">64dp</dimen>
+ <dimen name="car_button_min_width">158dp</dimen>
+ <dimen name="car_button_horizontal_padding">@dimen/car_padding_4</dimen>
+ <dimen name="car_borderless_button_horizontal_padding">0dp</dimen>
+ <dimen name="car_button_radius">@dimen/car_radius_1</dimen>
+
+ <!-- Application Bar -->
+ <dimen name="car_app_bar_height">80dp</dimen>
+
+ <!-- Action Bars -->
+ <dimen name="car_action_bar_height">128dp</dimen>
+ <dimen name="car_secondary_single_action_bar_height">@dimen/car_action_bar_height</dimen>
+ <dimen name="car_secondary_double_action_bar_height">256dp</dimen>
+
+ <!-- Lists -->
<dimen name="car_single_line_list_item_height">76dp</dimen>
<dimen name="car_double_line_list_item_height">96dp</dimen>
+ <dimen name="car_list_divider_height">1dp</dimen>
+ <!-- The height of a vertical line divider. -->
+ <dimen name="car_vertical_line_divider_height">60dp</dimen>
+ <dimen name="car_vertical_line_divider_width">1dp</dimen>
- <!-- List and Drawer Dimensions -->
- <!-- The margin on both sides of the screen before the contents of the PagedListView. -->
- <dimen name="car_card_margin">96dp</dimen>
+ <!-- Cards -->
+ <dimen name="car_card_header_height">76dp</dimen>
+ <dimen name="car_card_action_bar_height">76dp</dimen>
- <!-- The height of the dividers in the list. -->
- <dimen name="car_divider_height">1dp</dimen>
+ <!-- Dialogs -->
+ <dimen name="car_dialog_header_height">@dimen/car_card_header_height</dimen>
+ <dimen name="car_dialog_action_bar_height">@dimen/car_card_action_bar_height</dimen>
+ <!-- Slide Up Menu -->
+ <dimen name="car_slide_up_menu_initial_height">76dp</dimen>
+
+ <!-- Slide Down Menu -->
+ <dimen name="car_slide_down_menu_initial_height">@dimen/car_slide_up_menu_initial_height</dimen>
+
+ <!-- Sub Header -->
+ <dimen name="car_sub_header_height">76dp</dimen>
+
+ <!-- Slider -->
+ <dimen name="car_slider_height">6dp</dimen>
+ <dimen name="car_slider_knob_size">20dp</dimen>
+
+ <!-- Scroll Bar -->
+ <dimen name="car_scroll_bar_padding">@dimen/car_padding_2</dimen>
+
+ <!-- Scroll Bar Thumb -->
+ <dimen name="car_scroll_bar_thumb_width">@dimen/car_slider_height</dimen>
+ <dimen name="car_min_scroll_bar_thumb_height">48dp</dimen>
+ <dimen name="car_max_scroll_bar_thumb_height">128dp</dimen>
+ <dimen name="car_scroll_bar_thumb_margin">@dimen/car_padding_1</dimen>
+
+ <!-- Scroll Bar and Alpha Jump Buttons -->
+ <dimen name="car_scroll_bar_button_size">56dp</dimen>
+ <dimen name="car_alpha_jump_button_size">@dimen/car_scroll_bar_button_size</dimen>
+
+ <!-- Progress Bar -->
+ <dimen name="car_progress_bar_height">@dimen/car_slider_height</dimen>
+
+ <!-- Text Input -->
+ <dimen name="car_text_input_line_height">2dp</dimen>
+
+ <!-- PagedListView Dimensions -->
<!-- Sample row height used for scroll bar calculations in the off chance that a view hasn't
- been measured. It's highly unlikely that this value will actually be used for more than
- a frame max. The sample row is a 96dp card + 16dp margin on either side. -->
+ been measured. It's highly unlikely that this value will actually be used for more than
+ a frame max. The sample row is a 96dp card + 16dp margin on either side. -->
<dimen name="car_sample_row_height">128dp</dimen>
<!-- The amount of space the LayoutManager will make sure the last item on the screen is
peeking before scrolling down -->
<dimen name="car_last_card_peek_amount">16dp</dimen>
- <!-- The spacing between each column that fits on the screen. The number of columns is
- determined by integer/car_screen_num_of_columns. -->
- <dimen name="car_screen_gutter_size">16dp</dimen>
-
- <!-- The margin on both sizes of the scroll bar thumb. -->
- <dimen name="car_paged_list_view_scrollbar_thumb_margin">8dp</dimen>
-
- <!-- The size of the scroll bar up and down arrows. -->
- <dimen name="car_scroll_bar_button_size">44dp</dimen>
-
- <!-- The padding around the scroll bar. -->
- <dimen name="car_scroll_bar_padding">16dp</dimen>
-
- <!-- The width of the scroll bar thumb. -->
- <dimen name="car_scroll_bar_thumb_width">6dp</dimen>
-
- <!-- The minimum the scrollbar thumb can shrink to -->
- <dimen name="min_thumb_height">48dp</dimen>
-
- <!-- The maximum the scrollbar thumb can grow to -->
- <dimen name="max_thumb_height">128dp</dimen>
-
+ <!-- Drawer Dimensions -->
<!-- Size of progress-bar in Drawer -->
<dimen name="car_drawer_progress_bar_size">48dp</dimen>
diff --git a/car/res/values/integers.xml b/car/res/values/integers.xml
index 575d646..6352d7c 100644
--- a/car/res/values/integers.xml
+++ b/car/res/values/integers.xml
@@ -14,10 +14,28 @@
limitations under the License.
-->
<resources>
- <!-- The number of columns that appear on-screen. -->
- <integer name="car_screen_num_of_columns">4</integer>
+ <!-- Framework -->
+ <!-- Columns -->
+ <integer name="car_column_number">4</integer>
- <!-- The default number of columns that a ColumnCardView will span if columnSpan is not
- specified.-->
+ <!-- Application Components -->
+ <!-- Action Bar -->
+ <integer name="action_bar_column_number">@integer/car_column_number</integer>
+
+ <!-- Cards -->
<integer name="column_card_default_column_span">4</integer>
+
+ <!-- Dialogs -->
+ <integer name="car_dialog_column_number">10</integer>
+
+ <!-- Slide Up Menu -->
+ <integer name="car_slide_up_menu_column_number">4</integer>
+
+ <!-- The length limit of body text in a paged list item. String longer than this limit should be
+ truncated. -->
+ <integer name="car_list_item_text_length_limit">120</integer>
+
+ <!-- The length limit of text in a borderless button. String longer than this limit should be
+ truncated. -->
+ <integer name="car_borderless_button_text_length_limit">20</integer>
</resources>
diff --git a/car/res/values/strings.xml b/car/res/values/strings.xml
index 65f08b6..1fb4cf4 100644
--- a/car/res/values/strings.xml
+++ b/car/res/values/strings.xml
@@ -21,4 +21,5 @@
-->
<string name="car_drawer_open" translatable="false">Open drawer</string>
<string name="car_drawer_close" translatable="false">Close drawer</string>
+ <string name="ellipsis" translatable="false">…</string>
</resources>
diff --git a/car/res/values/styles.xml b/car/res/values/styles.xml
index 61e089b..606bdc5 100644
--- a/car/res/values/styles.xml
+++ b/car/res/values/styles.xml
@@ -15,25 +15,42 @@
-->
<resources>
<!-- The styling for title text. The color of this text changes based on day/night mode. -->
- <style name="CarTitle" >
+ <style name="CarTitle">
<item name="android:textStyle">normal</item>
<item name="android:textSize">@dimen/car_title_size</item>
<item name="android:textColor">@color/car_title</item>
</style>
<!-- Title text that is permanently a dark color. -->
- <style name="CarTitle.Dark" >
+ <style name="CarTitle.Dark">
<item name="android:textColor">@color/car_title_dark</item>
</style>
<!-- Title text that is permanently a light color. -->
- <style name="CarTitle.Light" >
+ <style name="CarTitle.Light">
<item name="android:textColor">@color/car_title_light</item>
</style>
+ <!-- The styling for title2 text. The color of this text changes based on day/night mode. -->
+ <style name="CarTitle2">
+ <item name="android:textStyle">normal</item>
+ <item name="android:textSize">@dimen/car_title2_size</item>
+ <item name="android:textColor">@color/car_title2</item>
+ </style>
+
+ <!-- Title2 text that is permanently a dark color. -->
+ <style name="CarTitle2.Dark">
+ <item name="android:textColor">@color/car_title2_dark</item>
+ </style>
+
+ <!-- Title2 text that is permanently a light color. -->
+ <style name="CarTitle2.Light">
+ <item name="android:textColor">@color/car_title2_light</item>
+ </style>
+
<!-- The styling for the main headline text. The color of this text changes based on the
day/night mode. -->
- <style name="CarHeadline1" >
+ <style name="CarHeadline1">
<item name="android:textStyle">normal</item>
<item name="android:textSize">@dimen/car_headline1_size</item>
<item name="android:textColor">@color/car_headline1</item>
@@ -41,7 +58,7 @@
<!-- The styling for a sub-headline text. The color of this text changes based on the
day/night mode. -->
- <style name="CarHeadline2" >
+ <style name="CarHeadline2">
<item name="android:textStyle">normal</item>
<item name="android:textSize">@dimen/car_headline2_size</item>
<item name="android:textColor">@color/car_headline2</item>
@@ -49,7 +66,7 @@
<!-- The styling for a smaller alternate headline text. The color of this text changes based on
the day/night mode. -->
- <style name="CarHeadline3" >
+ <style name="CarHeadline3">
<item name="android:textStyle">normal</item>
<item name="android:textSize">@dimen/car_headline3_size</item>
<item name="android:textColor">@color/car_headline3</item>
@@ -57,14 +74,14 @@
<!-- The styling for the smallest headline text. The color of this text changes based on the
day/night mode. -->
- <style name="CarHeadline4" >
+ <style name="CarHeadline4">
<item name="android:textStyle">normal</item>
<item name="android:textSize">@dimen/car_headline4_size</item>
<item name="android:textColor">@color/car_headline4</item>
</style>
<!-- The styling for body text. The color of this text changes based on the day/night mode. -->
- <style name="CarBody1" >
+ <style name="CarBody1">
<item name="android:textStyle">normal</item>
<item name="android:textSize">@dimen/car_body1_size</item>
<item name="android:textColor">@color/car_body1</item>
@@ -72,7 +89,7 @@
<!-- An alternate styling for body text that is both a different color and size than
CarBody1. -->
- <style name="CarBody2" >
+ <style name="CarBody2">
<item name="android:textStyle">normal</item>
<item name="android:textSize">@dimen/car_body2_size</item>
<item name="android:textColor">@color/car_body2</item>
@@ -80,7 +97,7 @@
<!-- A smaller styling for body text. The color of this text changes based on the day/night
mode. -->
- <style name="CarBody3" >
+ <style name="CarBody3">
<item name="android:textStyle">normal</item>
<item name="android:textSize">@dimen/car_body3_size</item>
<item name="android:textColor">@color/car_body3</item>
@@ -88,7 +105,7 @@
<!-- The smallest styling for body text. The color of this text changes based on the day/night
mode. -->
- <style name="CarBody4" >
+ <style name="CarBody4">
<item name="android:textStyle">normal</item>
<item name="android:textSize">@dimen/car_body4_size</item>
<item name="android:textColor">@color/car_body4</item>
@@ -119,14 +136,17 @@
<item name="android:background">@drawable/car_button_background</item>
</style>
- <style name="CarBorderlessButton" parent="android:Widget.Material.Button.Borderless">
+ <style name="CarButton.Borderless" parent="android:Widget.Material.Button.Borderless">
<item name="android:layout_height">@dimen/car_button_height</item>
- <item name="android:minWidth">@dimen/car_button_min_width</item>
- <item name="android:paddingStart">@dimen/car_button_horizontal_padding</item>
- <item name="android:paddingEnd">@dimen/car_button_horizontal_padding</item>
+ <item name="android:paddingStart">@dimen/car_borderless_button_horizontal_padding</item>
+ <item name="android:paddingEnd">@dimen/car_borderless_button_horizontal_padding</item>
<item name="android:textStyle">normal</item>
<item name="android:textSize">@dimen/car_action1_size</item>
- <item name="android:textColor">@drawable/car_button_text_color</item>
+ <item name="android:textColor">@drawable/car_borderless_button_text_color</item>
<item name="android:textAllCaps">true</item>
</style>
+
+ <!-- Style for the progress bars -->
+ <style name="CarProgressBar.Horizontal"
+ parent="android:Widget.Material.ProgressBar.Horizontal"/>
</resources>
diff --git a/car/src/main/java/android/support/car/drawer/CarDrawerActivity.java b/car/src/main/java/androidx/car/drawer/CarDrawerActivity.java
similarity index 98%
rename from car/src/main/java/android/support/car/drawer/CarDrawerActivity.java
rename to car/src/main/java/androidx/car/drawer/CarDrawerActivity.java
index f46c652..55bb23c 100644
--- a/car/src/main/java/android/support/car/drawer/CarDrawerActivity.java
+++ b/car/src/main/java/androidx/car/drawer/CarDrawerActivity.java
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-package android.support.car.drawer;
+package androidx.car.drawer;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
-import android.support.car.R;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
@@ -30,6 +29,8 @@
import android.view.View;
import android.view.ViewGroup;
+import androidx.car.R;
+
/**
* Common base Activity for car apps that need to present a Drawer.
*
diff --git a/car/src/main/java/android/support/car/drawer/CarDrawerAdapter.java b/car/src/main/java/androidx/car/drawer/CarDrawerAdapter.java
similarity index 98%
rename from car/src/main/java/android/support/car/drawer/CarDrawerAdapter.java
rename to car/src/main/java/androidx/car/drawer/CarDrawerAdapter.java
index b0fd965..ca16413 100644
--- a/car/src/main/java/android/support/car/drawer/CarDrawerAdapter.java
+++ b/car/src/main/java/androidx/car/drawer/CarDrawerAdapter.java
@@ -14,20 +14,21 @@
* limitations under the License.
*/
-package android.support.car.drawer;
+package androidx.car.drawer;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.car.R;
-import android.support.car.widget.PagedListView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import androidx.car.R;
+import androidx.car.widget.PagedListView;
+
/**
* Base adapter for displaying items in the car navigation drawer, which uses a
* {@link PagedListView}.
diff --git a/car/src/main/java/android/support/car/drawer/CarDrawerController.java b/car/src/main/java/androidx/car/drawer/CarDrawerController.java
similarity index 97%
rename from car/src/main/java/android/support/car/drawer/CarDrawerController.java
rename to car/src/main/java/androidx/car/drawer/CarDrawerController.java
index 7b23714..e26054f 100644
--- a/car/src/main/java/android/support/car/drawer/CarDrawerController.java
+++ b/car/src/main/java/androidx/car/drawer/CarDrawerController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.car.drawer;
+package androidx.car.drawer;
import android.content.Context;
import android.content.res.Configuration;
@@ -22,8 +22,6 @@
import android.support.annotation.AnimRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.car.R;
-import android.support.car.widget.PagedListView;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.RecyclerView;
@@ -34,7 +32,10 @@
import android.view.animation.AnimationUtils;
import android.widget.ProgressBar;
-import java.util.Stack;
+import java.util.ArrayDeque;
+
+import androidx.car.R;
+import androidx.car.widget.PagedListView;
/**
* A controller that will handle the set up of the navigation drawer. It will hook up the
@@ -58,7 +59,7 @@
* this stack is the order that the user has visited each level. When the user navigates up,
* the adapters are popped from this list.
*/
- private final Stack<CarDrawerAdapter> mAdapterStack = new Stack<>();
+ private final ArrayDeque<CarDrawerAdapter> mAdapterStack = new ArrayDeque<>();
private final Context mContext;
@@ -114,11 +115,10 @@
}
// The root adapter is always the last item in the stack.
- if (mAdapterStack.size() > 0) {
- mAdapterStack.set(0, rootAdapter);
- } else {
- mAdapterStack.push(rootAdapter);
+ if (!mAdapterStack.isEmpty()) {
+ mAdapterStack.removeLast();
}
+ mAdapterStack.addLast(rootAdapter);
setToolbarTitleFrom(rootAdapter);
mDrawerList.setAdapter(rootAdapter);
diff --git a/car/src/main/java/android/support/car/drawer/DrawerItemClickListener.java b/car/src/main/java/androidx/car/drawer/DrawerItemClickListener.java
similarity index 95%
rename from car/src/main/java/android/support/car/drawer/DrawerItemClickListener.java
rename to car/src/main/java/androidx/car/drawer/DrawerItemClickListener.java
index d707dbd..4c0c7a2 100644
--- a/car/src/main/java/android/support/car/drawer/DrawerItemClickListener.java
+++ b/car/src/main/java/androidx/car/drawer/DrawerItemClickListener.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.car.drawer;
+package androidx.car.drawer;
/**
* Listener for handling clicks on items/views managed by {@link DrawerItemViewHolder}.
diff --git a/car/src/main/java/android/support/car/drawer/DrawerItemViewHolder.java b/car/src/main/java/androidx/car/drawer/DrawerItemViewHolder.java
similarity index 95%
rename from car/src/main/java/android/support/car/drawer/DrawerItemViewHolder.java
rename to car/src/main/java/androidx/car/drawer/DrawerItemViewHolder.java
index d016b2d..8bbded9 100644
--- a/car/src/main/java/android/support/car/drawer/DrawerItemViewHolder.java
+++ b/car/src/main/java/androidx/car/drawer/DrawerItemViewHolder.java
@@ -14,19 +14,20 @@
* limitations under the License.
*/
-package android.support.car.drawer;
+package androidx.car.drawer;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.car.R;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.car.R;
+
/**
* Re-usable {@link RecyclerView.ViewHolder} for displaying items in the
- * {@link android.support.car.drawer.CarDrawerAdapter}.
+ * {@link androidx.car.drawer.CarDrawerAdapter}.
*/
public class DrawerItemViewHolder extends RecyclerView.ViewHolder {
private final ImageView mIcon;
diff --git a/car/src/main/java/android/support/car/utils/ColumnCalculator.java b/car/src/main/java/androidx/car/utils/ColumnCalculator.java
similarity index 95%
rename from car/src/main/java/android/support/car/utils/ColumnCalculator.java
rename to car/src/main/java/androidx/car/utils/ColumnCalculator.java
index fa5dd43..35b1a91 100644
--- a/car/src/main/java/android/support/car/utils/ColumnCalculator.java
+++ b/car/src/main/java/androidx/car/utils/ColumnCalculator.java
@@ -14,15 +14,16 @@
* limitations under the License.
*/
-package android.support.car.utils;
+package androidx.car.utils;
import android.content.Context;
import android.content.res.Resources;
-import android.support.car.R;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;
+import androidx.car.R;
+
/**
* Utility class that calculates the size of the columns that will fit on the screen. A column's
* width is determined by the size of the margins and gutters (space between the columns) that fit
@@ -66,8 +67,8 @@
private ColumnCalculator(Context context) {
Resources res = context.getResources();
int marginSize = res.getDimensionPixelSize(R.dimen.car_margin);
- mGutterSize = res.getDimensionPixelSize(R.dimen.car_screen_gutter_size);
- mNumOfColumns = res.getInteger(R.integer.car_screen_num_of_columns);
+ mGutterSize = res.getDimensionPixelSize(R.dimen.car_gutter_size);
+ mNumOfColumns = res.getInteger(R.integer.car_column_number);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, String.format("marginSize: %d; numOfColumns: %d; gutterSize: %d",
diff --git a/car/src/main/java/android/support/car/widget/CarItemAnimator.java b/car/src/main/java/androidx/car/widget/CarItemAnimator.java
similarity index 98%
rename from car/src/main/java/android/support/car/widget/CarItemAnimator.java
rename to car/src/main/java/androidx/car/widget/CarItemAnimator.java
index ef22c48..e6bfd05 100644
--- a/car/src/main/java/android/support/car/widget/CarItemAnimator.java
+++ b/car/src/main/java/androidx/car/widget/CarItemAnimator.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.car.widget;
+package androidx.car.widget;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.RecyclerView;
diff --git a/car/src/main/java/android/support/car/widget/CarRecyclerView.java b/car/src/main/java/androidx/car/widget/CarRecyclerView.java
similarity index 98%
rename from car/src/main/java/android/support/car/widget/CarRecyclerView.java
rename to car/src/main/java/androidx/car/widget/CarRecyclerView.java
index bb9cb71..1d89ed1 100644
--- a/car/src/main/java/android/support/car/widget/CarRecyclerView.java
+++ b/car/src/main/java/androidx/car/widget/CarRecyclerView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.car.widget;
+package androidx.car.widget;
import android.content.Context;
import android.graphics.Canvas;
diff --git a/car/src/main/java/android/support/car/widget/ColumnCardView.java b/car/src/main/java/androidx/car/widget/ColumnCardView.java
similarity index 95%
rename from car/src/main/java/android/support/car/widget/ColumnCardView.java
rename to car/src/main/java/androidx/car/widget/ColumnCardView.java
index 06f8553..9ec2bb6 100644
--- a/car/src/main/java/android/support/car/widget/ColumnCardView.java
+++ b/car/src/main/java/androidx/car/widget/ColumnCardView.java
@@ -14,16 +14,17 @@
* limitations under the License.
*/
-package android.support.car.widget;
+package androidx.car.widget;
import android.content.Context;
import android.content.res.TypedArray;
-import android.support.car.R;
-import android.support.car.utils.ColumnCalculator;
import android.support.v7.widget.CardView;
import android.util.AttributeSet;
import android.util.Log;
+import androidx.car.R;
+import androidx.car.utils.ColumnCalculator;
+
/**
* A {@link CardView} whose width can be specified by the number of columns that it will span.
*
@@ -34,7 +35,7 @@
* a default span value that it uses.
*
* <pre>
- * <android.support.car.widget.ColumnCardView
+ * <androidx.car.widget.ColumnCardView
* android:layout_width="wrap_content"
* android:layout_height="wrap_content"
* app:columnSpan="4" />
diff --git a/car/src/main/java/android/support/car/widget/DayNightStyle.java b/car/src/main/java/androidx/car/widget/DayNightStyle.java
similarity index 98%
rename from car/src/main/java/android/support/car/widget/DayNightStyle.java
rename to car/src/main/java/androidx/car/widget/DayNightStyle.java
index ff5a1b3..6e3ecbe 100644
--- a/car/src/main/java/android/support/car/widget/DayNightStyle.java
+++ b/car/src/main/java/androidx/car/widget/DayNightStyle.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.car.widget;
+package androidx.car.widget;
import android.support.annotation.IntDef;
diff --git a/car/src/main/java/androidx/car/widget/ListItem.java b/car/src/main/java/androidx/car/widget/ListItem.java
new file mode 100644
index 0000000..ad1e3b8
--- /dev/null
+++ b/car/src/main/java/androidx/car/widget/ListItem.java
@@ -0,0 +1,720 @@
+/*
+ * 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 androidx.car.widget;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.IntDef;
+import android.support.v7.widget.RecyclerView;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import java.lang.annotation.Retention;
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.car.R;
+
+/**
+ * Class to build a list item.
+ *
+ * <p>An item supports primary action and supplemental action(s).
+ *
+ * <p>An item visually composes of 3 parts; each part may contain multiple views.
+ * <ul>
+ * <li>{@code Primary Action}: represented by an icon of following types.
+ * <ul>
+ * <li>Primary Icon - icon size could be large or small.
+ * <li>No Icon
+ * <li>Empty Icon - different from No Icon by how much margin {@code Text} offsets
+ * </ul>
+ * <li>{@code Text}: supports any combination of the follow text views.
+ * <ul>
+ * <li>Title
+ * <li>Body
+ * </ul>
+ * <li>{@code Supplemental Action(s)}: represented by one of the following types; aligned toward
+ * the end of item.
+ * <ul>
+ * <li>Supplemental Icon
+ * <li>One Action Button
+ * <li>Two Action Buttons
+ * </ul>
+ * </ul>
+ *
+ * {@link ListItem} can be built through its {@link ListItem.Builder}. It binds data
+ * to {@link ListItemAdapter.ViewHolder} based on components selected.
+ */
+public class ListItem {
+
+ private Builder mBuilder;
+
+ private ListItem(Builder builder) {
+ mBuilder = builder;
+ }
+
+ /**
+ * Applies all {@link ViewBinder} to {@code viewHolder}.
+ */
+ void bind(ListItemAdapter.ViewHolder viewHolder) {
+ setAllSubViewsGone(viewHolder);
+ for (ViewBinder binder : mBuilder.mBinders) {
+ binder.bind(viewHolder);
+ }
+ }
+
+ void setAllSubViewsGone(ListItemAdapter.ViewHolder vh) {
+ View[] subviews = new View[] {
+ vh.getPrimaryIcon(),
+ vh.getTitle(), vh.getBody(),
+ vh.getSupplementalIcon(), vh.getSupplementalIconDivider(),
+ vh.getAction1(), vh.getAction1Divider(), vh.getAction2(), vh.getAction2Divider()};
+ for (View v : subviews) {
+ v.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Used by {@link ListItemAdapter} to choose layout to inflate for view holder.
+ * New view type needs support in {@link ListItemAdapter}.
+ */
+ protected int getViewType() {
+ return mBuilder.mIsCard
+ ? ListItemAdapter.CAR_PAGED_LIST_CARD
+ : ListItemAdapter.CAR_PAGED_LIST_ITEM;
+ }
+
+ /**
+ * Functional interface to provide a way to interact with views in
+ * {@link ListItemAdapter.ViewHolder}. {@code ViewBinder}s added to a
+ * {@code ListItem} will be called when {@code ListItem} {@code bind}s to
+ * {@link ListItemAdapter.ViewHolder}.
+ */
+ public interface ViewBinder {
+ /**
+ * Provides a way to interact with views in view holder.
+ */
+ void bind(ListItemAdapter.ViewHolder viewHolder);
+ }
+
+ /**
+ * Builds a {@link ListItem}.
+ *
+ * <p>With conflicting methods are called, e.g. setting primary action to both primary icon and
+ * no icon, the last called method wins.
+ */
+ public static class Builder {
+
+ @Retention(SOURCE)
+ @IntDef({
+ PRIMARY_ACTION_TYPE_NO_ICON, PRIMARY_ACTION_TYPE_EMPTY_ICON,
+ PRIMARY_ACTION_TYPE_LARGE_ICON, PRIMARY_ACTION_TYPE_SMALL_ICON})
+ private @interface PrimaryActionType {}
+
+ private static final int PRIMARY_ACTION_TYPE_NO_ICON = 0;
+ private static final int PRIMARY_ACTION_TYPE_EMPTY_ICON = 1;
+ private static final int PRIMARY_ACTION_TYPE_LARGE_ICON = 2;
+ private static final int PRIMARY_ACTION_TYPE_SMALL_ICON = 3;
+
+ @Retention(SOURCE)
+ @IntDef({SUPPLEMENTAL_ACTION_NO_ACTION, SUPPLEMENTAL_ACTION_SUPPLEMENTAL_ICON,
+ SUPPLEMENTAL_ACTION_ONE_ACTION, SUPPLEMENTAL_ACTION_TWO_ACTIONS})
+ private @interface SupplementalActionType {}
+
+ private static final int SUPPLEMENTAL_ACTION_NO_ACTION = 0;
+ private static final int SUPPLEMENTAL_ACTION_SUPPLEMENTAL_ICON = 1;
+ private static final int SUPPLEMENTAL_ACTION_ONE_ACTION = 2;
+ private static final int SUPPLEMENTAL_ACTION_TWO_ACTIONS = 3;
+
+ private final Context mContext;
+ private final List<ViewBinder> mBinders = new ArrayList<>();
+ // Store custom binders separately so they will bind after binders are created in build().
+ private final List<ViewBinder> mCustomBinders = new ArrayList<>();
+
+ private boolean mIsCard;
+
+ private View.OnClickListener mOnClickListener;
+
+ @PrimaryActionType private int mPrimaryActionType = PRIMARY_ACTION_TYPE_NO_ICON;
+ private int mPrimaryActionIconResId;
+ private Drawable mPrimaryActionIconDrawable;
+
+ private String mTitle;
+ private String mBody;
+ private boolean mIsBodyPrimary;
+
+ @SupplementalActionType private int mSupplementalActionType = SUPPLEMENTAL_ACTION_NO_ACTION;
+ private int mSupplementalIconResId;
+ private View.OnClickListener mSupplementalIconOnClickListener;
+ private boolean mShowSupplementalIconDivider;
+
+ private String mAction1Text;
+ private View.OnClickListener mAction1OnClickListener;
+ private boolean mShowAction1Divider;
+ private String mAction2Text;
+ private View.OnClickListener mAction2OnClickListener;
+ private boolean mShowAction2Divider;
+
+ public Builder(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Builds a {@link ListItem}. Adds {@link ViewBinder}s that will adjust layout in
+ * {@link ListItemAdapter.ViewHolder} depending on sub-views used.
+ */
+ public ListItem build() {
+ setItemLayoutHeight();
+ setPrimaryAction();
+ setText();
+ setSupplementalActions();
+ setOnClickListener();
+
+ mBinders.addAll(mCustomBinders);
+
+ return new ListItem(this);
+ }
+
+ /**
+ * Sets the height of item depending on which text field is set.
+ */
+ private void setItemLayoutHeight() {
+ if (TextUtils.isEmpty(mBody)) {
+ // If the item only has title or no text, it uses fixed-height as single line.
+ int height = (int) mContext.getResources().getDimension(
+ R.dimen.car_single_line_list_item_height);
+ mBinders.add((vh) -> {
+ RecyclerView.LayoutParams layoutParams =
+ (RecyclerView.LayoutParams) vh.itemView.getLayoutParams();
+ layoutParams.height = height;
+ vh.itemView.setLayoutParams(layoutParams);
+ });
+ } else {
+ // If body is present, the item should be at least as tall as min height, and wraps
+ // content.
+ int minHeight = (int) mContext.getResources().getDimension(
+ R.dimen.car_double_line_list_item_height);
+ mBinders.add((vh) -> {
+ vh.itemView.setMinimumHeight(minHeight);
+ vh.getContainerLayout().setMinimumHeight(minHeight);
+
+ RecyclerView.LayoutParams layoutParams =
+ (RecyclerView.LayoutParams) vh.itemView.getLayoutParams();
+ layoutParams.height = RecyclerView.LayoutParams.WRAP_CONTENT;
+ vh.itemView.setLayoutParams(layoutParams);
+ });
+ }
+ }
+
+ private void setPrimaryAction() {
+ setPrimaryIconContent();
+ setPrimaryIconLayout();
+ }
+
+ private void setText() {
+ setTextContent();
+ setTextVerticalMargin();
+ // Only setting start margin because text end is relative to the start of supplemental
+ // actions.
+ setTextStartMargin();
+ }
+
+ private void setOnClickListener() {
+ if (mOnClickListener != null) {
+ mBinders.add(vh -> vh.itemView.setOnClickListener(mOnClickListener));
+ }
+ }
+
+ private void setPrimaryIconContent() {
+ switch (mPrimaryActionType) {
+ case PRIMARY_ACTION_TYPE_SMALL_ICON:
+ case PRIMARY_ACTION_TYPE_LARGE_ICON:
+ mBinders.add((vh) -> {
+ vh.getPrimaryIcon().setVisibility(View.VISIBLE);
+
+ if (mPrimaryActionIconDrawable != null) {
+ vh.getPrimaryIcon().setImageDrawable(mPrimaryActionIconDrawable);
+ } else if (mPrimaryActionIconResId != 0) {
+ vh.getPrimaryIcon().setImageResource(mPrimaryActionIconResId);
+ }
+ });
+ break;
+ case PRIMARY_ACTION_TYPE_EMPTY_ICON:
+ case PRIMARY_ACTION_TYPE_NO_ICON:
+ // Do nothing.
+ break;
+ default:
+ throw new IllegalStateException("Unrecognizable primary action type.");
+ }
+ }
+
+ /**
+ * Sets layout params of primary icon.
+ *
+ * <p>Large icon will have no start margin, and always align center vertically.
+ *
+ * <p>Small icon will have start margin. When body text is present small icon uses a top
+ * margin otherwise align center vertically.
+ */
+ private void setPrimaryIconLayout() {
+ // Set all relevant fields in layout params to avoid carried over params when the item
+ // gets bound to a recycled view holder.
+ switch (mPrimaryActionType) {
+ case PRIMARY_ACTION_TYPE_SMALL_ICON:
+ mBinders.add(vh -> {
+ int iconSize = mContext.getResources().getDimensionPixelSize(
+ R.dimen.car_primary_icon_size);
+ // Icon size.
+ RelativeLayout.LayoutParams layoutParams =
+ (RelativeLayout.LayoutParams) vh.getPrimaryIcon().getLayoutParams();
+ layoutParams.height = iconSize;
+ layoutParams.width = iconSize;
+
+ // Start margin.
+ layoutParams.setMarginStart(mContext.getResources().getDimensionPixelSize(
+ R.dimen.car_keyline_1));
+
+ if (!TextUtils.isEmpty(mBody)) {
+ // Set top margin.
+ layoutParams.removeRule(RelativeLayout.CENTER_VERTICAL);
+ layoutParams.topMargin = mContext.getResources().getDimensionPixelSize(
+ R.dimen.car_padding_4);
+ } else {
+ // Centered vertically.
+ layoutParams.addRule(RelativeLayout.CENTER_VERTICAL);
+ layoutParams.topMargin = 0;
+ }
+ vh.getPrimaryIcon().setLayoutParams(layoutParams);
+ });
+ break;
+ case PRIMARY_ACTION_TYPE_LARGE_ICON:
+ mBinders.add(vh -> {
+ int iconSize = mContext.getResources().getDimensionPixelSize(
+ R.dimen.car_single_line_list_item_height);
+ // Icon size.
+ RelativeLayout.LayoutParams layoutParams =
+ (RelativeLayout.LayoutParams) vh.getPrimaryIcon().getLayoutParams();
+ layoutParams.height = iconSize;
+ layoutParams.width = iconSize;
+
+ // No start margin.
+ layoutParams.setMarginStart(0);
+
+ // Always centered vertically.
+ layoutParams.addRule(RelativeLayout.CENTER_VERTICAL);
+ layoutParams.topMargin = 0;
+
+ vh.getPrimaryIcon().setLayoutParams(layoutParams);
+ });
+ break;
+ case PRIMARY_ACTION_TYPE_EMPTY_ICON:
+ case PRIMARY_ACTION_TYPE_NO_ICON:
+ // Do nothing.
+ break;
+ default:
+ throw new IllegalStateException("Unrecognizable primary action type.");
+ }
+ }
+
+ private void setTextContent() {
+ if (!TextUtils.isEmpty(mTitle)) {
+ mBinders.add(vh -> {
+ vh.getTitle().setVisibility(View.VISIBLE);
+ vh.getTitle().setText(mTitle);
+ });
+ }
+ if (!TextUtils.isEmpty(mBody)) {
+ mBinders.add(vh -> {
+ vh.getBody().setVisibility(View.VISIBLE);
+ vh.getBody().setText(mBody);
+ });
+ }
+
+ if (mIsBodyPrimary) {
+ mBinders.add((vh) -> {
+ vh.getTitle().setTextAppearance(R.style.CarBody2);
+ vh.getBody().setTextAppearance(R.style.CarBody1);
+ });
+ } else {
+ mBinders.add((vh) -> {
+ vh.getTitle().setTextAppearance(R.style.CarBody1);
+ vh.getBody().setTextAppearance(R.style.CarBody2);
+ });
+ }
+ }
+
+ /**
+ * Sets start margin of text view depending on icon type.
+ */
+ private void setTextStartMargin() {
+ final int startMarginResId;
+ switch (mPrimaryActionType) {
+ case PRIMARY_ACTION_TYPE_NO_ICON:
+ startMarginResId = R.dimen.car_keyline_1;
+ break;
+ case PRIMARY_ACTION_TYPE_EMPTY_ICON:
+ startMarginResId = R.dimen.car_keyline_3;
+ break;
+ case PRIMARY_ACTION_TYPE_SMALL_ICON:
+ startMarginResId = R.dimen.car_keyline_3;
+ break;
+ case PRIMARY_ACTION_TYPE_LARGE_ICON:
+ startMarginResId = R.dimen.car_keyline_4;
+ break;
+ default:
+ throw new IllegalStateException("Unrecognizable primary action type.");
+ }
+ int startMargin = mContext.getResources().getDimensionPixelSize(startMarginResId);
+ mBinders.add(vh -> {
+ RelativeLayout.LayoutParams titleLayoutParams =
+ (RelativeLayout.LayoutParams) vh.getTitle().getLayoutParams();
+ titleLayoutParams.setMarginStart(startMargin);
+ vh.getTitle().setLayoutParams(titleLayoutParams);
+
+ RelativeLayout.LayoutParams bodyLayoutParams =
+ (RelativeLayout.LayoutParams) vh.getBody().getLayoutParams();
+ bodyLayoutParams.setMarginStart(startMargin);
+ vh.getBody().setLayoutParams(bodyLayoutParams);
+ });
+ }
+
+ /**
+ * Sets top/bottom margins of {@code Title} and {@code Body}.
+ */
+ private void setTextVerticalMargin() {
+ // Set all relevant fields in layout params to avoid carried over params when the item
+ // gets bound to a recycled view holder.
+ if (!TextUtils.isEmpty(mTitle) && TextUtils.isEmpty(mBody)) {
+ // Title only - view is aligned center vertically by itself.
+ mBinders.add(vh -> {
+ RelativeLayout.LayoutParams layoutParams =
+ (RelativeLayout.LayoutParams) vh.getTitle().getLayoutParams();
+ layoutParams.addRule(RelativeLayout.CENTER_VERTICAL);
+ layoutParams.topMargin = 0;
+ vh.getTitle().setLayoutParams(layoutParams);
+ });
+ } else if (TextUtils.isEmpty(mTitle) && !TextUtils.isEmpty(mBody)) {
+ mBinders.add(vh -> {
+ // Body uses top and bottom margin.
+ int margin = mContext.getResources().getDimensionPixelSize(
+ R.dimen.car_padding_3);
+ RelativeLayout.LayoutParams layoutParams =
+ (RelativeLayout.LayoutParams) vh.getBody().getLayoutParams();
+ layoutParams.addRule(RelativeLayout.CENTER_VERTICAL);
+ layoutParams.removeRule(RelativeLayout.BELOW);
+ layoutParams.topMargin = margin;
+ layoutParams.bottomMargin = margin;
+ vh.getBody().setLayoutParams(layoutParams);
+ });
+ } else {
+ mBinders.add(vh -> {
+ // Title has a top margin
+ Resources resources = mContext.getResources();
+ int padding1 = resources.getDimensionPixelSize(R.dimen.car_padding_1);
+ int padding3 = resources.getDimensionPixelSize(R.dimen.car_padding_3);
+
+ RelativeLayout.LayoutParams titleLayoutParams =
+ (RelativeLayout.LayoutParams) vh.getTitle().getLayoutParams();
+ titleLayoutParams.removeRule(RelativeLayout.CENTER_VERTICAL);
+ titleLayoutParams.topMargin = padding3;
+ vh.getTitle().setLayoutParams(titleLayoutParams);
+ // Body is below title with a margin, and has bottom margin.
+ RelativeLayout.LayoutParams bodyLayoutParams =
+ (RelativeLayout.LayoutParams) vh.getBody().getLayoutParams();
+ bodyLayoutParams.removeRule(RelativeLayout.CENTER_VERTICAL);
+ bodyLayoutParams.addRule(RelativeLayout.BELOW, R.id.title);
+ bodyLayoutParams.topMargin = padding1;
+ bodyLayoutParams.bottomMargin = padding3;
+ vh.getBody().setLayoutParams(bodyLayoutParams);
+ });
+ }
+ }
+
+ /**
+ * Sets up view(s) for supplemental action.
+ */
+ private void setSupplementalActions() {
+ switch (mSupplementalActionType) {
+ case SUPPLEMENTAL_ACTION_SUPPLEMENTAL_ICON:
+ mBinders.add((vh) -> {
+ vh.getSupplementalIcon().setVisibility(View.VISIBLE);
+ if (mShowSupplementalIconDivider) {
+ vh.getSupplementalIconDivider().setVisibility(View.VISIBLE);
+ }
+
+ vh.getSupplementalIcon().setImageResource(mSupplementalIconResId);
+ vh.getSupplementalIcon().setOnClickListener(
+ mSupplementalIconOnClickListener);
+ });
+ break;
+ case SUPPLEMENTAL_ACTION_TWO_ACTIONS:
+ mBinders.add((vh) -> {
+ vh.getAction2().setVisibility(View.VISIBLE);
+ if (mShowAction2Divider) {
+ vh.getAction2Divider().setVisibility(View.VISIBLE);
+ }
+
+ vh.getAction2().setText(mAction2Text);
+ vh.getAction2().setOnClickListener(mAction2OnClickListener);
+ });
+ // Fall through
+ case SUPPLEMENTAL_ACTION_ONE_ACTION:
+ mBinders.add((vh) -> {
+ vh.getAction1().setVisibility(View.VISIBLE);
+ if (mShowAction1Divider) {
+ vh.getAction1Divider().setVisibility(View.VISIBLE);
+ }
+
+ vh.getAction1().setText(mAction1Text);
+ vh.getAction1().setOnClickListener(mAction1OnClickListener);
+ });
+ break;
+ case SUPPLEMENTAL_ACTION_NO_ACTION:
+ // Do nothing
+ break;
+ default:
+ throw new IllegalArgumentException("Unrecognized supplemental action type.");
+ }
+ }
+
+ /**
+ * Builds the item in a {@link android.support.v7.widget.CardView}.
+ *
+ * <p>Each item will have rounded corner, margin between items, and elevation.
+ *
+ * @return This Builder object to allow for chaining calls to set methods.
+ */
+ public Builder withCardLook() {
+ mIsCard = true;
+ return this;
+ }
+
+ /**
+ * Sets {@link View.OnClickListener} of {@code ListItem}.
+ *
+ * @return This Builder object to allow for chaining calls to set methods.
+ */
+ public Builder withOnClickListener(View.OnClickListener listener) {
+ mOnClickListener = listener;
+ return this;
+ }
+
+ /**
+ * Sets {@code Primary Action} to be represented by an icon.
+ *
+ * @param iconResId the resource identifier of the drawable.
+ * @param useLargeIcon the size of primary icon. Large Icon is a square as tall as an item
+ * with only title set; useful for album cover art.
+ * @return This Builder object to allow for chaining calls to set methods.
+ */
+ public Builder withPrimaryActionIcon(@DrawableRes int iconResId, boolean useLargeIcon) {
+ return withPrimaryActionIcon(null, iconResId, useLargeIcon);
+ }
+
+ /**
+ * Sets {@code Primary Action} to be represented by an icon.
+ *
+ * @param drawable the Drawable to set, or null to clear the content.
+ * @param useLargeIcon the size of primary icon. Large Icon is a square as tall as an item
+ * with only title set; useful for album cover art.
+ * @return This Builder object to allow for chaining calls to set methods.
+ */
+ public Builder withPrimaryActionIcon(Drawable drawable, boolean useLargeIcon) {
+ return withPrimaryActionIcon(drawable, 0, useLargeIcon);
+ }
+
+ private Builder withPrimaryActionIcon(Drawable drawable, @DrawableRes int iconResId,
+ boolean useLargeIcon) {
+ mPrimaryActionType = useLargeIcon
+ ? PRIMARY_ACTION_TYPE_LARGE_ICON
+ : PRIMARY_ACTION_TYPE_SMALL_ICON;
+ mPrimaryActionIconResId = iconResId;
+ mPrimaryActionIconDrawable = drawable;
+ return this;
+ }
+
+ /**
+ * Sets {@code Primary Action} to be empty icon.
+ *
+ * {@code Text} would have a start margin as if {@code Primary Action} were set to
+ * primary icon.
+ *
+ * @return This Builder object to allow for chaining calls to set methods.
+ */
+ public Builder withPrimaryActionEmptyIcon() {
+ mPrimaryActionType = PRIMARY_ACTION_TYPE_EMPTY_ICON;
+ return this;
+ }
+
+ /**
+ * Sets {@code Primary Action} to have no icon. Text would align to the start of item.
+ *
+ * @return This Builder object to allow for chaining calls to set methods.
+ */
+ public Builder withPrimaryActionNoIcon() {
+ mPrimaryActionType = PRIMARY_ACTION_TYPE_NO_ICON;
+ return this;
+ }
+
+ /**
+ * Sets the title of item.
+ *
+ * <p>Primary text is {@code title} by default. It can be set by
+ * {@link #withBody(String, boolean)}
+ *
+ * @param title text to display as title.
+ * @return This Builder object to allow for chaining calls to set methods.
+ */
+ public Builder withTitle(String title) {
+ mTitle = title;
+ return this;
+ }
+
+ /**
+ * Sets the body text of item.
+ *
+ * <p>Text beyond length required by regulation will be truncated. Defaults {@code Title}
+ * text as the primary.
+ *
+ * @return This Builder object to allow for chaining calls to set methods.
+ */
+ public Builder withBody(String body) {
+ return withBody(body, false);
+ }
+
+ /**
+ * Sets the body text of item.
+ *
+ * <p>Text beyond length required by regulation will be truncated.
+ *
+ * @param asPrimary sets {@code Body Text} as primary text of item.
+ * @return This Builder object to allow for chaining calls to set methods.
+ */
+ public Builder withBody(String body, boolean asPrimary) {
+ int limit = mContext.getResources().getInteger(
+ R.integer.car_list_item_text_length_limit);
+ if (body.length() < limit) {
+ mBody = body;
+ } else {
+ mBody = body.substring(0, limit) + mContext.getString(R.string.ellipsis);
+ }
+ mIsBodyPrimary = asPrimary;
+ return this;
+ }
+
+ /**
+ * Sets {@code Supplemental Action} to be represented by an {@code Supplemental Icon}.
+ *
+ * @return This Builder object to allow for chaining calls to set methods.
+ */
+ public Builder withSupplementalIcon(int iconResId, boolean showDivider) {
+ return withSupplementalIcon(iconResId, showDivider, null);
+ }
+
+ /**
+ * Sets {@code Supplemental Action} to be represented by an {@code Supplemental Icon}.
+ *
+ * @param iconResId drawable resource id.
+ * @return This Builder object to allow for chaining calls to set methods.
+ */
+ public Builder withSupplementalIcon(int iconResId, boolean showDivider,
+ View.OnClickListener listener) {
+ mSupplementalActionType = SUPPLEMENTAL_ACTION_SUPPLEMENTAL_ICON;
+
+ mSupplementalIconResId = iconResId;
+ mSupplementalIconOnClickListener = listener;
+ mShowSupplementalIconDivider = showDivider;
+ return this;
+ }
+
+ /**
+ * Sets {@code Supplemental Action} to be represented by an {@code Action Button}.
+ *
+ * @param text button text to display.
+ * @return This Builder object to allow for chaining calls to set methods.
+ */
+ public Builder withAction(String text, boolean showDivider, View.OnClickListener listener) {
+ if (TextUtils.isEmpty(text)) {
+ throw new IllegalArgumentException("Action text cannot be empty.");
+ }
+ mSupplementalActionType = SUPPLEMENTAL_ACTION_ONE_ACTION;
+
+ mAction1Text = text;
+ mAction1OnClickListener = listener;
+ mShowAction1Divider = showDivider;
+ return this;
+ }
+
+ /**
+ * Sets {@code Supplemental Action} to be represented by two {@code Action Button}s.
+ *
+ * <p>These two action buttons will be aligned towards item end.
+ *
+ * @param action1Text button text to display - this button will be closer to item end.
+ * @param action2Text button text to display.
+ */
+ public Builder withActions(String action1Text, boolean showAction1Divider,
+ View.OnClickListener action1OnClickListener,
+ String action2Text, boolean showAction2Divider,
+ View.OnClickListener action2OnClickListener) {
+ if (TextUtils.isEmpty(action1Text)) {
+ throw new IllegalArgumentException("Action1 text cannot be empty.");
+ }
+ if (TextUtils.isEmpty(action2Text)) {
+ throw new IllegalArgumentException("Action2 text cannot be empty.");
+ }
+ mSupplementalActionType = SUPPLEMENTAL_ACTION_TWO_ACTIONS;
+
+ mAction1Text = action1Text;
+ mAction1OnClickListener = action1OnClickListener;
+ mShowAction1Divider = showAction1Divider;
+ mAction2Text = action2Text;
+ mAction2OnClickListener = action2OnClickListener;
+ mShowAction2Divider = showAction2Divider;
+ return this;
+ }
+
+ /**
+ * Adds {@link ViewBinder} to interact with sub-views in
+ * {@link ListItemAdapter.ViewHolder}. These ViewBinders will always bind after
+ * other {@link Builder} methods have bond.
+ *
+ * <p>Make sure to call with...() method on the intended sub-view first.
+ *
+ * <p>Example:
+ * <pre>
+ * {@code
+ * new Builder()
+ * .withTitle("title")
+ * .withViewBinder((viewHolder) -> {
+ * viewHolder.getTitle().doMoreStuff();
+ * })
+ * .build();
+ * }
+ * </pre>
+ */
+ public Builder withViewBinder(ViewBinder binder) {
+ mCustomBinders.add(binder);
+ return this;
+ }
+ }
+}
diff --git a/car/src/main/java/androidx/car/widget/ListItemAdapter.java b/car/src/main/java/androidx/car/widget/ListItemAdapter.java
new file mode 100644
index 0000000..2bdfae6
--- /dev/null
+++ b/car/src/main/java/androidx/car/widget/ListItemAdapter.java
@@ -0,0 +1,182 @@
+/*
+ * 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 androidx.car.widget;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.content.Context;
+import android.support.annotation.IntDef;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import java.lang.annotation.Retention;
+
+import androidx.car.R;
+
+/**
+ * Adapter for {@link PagedListView} to display {@link ListItem}.
+ *
+ * Implements {@link PagedListView.ItemCap} - defaults to unlimited item count.
+ */
+public class ListItemAdapter extends
+ RecyclerView.Adapter<ListItemAdapter.ViewHolder> implements PagedListView.ItemCap {
+ @Retention(SOURCE)
+ @IntDef({CAR_PAGED_LIST_ITEM, CAR_PAGED_LIST_CARD})
+ public @interface PagedListItemType {}
+ public static final int CAR_PAGED_LIST_ITEM = 0;
+ public static final int CAR_PAGED_LIST_CARD = 1;
+
+ private final Context mContext;
+ private final ListItemProvider mItemProvider;
+
+ private int mMaxItems = PagedListView.ItemCap.UNLIMITED;
+
+ public ListItemAdapter(Context context, ListItemProvider itemProvider) {
+ mContext = context;
+ mItemProvider = itemProvider;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return mItemProvider.get(position).getViewType();
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, @PagedListItemType int viewType) {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ int layoutId;
+ switch (viewType) {
+ case CAR_PAGED_LIST_ITEM:
+ layoutId = R.layout.car_paged_list_item;
+ break;
+ case CAR_PAGED_LIST_CARD:
+ layoutId = R.layout.car_paged_list_card;
+ break;
+ default:
+ throw new IllegalArgumentException("Unrecognizable view type: " + viewType);
+ }
+ View itemView = inflater.inflate(layoutId, parent, false);
+ return new ViewHolder(itemView);
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ ListItem item = mItemProvider.get(position);
+ item.bind(holder);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mMaxItems == PagedListView.ItemCap.UNLIMITED
+ ? mItemProvider.size()
+ : Math.min(mItemProvider.size(), mMaxItems);
+ }
+
+ @Override
+ public void setMaxItems(int maxItems) {
+ mMaxItems = maxItems;
+ }
+
+ /**
+ * Holds views of an item in PagedListView.
+ *
+ * <p>This ViewHolder maps to views in layout car_paged_list_item_content.xml.
+ */
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+
+ private RelativeLayout mContainerLayout;
+
+ private ImageView mPrimaryIcon;
+
+ private TextView mTitle;
+ private TextView mBody;
+
+ private View mSupplementalIconDivider;
+ private ImageView mSupplementalIcon;
+
+ private Button mAction1;
+ private View mAction1Divider;
+
+ private Button mAction2;
+ private View mAction2Divider;
+
+ public ViewHolder(View itemView) {
+ super(itemView);
+
+ mContainerLayout = itemView.findViewById(R.id.container);
+
+ mPrimaryIcon = itemView.findViewById(R.id.primary_icon);
+
+ mTitle = itemView.findViewById(R.id.title);
+ mBody = itemView.findViewById(R.id.body);
+
+ mSupplementalIcon = itemView.findViewById(R.id.supplemental_icon);
+ mSupplementalIconDivider = itemView.findViewById(R.id.supplemental_icon_divider);
+
+ mAction1 = itemView.findViewById(R.id.action1);
+ mAction1Divider = itemView.findViewById(R.id.action1_divider);
+ mAction2 = itemView.findViewById(R.id.action2);
+ mAction2Divider = itemView.findViewById(R.id.action2_divider);
+ }
+
+ public RelativeLayout getContainerLayout() {
+ return mContainerLayout;
+ }
+
+ public ImageView getPrimaryIcon() {
+ return mPrimaryIcon;
+ }
+
+ public TextView getTitle() {
+ return mTitle;
+ }
+
+ public TextView getBody() {
+ return mBody;
+ }
+
+ public ImageView getSupplementalIcon() {
+ return mSupplementalIcon;
+ }
+
+ public View getSupplementalIconDivider() {
+ return mSupplementalIconDivider;
+ }
+
+ public Button getAction1() {
+ return mAction1;
+ }
+
+ public View getAction1Divider() {
+ return mAction1Divider;
+ }
+
+ public Button getAction2() {
+ return mAction2;
+ }
+
+ public View getAction2Divider() {
+ return mAction2Divider;
+ }
+ }
+}
diff --git a/car/src/main/java/androidx/car/widget/ListItemProvider.java b/car/src/main/java/androidx/car/widget/ListItemProvider.java
new file mode 100644
index 0000000..5a3edbd
--- /dev/null
+++ b/car/src/main/java/androidx/car/widget/ListItemProvider.java
@@ -0,0 +1,56 @@
+/*
+ * 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 androidx.car.widget;
+
+import java.util.List;
+
+/**
+ * Supplies data as {@link ListItem}.
+ */
+public abstract class ListItemProvider {
+
+ /**
+ * Returns {@link ListItem} at requested position.
+ */
+ public abstract ListItem get(int position);
+
+ /**
+ * @return number of total items.
+ */
+ public abstract int size();
+
+ /**
+ * A simple provider that wraps around a list.
+ */
+ public static class ListProvider extends ListItemProvider {
+ private final List<ListItem> mItems;
+
+ public ListProvider(List<ListItem> items) {
+ mItems = items;
+ }
+
+ @Override
+ public ListItem get(int position) {
+ return mItems.get(position);
+ }
+
+ @Override
+ public int size() {
+ return mItems.size();
+ }
+ }
+}
diff --git a/car/src/main/java/android/support/car/widget/PagedLayoutManager.java b/car/src/main/java/androidx/car/widget/PagedLayoutManager.java
similarity index 99%
rename from car/src/main/java/android/support/car/widget/PagedLayoutManager.java
rename to car/src/main/java/androidx/car/widget/PagedLayoutManager.java
index c4f469a..cf3b75d 100644
--- a/car/src/main/java/android/support/car/widget/PagedLayoutManager.java
+++ b/car/src/main/java/androidx/car/widget/PagedLayoutManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.car.widget;
+package androidx.car.widget;
import android.content.Context;
import android.graphics.PointF;
@@ -23,7 +23,6 @@
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.VisibleForTesting;
-import android.support.car.R;
import android.support.v7.widget.LinearSmoothScroller;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.Recycler;
@@ -42,6 +41,8 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import androidx.car.R;
+
/**
* Custom {@link RecyclerView.LayoutManager} that behaves similar to LinearLayoutManager except that
* it has a few tricks up its sleeve.
diff --git a/car/src/main/java/android/support/car/widget/PagedListView.java b/car/src/main/java/androidx/car/widget/PagedListView.java
similarity index 90%
rename from car/src/main/java/android/support/car/widget/PagedListView.java
rename to car/src/main/java/androidx/car/widget/PagedListView.java
index 67a6247..88a59dc 100644
--- a/car/src/main/java/android/support/car/widget/PagedListView.java
+++ b/car/src/main/java/androidx/car/widget/PagedListView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.car.widget;
+package androidx.car.widget;
import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
@@ -28,12 +28,14 @@
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
+import android.support.annotation.ColorRes;
import android.support.annotation.IdRes;
+import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.support.annotation.UiThread;
-import android.support.car.R;
+import android.support.annotation.VisibleForTesting;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
@@ -43,6 +45,8 @@
import android.view.View;
import android.widget.FrameLayout;
+import androidx.car.R;
+
/**
* Custom {@link android.support.v7.widget.RecyclerView} that displays a list of items that
* resembles a {@link android.widget.ListView} but also has page up and page down arrows on the
@@ -71,7 +75,8 @@
protected final PagedLayoutManager mLayoutManager;
protected final Handler mHandler = new Handler();
private final boolean mScrollBarEnabled;
- private final PagedScrollBarView mScrollBarView;
+ @VisibleForTesting
+ final PagedScrollBarView mScrollBarView;
private int mRowsPerPage = -1;
protected RecyclerView.Adapter<? extends RecyclerView.ViewHolder> mAdapter;
@@ -119,6 +124,39 @@
}
/**
+ * The possible values for @{link #setGutter}. The default value is actually
+ * {@link Gutter#BOTH}.
+ */
+ @IntDef({
+ Gutter.NONE,
+ Gutter.START,
+ Gutter.END,
+ Gutter.BOTH,
+ })
+ public @interface Gutter {
+ /**
+ * No gutter on either side of the list items. The items will span the full width of the
+ * {@link PagedListView}.
+ */
+ int NONE = 0;
+
+ /**
+ * Include a gutter only on the start side (that is, the same side as the scroll bar).
+ */
+ int START = 1;
+
+ /**
+ * Include a gutter only on the end side (that is, the opposite side of the scroll bar).
+ */
+ int END = 2;
+
+ /**
+ * Include a gutter on both sides of the list items. This is the default behaviour.
+ */
+ int BOTH = 3;
+ }
+
+ /**
* Interface for a {@link android.support.v7.widget.RecyclerView.Adapter} to set the position
* offset for the adapter to load the data.
*
@@ -167,14 +205,17 @@
mRecyclerView.getRecycledViewPool().setMaxRecycledViews(0, 12);
mRecyclerView.setItemAnimator(new CarItemAnimator(mLayoutManager));
- boolean offsetScrollBar = a.getBoolean(R.styleable.PagedListView_offsetScrollBar, false);
- if (offsetScrollBar) {
- MarginLayoutParams params = (MarginLayoutParams) mRecyclerView.getLayoutParams();
- params.setMarginStart(getResources().getDimensionPixelSize(
- R.dimen.car_margin));
- params.setMarginEnd(
- a.getDimensionPixelSize(R.styleable.PagedListView_listEndMargin, 0));
- mRecyclerView.setLayoutParams(params);
+ if (a.hasValue(R.styleable.PagedListView_gutter)) {
+ int gutter = a.getInt(R.styleable.PagedListView_gutter, Gutter.BOTH);
+ setGutter(gutter);
+ } else if (a.hasValue(R.styleable.PagedListView_offsetScrollBar)) {
+ boolean offsetScrollBar =
+ a.getBoolean(R.styleable.PagedListView_offsetScrollBar, false);
+ if (offsetScrollBar) {
+ setGutter(Gutter.START);
+ }
+ } else {
+ setGutter(Gutter.BOTH);
}
if (a.getBoolean(R.styleable.PagedListView_showPagedListViewDivider, true)) {
@@ -286,6 +327,31 @@
return mLayoutManager.getPosition(v);
}
+ /**
+ * Set the gutter to the specified value.
+ *
+ * The gutter is the space to the start/end of the list view items and will be equal in size
+ * to the scroll bars. By default, there is a gutter to both the left and right of the list
+ * view items, to account for the scroll bar.
+ *
+ * @param gutter A {@link Gutter} value that identifies which sides to apply the gutter to.
+ */
+ public void setGutter(@Gutter int gutter) {
+ int startPadding = 0;
+ int endPadding = 0;
+ if ((gutter & Gutter.START) != 0) {
+ startPadding = getResources().getDimensionPixelSize(R.dimen.car_margin);
+ }
+ if ((gutter & Gutter.END) != 0) {
+ endPadding = getResources().getDimensionPixelSize(R.dimen.car_margin);
+ }
+ mRecyclerView.setPaddingRelative(startPadding, 0, endPadding, 0);
+
+ // If there's a gutter, set ClipToPadding to false so that CardView's shadow will still
+ // appear outside of the padding.
+ mRecyclerView.setClipToPadding(startPadding == 0 && endPadding == 0);
+ }
+
@NonNull
public CarRecyclerView getRecyclerView() {
return mRecyclerView;
@@ -451,6 +517,25 @@
}
/**
+ * Sets the color of scrollbar.
+ *
+ * <p>Custom color ignores {@link DayNightStyle}. Calling {@link #resetScrollbarColor} resets to
+ * default color.
+ *
+ * @param color Resource identifier of the color.
+ */
+ public void setScrollbarColor(@ColorRes int color) {
+ mScrollBarView.setThumbColor(color);
+ }
+
+ /**
+ * Resets the color of scrollbar to default.
+ */
+ public void resetScrollbarColor() {
+ mScrollBarView.resetThumbColor();
+ }
+
+ /**
* Adds an {@link android.support.v7.widget.RecyclerView.OnItemTouchListener} to this
* PagedListView.
*
@@ -473,6 +558,7 @@
public void removeOnItemTouchListener(@NonNull RecyclerView.OnItemTouchListener touchListener) {
mRecyclerView.removeOnItemTouchListener(touchListener);
}
+
/**
* Sets how this {@link PagedListView} responds to day/night configuration changes. By
* default, the PagedListView is darker in the day and lighter at night.
@@ -940,7 +1026,7 @@
Resources res = context.getResources();
mPaint = new Paint();
mPaint.setColor(res.getColor(R.color.car_list_divider));
- mDividerHeight = res.getDimensionPixelSize(R.dimen.car_divider_height);
+ mDividerHeight = res.getDimensionPixelSize(R.dimen.car_list_divider_height);
}
/** Updates the list divider color which may have changed due to a day night transition. */
@@ -970,8 +1056,18 @@
continue;
}
- int left = mDividerStartMargin + startChild.getLeft();
- int right = endChild.getRight();
+ Rect containerRect = new Rect();
+ container.getGlobalVisibleRect(containerRect);
+
+ Rect startRect = new Rect();
+ startChild.getGlobalVisibleRect(startRect);
+
+ Rect endRect = new Rect();
+ endChild.getGlobalVisibleRect(endRect);
+
+ int left = container.getLeft() + mDividerStartMargin
+ + (startRect.left - containerRect.left);
+ int right = container.getRight() - (endRect.right - containerRect.right);
int bottom = container.getBottom() + spacing / 2 + mDividerHeight / 2;
int top = bottom - mDividerHeight;
diff --git a/car/src/main/java/android/support/car/widget/PagedScrollBarView.java b/car/src/main/java/androidx/car/widget/PagedScrollBarView.java
similarity index 81%
rename from car/src/main/java/android/support/car/widget/PagedScrollBarView.java
rename to car/src/main/java/androidx/car/widget/PagedScrollBarView.java
index 1c46b5d..25f586c 100644
--- a/car/src/main/java/android/support/car/widget/PagedScrollBarView.java
+++ b/car/src/main/java/androidx/car/widget/PagedScrollBarView.java
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package android.support.car.widget;
+package androidx.car.widget;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
-import android.support.car.R;
+import android.support.annotation.ColorRes;
+import android.support.annotation.VisibleForTesting;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -30,6 +31,8 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
+import androidx.car.R;
+
/** A custom view to provide list scroll behaviour -- up/down buttons and scroll indicator. */
public class PagedScrollBarView extends FrameLayout
implements View.OnClickListener, View.OnLongClickListener {
@@ -48,13 +51,16 @@
private final ImageView mUpButton;
private final ImageView mDownButton;
- private final ImageView mScrollThumb;
+ @VisibleForTesting
+ final ImageView mScrollThumb;
/** The "filler" view between the up and down buttons */
private final View mFiller;
private final Interpolator mPaginationInterpolator = new AccelerateDecelerateInterpolator();
private final int mMinThumbLength;
private final int mMaxThumbLength;
+ private boolean mUseCustomThumbBackground;
+ @ColorRes private int mCustomThumbBackgroundResId;
private PaginationListener mPaginationListener;
public PagedScrollBarView(Context context, AttributeSet attrs) {
@@ -84,8 +90,10 @@
mScrollThumb = (ImageView) findViewById(R.id.scrollbar_thumb);
mFiller = findViewById(R.id.filler);
- mMinThumbLength = getResources().getDimensionPixelSize(R.dimen.min_thumb_height);
- mMaxThumbLength = getResources().getDimensionPixelSize(R.dimen.max_thumb_height);
+ mMinThumbLength = getResources()
+ .getDimensionPixelSize(R.dimen.car_min_scroll_bar_thumb_height);
+ mMaxThumbLength = getResources()
+ .getDimensionPixelSize(R.dimen.car_max_scroll_bar_thumb_height);
}
@Override
@@ -196,43 +204,65 @@
return mDownButton.isEnabled();
}
+ /**
+ * Sets the color of thumb.
+ *
+ * <p>Custom thumb color ignores {@link DayNightStyle}. Calling {@link #resetThumbColor} resets
+ * to default color.
+ *
+ * @param color Resource identifier of the color.
+ */
+ public void setThumbColor(@ColorRes int color) {
+ mUseCustomThumbBackground = true;
+ mCustomThumbBackgroundResId = color;
+ reloadColors();
+ }
+
+ /**
+ * Resets the color of thumb to default.
+ */
+ public void resetThumbColor() {
+ mUseCustomThumbBackground = false;
+ reloadColors();
+ }
+
/** Reload the colors for the current {@link DayNightStyle}. */
private void reloadColors() {
- int tint;
- int thumbBackground;
+ int tintResId;
+ int thumbBackgroundResId;
int upDownBackgroundResId;
switch (mDayNightStyle) {
case DayNightStyle.AUTO:
- tint = ContextCompat.getColor(getContext(), R.color.car_tint);
- thumbBackground = ContextCompat.getColor(getContext(),
- R.color.car_scrollbar_thumb);
+ tintResId = R.color.car_tint;
+ thumbBackgroundResId = R.color.car_scrollbar_thumb;
upDownBackgroundResId = R.drawable.car_pagination_background;
break;
case DayNightStyle.AUTO_INVERSE:
- tint = ContextCompat.getColor(getContext(), R.color.car_tint_inverse);
- thumbBackground = ContextCompat.getColor(getContext(),
- R.color.car_scrollbar_thumb_inverse);
+ tintResId = R.color.car_tint_inverse;
+ thumbBackgroundResId = R.color.car_scrollbar_thumb_inverse;
upDownBackgroundResId = R.drawable.car_pagination_background_inverse;
break;
case DayNightStyle.FORCE_NIGHT:
- tint = ContextCompat.getColor(getContext(), R.color.car_tint_light);
- thumbBackground = ContextCompat.getColor(getContext(),
- R.color.car_scrollbar_thumb_light);
+ tintResId = R.color.car_tint_light;
+ thumbBackgroundResId = R.color.car_scrollbar_thumb_light;
upDownBackgroundResId = R.drawable.car_pagination_background_night;
break;
case DayNightStyle.FORCE_DAY:
- tint = ContextCompat.getColor(getContext(), R.color.car_tint_dark);
- thumbBackground = ContextCompat.getColor(getContext(),
- R.color.car_scrollbar_thumb_dark);
+ tintResId = R.color.car_tint_dark;
+ thumbBackgroundResId = R.color.car_scrollbar_thumb_dark;
upDownBackgroundResId = R.drawable.car_pagination_background_day;
break;
default:
throw new IllegalArgumentException("Unknown DayNightStyle: " + mDayNightStyle);
}
- mScrollThumb.setBackgroundColor(thumbBackground);
+ if (mUseCustomThumbBackground) {
+ thumbBackgroundResId = mCustomThumbBackgroundResId;
+ }
+ mScrollThumb.setBackgroundColor(ContextCompat.getColor(getContext(), thumbBackgroundResId));
+ int tint = ContextCompat.getColor(getContext(), tintResId);
mUpButton.setColorFilter(tint, PorterDuff.Mode.SRC_IN);
mUpButton.setBackgroundResource(upDownBackgroundResId);
diff --git a/car/tests/AndroidManifest.xml b/car/tests/AndroidManifest.xml
index 949e85a..8e5422d 100644
--- a/car/tests/AndroidManifest.xml
+++ b/car/tests/AndroidManifest.xml
@@ -15,12 +15,12 @@
~ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.support.car.widget.test">
+ package="androidx.car.widget.test">
<uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
<application android:supportsRtl="true">
- <activity android:name="android.support.car.widget.ColumnCardViewTestActivity"/>
- <activity android:name="android.support.car.widget.PagedListViewSavedStateActivity"/>
- <activity android:name="android.support.car.widget.PagedListViewTestActivity"/>
+ <activity android:name="androidx.car.widget.ColumnCardViewTestActivity"/>
+ <activity android:name="androidx.car.widget.PagedListViewSavedStateActivity"/>
+ <activity android:name="androidx.car.widget.PagedListViewTestActivity"/>
</application>
</manifest>
diff --git a/car/tests/res/layout/activity_column_card_view.xml b/car/tests/res/layout/activity_column_card_view.xml
index ad9c5e1..a6acc57 100644
--- a/car/tests/res/layout/activity_column_card_view.xml
+++ b/car/tests/res/layout/activity_column_card_view.xml
@@ -21,13 +21,13 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <android.support.car.widget.ColumnCardView
+ <androidx.car.widget.ColumnCardView
android:id="@+id/default_width_column_card"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
- <android.support.car.widget.ColumnCardView
+ <androidx.car.widget.ColumnCardView
car:columnSpan="2"
android:id="@+id/span_2_column_card"
android:layout_gravity="center"
diff --git a/car/tests/res/layout/activity_paged_list_view.xml b/car/tests/res/layout/activity_paged_list_view.xml
index d14eb96..d7c8946 100644
--- a/car/tests/res/layout/activity_paged_list_view.xml
+++ b/car/tests/res/layout/activity_paged_list_view.xml
@@ -21,7 +21,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.car.widget.PagedListView
+ <androidx.car.widget.PagedListView
android:id="@+id/paged_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/car/tests/res/layout/activity_two_paged_list_view.xml b/car/tests/res/layout/activity_two_paged_list_view.xml
index 588071f..457cb95 100644
--- a/car/tests/res/layout/activity_two_paged_list_view.xml
+++ b/car/tests/res/layout/activity_two_paged_list_view.xml
@@ -21,7 +21,7 @@
android:layout_height="match_parent"
android:orientation="horizontal">
- <android.support.car.widget.PagedListView
+ <androidx.car.widget.PagedListView
android:id="@+id/paged_list_view_1"
android:layout_weight="1"
android:layout_width="0dp"
@@ -29,7 +29,7 @@
app:showPagedListViewDivider="false"
app:offsetScrollBar="true"/>
- <android.support.car.widget.PagedListView
+ <androidx.car.widget.PagedListView
android:id="@+id/paged_list_view_2"
android:layout_weight="1"
android:layout_width="0dp"
diff --git a/car/tests/res/layout/paged_list_item_column_card.xml b/car/tests/res/layout/paged_list_item_column_card.xml
index 2bc5cd0..5028abf 100644
--- a/car/tests/res/layout/paged_list_item_column_card.xml
+++ b/car/tests/res/layout/paged_list_item_column_card.xml
@@ -20,7 +20,7 @@
android:layout_height="wrap_content"
android:orientation="vertical">
- <android.support.car.widget.ColumnCardView
+ <androidx.car.widget.ColumnCardView
android:id="@+id/column_card"
android:layout_width="match_parent"
android:layout_height="wrap_content">
@@ -30,6 +30,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
- </android.support.car.widget.ColumnCardView>
+ </androidx.car.widget.ColumnCardView>
</FrameLayout>
diff --git a/car/res/values-w1024dp/dimens.xml b/car/tests/res/values/strings.xml
similarity index 78%
copy from car/res/values-w1024dp/dimens.xml
copy to car/tests/res/values/strings.xml
index b1ae5ba..478abc4 100644
--- a/car/res/values-w1024dp/dimens.xml
+++ b/car/tests/res/values/strings.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<resources>
- <dimen name="car_screen_margin_size">112dp</dimen>
+ <string name="over_120_chars">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</string>
</resources>
diff --git a/car/tests/src/android/support/car/widget/ColumnCardViewTest.java b/car/tests/src/androidx/car/widget/ColumnCardViewTest.java
similarity index 96%
rename from car/tests/src/android/support/car/widget/ColumnCardViewTest.java
rename to car/tests/src/androidx/car/widget/ColumnCardViewTest.java
index cb61caf..1963629 100644
--- a/car/tests/src/android/support/car/widget/ColumnCardViewTest.java
+++ b/car/tests/src/androidx/car/widget/ColumnCardViewTest.java
@@ -14,13 +14,11 @@
* limitations under the License.
*/
-package android.support.car.widget;
+package androidx.car.widget;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import android.support.car.test.R;
-import android.support.car.utils.ColumnCalculator;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.rule.ActivityTestRule;
@@ -32,6 +30,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import androidx.car.test.R;
+import androidx.car.utils.ColumnCalculator;
+
/** Instrumentation unit tests for {@link ColumnCardView}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
diff --git a/car/tests/src/android/support/car/widget/ColumnCardViewTestActivity.java b/car/tests/src/androidx/car/widget/ColumnCardViewTestActivity.java
similarity index 92%
rename from car/tests/src/android/support/car/widget/ColumnCardViewTestActivity.java
rename to car/tests/src/androidx/car/widget/ColumnCardViewTestActivity.java
index 693e4a1..3f42d62 100644
--- a/car/tests/src/android/support/car/widget/ColumnCardViewTestActivity.java
+++ b/car/tests/src/androidx/car/widget/ColumnCardViewTestActivity.java
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.support.car.widget;
+package androidx.car.widget;
import android.app.Activity;
import android.os.Bundle;
-import android.support.car.test.R;
+
+import androidx.car.test.R;
public class ColumnCardViewTestActivity extends Activity {
@Override
diff --git a/car/tests/src/androidx/car/widget/ListItemTest.java b/car/tests/src/androidx/car/widget/ListItemTest.java
new file mode 100644
index 0000000..64b9ede
--- /dev/null
+++ b/car/tests/src/androidx/car/widget/ListItemTest.java
@@ -0,0 +1,560 @@
+/*
+ * 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 androidx.car.widget;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition;
+import static android.support.test.espresso.contrib.RecyclerViewActions.scrollToPosition;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+import static junit.framework.TestCase.assertFalse;
+
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.hamcrest.number.IsCloseTo.closeTo;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.drawable.Drawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.widget.CardView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import androidx.car.test.R;
+
+/**
+* Tests the layout configuration in {@link ListItem}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ListItemTest {
+
+ @Rule
+ public ActivityTestRule<PagedListViewTestActivity> mActivityRule =
+ new ActivityTestRule<>(PagedListViewTestActivity.class);
+
+ private PagedListViewTestActivity mActivity;
+ private PagedListView mPagedListView;
+
+ @Before
+ public void setUp() {
+ mActivity = mActivityRule.getActivity();
+ mPagedListView = mActivity.findViewById(R.id.paged_list_view);
+ }
+
+ private void setupPagedListView(List<ListItem> items) {
+ ListItemProvider provider = new ListItemProvider.ListProvider(
+ new ArrayList<>(items));
+ try {
+ mActivityRule.runOnUiThread(() -> {
+ mPagedListView.setAdapter(new ListItemAdapter(mActivity, provider));
+ });
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ throw new RuntimeException(throwable);
+ }
+ // Wait for paged list view to layout by using espresso to scroll to a position.
+ onView(withId(R.id.recycler_view)).perform(scrollToPosition(0));
+ }
+
+ private static void verifyViewIsHidden(View view) {
+ if (view instanceof ViewGroup) {
+ ViewGroup viewGroup = (ViewGroup) view;
+ final int childCount = viewGroup.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ verifyViewIsHidden(viewGroup.getChildAt(i));
+ }
+ } else {
+ assertThat(view.getVisibility(), is(equalTo(View.GONE)));
+ }
+ }
+
+ private ListItemAdapter.ViewHolder getViewHolderAtPosition(int position) {
+ return (ListItemAdapter.ViewHolder) mPagedListView.getRecyclerView()
+ .findViewHolderForAdapterPosition(
+ position);
+ }
+
+ @Test
+ public void testEmptyItemHidesAllViews() {
+ ListItem item = new ListItem.Builder(mActivity).build();
+ setupPagedListView(Arrays.asList(item));
+ verifyViewIsHidden(mPagedListView.findViewByPosition(0));
+ }
+
+ @Test
+ public void testPrimaryActionVisible() {
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, true)
+ .build(),
+ new ListItem.Builder(mActivity)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false)
+ .build());
+ setupPagedListView(items);
+
+ assertThat(getViewHolderAtPosition(0).getPrimaryIcon().getVisibility(),
+ is(equalTo(View.VISIBLE)));
+ assertThat(getViewHolderAtPosition(1).getPrimaryIcon().getVisibility(),
+ is(equalTo(View.VISIBLE)));
+ }
+
+ @Test
+ public void testTextVisible() {
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withTitle("title")
+ .build(),
+ new ListItem.Builder(mActivity)
+ .withBody("body")
+ .build());
+ setupPagedListView(items);
+
+ assertThat(getViewHolderAtPosition(0).getTitle().getVisibility(),
+ is(equalTo(View.VISIBLE)));
+ assertThat(getViewHolderAtPosition(1).getBody().getVisibility(),
+ is(equalTo(View.VISIBLE)));
+ }
+
+ @Test
+ public void testSupplementalActionVisible() {
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withSupplementalIcon(android.R.drawable.sym_def_app_icon, true)
+ .build(),
+ new ListItem.Builder(mActivity)
+ .withAction("text", true, null)
+ .build(),
+ new ListItem.Builder(mActivity)
+ .withActions("text", true, null,
+ "text", true, null)
+ .build());
+ setupPagedListView(items);
+
+ ListItemAdapter.ViewHolder viewHolder = getViewHolderAtPosition(0);
+ assertThat(viewHolder.getSupplementalIcon().getVisibility(), is(equalTo(View.VISIBLE)));
+ assertThat(viewHolder.getSupplementalIconDivider().getVisibility(),
+ is(equalTo(View.VISIBLE)));
+
+ viewHolder = getViewHolderAtPosition(1);
+ assertThat(viewHolder.getAction1().getVisibility(), is(equalTo(View.VISIBLE)));
+ assertThat(viewHolder.getAction1Divider().getVisibility(), is(equalTo(View.VISIBLE)));
+
+ viewHolder = getViewHolderAtPosition(2);
+ assertThat(viewHolder.getAction1().getVisibility(), is(equalTo(View.VISIBLE)));
+ assertThat(viewHolder.getAction1Divider().getVisibility(), is(equalTo(View.VISIBLE)));
+ assertThat(viewHolder.getAction2().getVisibility(), is(equalTo(View.VISIBLE)));
+ assertThat(viewHolder.getAction2Divider().getVisibility(), is(equalTo(View.VISIBLE)));
+ }
+
+ @Test
+ public void testDividersAreOptional() {
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withSupplementalIcon(android.R.drawable.sym_def_app_icon, false)
+ .build(),
+ new ListItem.Builder(mActivity)
+ .withAction("text", false, null)
+ .build(),
+ new ListItem.Builder(mActivity)
+ .withActions("text", false, null,
+ "text", false, null)
+ .build());
+ setupPagedListView(items);
+
+ setupPagedListView(items);
+
+ ListItemAdapter.ViewHolder viewHolder = getViewHolderAtPosition(0);
+ assertThat(viewHolder.getSupplementalIcon().getVisibility(), is(equalTo(View.VISIBLE)));
+ assertThat(viewHolder.getSupplementalIconDivider().getVisibility(),
+ is(equalTo(View.GONE)));
+
+ viewHolder = getViewHolderAtPosition(1);
+ assertThat(viewHolder.getAction1().getVisibility(), is(equalTo(View.VISIBLE)));
+ assertThat(viewHolder.getAction1Divider().getVisibility(), is(equalTo(View.GONE)));
+
+ viewHolder = getViewHolderAtPosition(2);
+ assertThat(viewHolder.getAction1().getVisibility(), is(equalTo(View.VISIBLE)));
+ assertThat(viewHolder.getAction1Divider().getVisibility(), is(equalTo(View.GONE)));
+ assertThat(viewHolder.getAction2().getVisibility(), is(equalTo(View.VISIBLE)));
+ assertThat(viewHolder.getAction2Divider().getVisibility(), is(equalTo(View.GONE)));
+ }
+
+ @Test
+ public void testTextStartMarginMatchesPrimaryActionType() {
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, true)
+ .build(),
+ new ListItem.Builder(mActivity)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false)
+ .build(),
+ new ListItem.Builder(mActivity)
+ .withPrimaryActionEmptyIcon()
+ .build(),
+ new ListItem.Builder(mActivity)
+ .withPrimaryActionNoIcon()
+ .build());
+ List<Integer> expectedStartMargin = Arrays.asList(R.dimen.car_keyline_4,
+ R.dimen.car_keyline_3, R.dimen.car_keyline_3, R.dimen.car_keyline_1);
+ setupPagedListView(items);
+
+ for (int i = 0; i < items.size(); i++) {
+ ListItemAdapter.ViewHolder viewHolder = getViewHolderAtPosition(i);
+
+ int expected = InstrumentationRegistry.getContext().getResources()
+ .getDimensionPixelSize(expectedStartMargin.get(i));
+ assertThat(((ViewGroup.MarginLayoutParams) viewHolder.getTitle().getLayoutParams())
+ .getMarginStart(), is(equalTo(expected)));
+ assertThat(((ViewGroup.MarginLayoutParams) viewHolder.getBody().getLayoutParams())
+ .getMarginStart(), is(equalTo(expected)));
+ }
+ }
+
+ @Test
+ public void testItemWithOnlyTitleIsSingleLine() {
+ List<ListItem> items = Arrays.asList(
+ // Only space
+ new ListItem.Builder(mActivity)
+ .withTitle(" ")
+ .build(),
+ // Underscore
+ new ListItem.Builder(mActivity)
+ .withTitle("______")
+ .build(),
+ new ListItem.Builder(mActivity)
+ .withTitle("ALL UPPER CASE")
+ .build(),
+ // String wouldn't fit in one line
+ new ListItem.Builder(mActivity)
+ .withTitle(InstrumentationRegistry.getContext().getResources().getString(
+ R.string.over_120_chars))
+ .build());
+ setupPagedListView(items);
+
+ double singleLineHeight = InstrumentationRegistry.getContext().getResources().getDimension(
+ R.dimen.car_single_line_list_item_height);
+
+ for (int i = 0; i < items.size(); i++) {
+ assertThat((double) mPagedListView.findViewByPosition(i).getHeight(),
+ is(closeTo(singleLineHeight, 1.0d)));
+ }
+ }
+
+ @Test
+ public void testItemWithBodyTextIsAtLeastDoubleLine() {
+ List<ListItem> items = Arrays.asList(
+ // Only space
+ new ListItem.Builder(mActivity)
+ .withBody(" ")
+ .build(),
+ // Underscore
+ new ListItem.Builder(mActivity)
+ .withBody("____")
+ .build(),
+ // String wouldn't fit in one line
+ new ListItem.Builder(mActivity)
+ .withBody(InstrumentationRegistry.getContext().getResources().getString(
+ R.string.over_120_chars))
+ .build());
+ setupPagedListView(items);
+
+ final int doubleLineHeight =
+ (int) InstrumentationRegistry.getContext().getResources().getDimension(
+ R.dimen.car_double_line_list_item_height);
+
+ for (int i = 0; i < items.size(); i++) {
+ assertThat(mPagedListView.findViewByPosition(i).getHeight(),
+ is(greaterThanOrEqualTo(doubleLineHeight)));
+ }
+ }
+
+ @Test
+ public void testBodyTextLengthLimit() {
+ final String longText = InstrumentationRegistry.getContext().getResources().getString(
+ R.string.over_120_chars);
+ final int limit = InstrumentationRegistry.getContext().getResources().getInteger(
+ R.integer.car_list_item_text_length_limit);
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withBody(longText)
+ .build());
+ setupPagedListView(items);
+
+ // + 1 for appended ellipsis.
+ assertThat(getViewHolderAtPosition(0).getBody().getText().length(),
+ is(equalTo(limit + 1)));
+ }
+
+ @Test
+ public void testPrimaryIconDrawable() {
+ Drawable drawable = InstrumentationRegistry.getContext().getResources().getDrawable(
+ android.R.drawable.sym_def_app_icon, null);
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withPrimaryActionIcon(drawable, true)
+ .build());
+ setupPagedListView(items);
+
+ assertTrue(getViewHolderAtPosition(0).getPrimaryIcon().getDrawable().getConstantState()
+ .equals(drawable.getConstantState()));
+ }
+
+ @Test
+ public void testLargePrimaryIconHasNoStartMargin() {
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, true)
+ .build());
+ setupPagedListView(items);
+
+ ListItemAdapter.ViewHolder viewHolder = getViewHolderAtPosition(0);
+ assertThat(((ViewGroup.MarginLayoutParams) viewHolder.getPrimaryIcon().getLayoutParams())
+ .getMarginStart(), is(equalTo(0)));
+ }
+
+ @Test
+ public void testSmallPrimaryIconStartMargin() {
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false)
+ .build());
+ setupPagedListView(items);
+
+ int expected = InstrumentationRegistry.getContext().getResources().getDimensionPixelSize(
+ R.dimen.car_keyline_1);
+
+ ListItemAdapter.ViewHolder viewHolder = getViewHolderAtPosition(0);
+ assertThat(((ViewGroup.MarginLayoutParams) viewHolder.getPrimaryIcon().getLayoutParams())
+ .getMarginStart(), is(equalTo(expected)));
+ }
+
+ @Test
+ public void testClickingPrimaryActionIsSeparateFromSupplementalAction() {
+ final boolean[] clicked = {false, false};
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withOnClickListener((v) -> clicked[0] = true)
+ .withSupplementalIcon(android.R.drawable.sym_def_app_icon, true,
+ (v) -> clicked[1] = true)
+ .build());
+ setupPagedListView(items);
+
+ onView(withId(R.id.recycler_view)).perform(actionOnItemAtPosition(0, click()));
+ assertTrue(clicked[0]);
+ assertFalse(clicked[1]);
+
+ onView(withId(R.id.recycler_view)).perform(
+ actionOnItemAtPosition(0, clickChildViewWithId(R.id.supplemental_icon)));
+ assertTrue(clicked[1]);
+ }
+
+ @Test
+ public void testClickingSupplementalIcon() {
+ final boolean[] clicked = {false};
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withSupplementalIcon(android.R.drawable.sym_def_app_icon, true,
+ (v) -> clicked[0] = true)
+ .build());
+ setupPagedListView(items);
+
+ onView(withId(R.id.recycler_view)).perform(
+ actionOnItemAtPosition(0, clickChildViewWithId(R.id.supplemental_icon)));
+ assertTrue(clicked[0]);
+ }
+
+ @Test
+ public void testClickingSupplementalAction() {
+ final boolean[] clicked = {false};
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withAction("action", true, (v) -> clicked[0] = true)
+ .build());
+ setupPagedListView(items);
+
+ onView(withId(R.id.recycler_view)).perform(
+ actionOnItemAtPosition(0, clickChildViewWithId(R.id.action1)));
+ assertTrue(clicked[0]);
+ }
+
+ @Test
+ public void testClickingBothSupplementalActions() {
+ final boolean[] clicked = {false, false};
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withActions("action 1", true, (v) -> clicked[0] = true,
+ "action 2", true, (v) -> clicked[1] = true)
+ .build());
+ setupPagedListView(items);
+
+ onView(withId(R.id.recycler_view)).perform(
+ actionOnItemAtPosition(0, clickChildViewWithId(R.id.action1)));
+ assertTrue(clicked[0]);
+ assertFalse(clicked[1]);
+
+ onView(withId(R.id.recycler_view)).perform(
+ actionOnItemAtPosition(0, clickChildViewWithId(R.id.action2)));
+ assertTrue(clicked[1]);
+ }
+
+ @Test
+ public void testCustomViewBinderAreCalledLast() {
+ final String updatedTitle = "updated title";
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withTitle("original title")
+ .withViewBinder((viewHolder) -> viewHolder.getTitle().setText(updatedTitle))
+ .build());
+ setupPagedListView(items);
+
+ ListItemAdapter.ViewHolder viewHolder = getViewHolderAtPosition(0);
+ assertThat(viewHolder.getTitle().getText(), is(equalTo(updatedTitle)));
+ }
+
+ @Test
+ public void testCustomViewBinderOnUnusedViewsHasNoEffect() {
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withViewBinder((viewHolder) -> viewHolder.getBody().setText("text"))
+ .build());
+ setupPagedListView(items);
+
+ ListItemAdapter.ViewHolder viewHolder = getViewHolderAtPosition(0);
+ assertThat(viewHolder.getBody().getVisibility(), is(equalTo(View.GONE)));
+ // Custom binder interacts with body but has no effect.
+ // Expect card height to remain single line.
+ assertThat((double) viewHolder.itemView.getHeight(), is(closeTo(
+ InstrumentationRegistry.getContext().getResources().getDimension(
+ R.dimen.car_single_line_list_item_height), 1.0d)));
+ }
+
+ @Test
+ public void testCardLookUsesCardView() {
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withCardLook()
+ .build());
+ setupPagedListView(items);
+
+ ListItemAdapter.ViewHolder viewHolder = getViewHolderAtPosition(0);
+ assertThat(viewHolder.itemView, is(instanceOf(CardView.class)));
+ }
+
+ @Test
+ public void testSettingTitleOrBodyAsPrimaryText() {
+ // Create 2 items, one with Title as primary (default) and one with Body.
+ // The primary text, regardless of view, should have consistent look (as primary).
+ List<ListItem> items = Arrays.asList(
+ new ListItem.Builder(mActivity)
+ .withTitle("title")
+ .withBody("body")
+ .build(),
+ new ListItem.Builder(mActivity)
+ .withTitle("title")
+ .withBody("body", true)
+ .build());
+ setupPagedListView(items);
+
+ ListItemAdapter.ViewHolder titlePrimary = getViewHolderAtPosition(0);
+ ListItemAdapter.ViewHolder bodyPrimary = getViewHolderAtPosition(1);
+ assertThat(titlePrimary.getTitle().getTextSize(),
+ is(equalTo(bodyPrimary.getBody().getTextSize())));
+ assertThat(titlePrimary.getTitle().getTextColors(),
+ is(equalTo(bodyPrimary.getBody().getTextColors())));
+ }
+
+ @Test
+ public void testNoCarriedOverLayoutParamsForTextView() throws Throwable {
+ ListItem singleLine = new ListItem.Builder(mActivity).withTitle("t").build();
+ setupPagedListView(Arrays.asList(singleLine));
+
+ // Manually rebind the view holder of a single line item to a double line item.
+ ListItem doubleLine = new ListItem.Builder(mActivity).withTitle("t").withBody("b").build();
+ ListItemAdapter.ViewHolder viewHolder = getViewHolderAtPosition(0);
+ mActivityRule.runOnUiThread(() -> doubleLine.bind(viewHolder));
+
+ RelativeLayout.LayoutParams titleLayoutParams =
+ (RelativeLayout.LayoutParams) viewHolder.getTitle().getLayoutParams();
+ RelativeLayout.LayoutParams bodyLayoutParams =
+ (RelativeLayout.LayoutParams) viewHolder.getTitle().getLayoutParams();
+ assertThat(titleLayoutParams.getRule(RelativeLayout.CENTER_VERTICAL), is(equalTo(0)));
+ assertThat(bodyLayoutParams.getRule(RelativeLayout.CENTER_VERTICAL), is(equalTo(0)));
+ }
+
+ @Test
+ public void testNoCarriedOverLayoutParamsForPrimaryIcon() throws Throwable {
+ ListItem smallIcon = new ListItem.Builder(mActivity)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false)
+ .withBody("body") // Small icon of items with body text should use top margin.
+ .build();
+ setupPagedListView(Arrays.asList(smallIcon));
+
+ // Manually rebind the view holder.
+ ListItem largeIcon = new ListItem.Builder(mActivity)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, true)
+ .build();
+ ListItemAdapter.ViewHolder viewHolder = getViewHolderAtPosition(0);
+ mActivityRule.runOnUiThread(() -> largeIcon.bind(viewHolder));
+
+ RelativeLayout.LayoutParams iconLayoutParams =
+ (RelativeLayout.LayoutParams) viewHolder.getPrimaryIcon().getLayoutParams();
+ assertThat(iconLayoutParams.getRule(RelativeLayout.CENTER_VERTICAL),
+ is(equalTo(RelativeLayout.TRUE)));
+ assertThat(iconLayoutParams.topMargin, is(equalTo(0)));
+ }
+
+ private static ViewAction clickChildViewWithId(final int id) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return null;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Click on a child view with specific id.";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ View v = view.findViewById(id);
+ v.performClick();
+ }
+ };
+ }
+}
diff --git a/car/tests/src/android/support/car/widget/PagedListViewSavedStateActivity.java b/car/tests/src/androidx/car/widget/PagedListViewSavedStateActivity.java
similarity index 93%
rename from car/tests/src/android/support/car/widget/PagedListViewSavedStateActivity.java
rename to car/tests/src/androidx/car/widget/PagedListViewSavedStateActivity.java
index 8cb976c..d9eecd5 100644
--- a/car/tests/src/android/support/car/widget/PagedListViewSavedStateActivity.java
+++ b/car/tests/src/androidx/car/widget/PagedListViewSavedStateActivity.java
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.support.car.widget;
+package androidx.car.widget;
import android.app.Activity;
import android.os.Bundle;
-import android.support.car.test.R;
+
+import androidx.car.test.R;
/**
* Test Activity for testing the saving of state for the {@link PagedListView}. It will inflate
diff --git a/car/tests/src/android/support/car/widget/PagedListViewSavedStateTest.java b/car/tests/src/androidx/car/widget/PagedListViewSavedStateTest.java
similarity index 99%
rename from car/tests/src/android/support/car/widget/PagedListViewSavedStateTest.java
rename to car/tests/src/androidx/car/widget/PagedListViewSavedStateTest.java
index 9b871b3..b134e10 100644
--- a/car/tests/src/android/support/car/widget/PagedListViewSavedStateTest.java
+++ b/car/tests/src/androidx/car/widget/PagedListViewSavedStateTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.car.widget;
+package androidx.car.widget;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
@@ -26,7 +26,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
-import android.support.car.test.R;
import android.support.test.espresso.IdlingRegistry;
import android.support.test.espresso.IdlingResource;
import android.support.test.filters.SmallTest;
@@ -50,6 +49,8 @@
import java.util.List;
import java.util.Random;
+import androidx.car.test.R;
+
/** Unit tests for the ability of the {@link PagedListView} to save state. */
@RunWith(AndroidJUnit4.class)
@SmallTest
diff --git a/car/tests/src/android/support/car/widget/PagedListViewTest.java b/car/tests/src/androidx/car/widget/PagedListViewTest.java
similarity index 91%
rename from car/tests/src/android/support/car/widget/PagedListViewTest.java
rename to car/tests/src/androidx/car/widget/PagedListViewTest.java
index 0d07fbd..c977a6e 100644
--- a/car/tests/src/android/support/car/widget/PagedListViewTest.java
+++ b/car/tests/src/androidx/car/widget/PagedListViewTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.car.widget;
+package androidx.car.widget;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
@@ -35,8 +35,9 @@
import static org.junit.Assert.assertThat;
import android.content.pm.PackageManager;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.support.car.test.R;
+import android.support.test.InstrumentationRegistry;
import android.support.test.annotation.UiThreadTest;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.IdlingResource;
@@ -61,6 +62,8 @@
import java.util.ArrayList;
import java.util.List;
+import androidx.car.test.R;
+
/** Unit tests for {@link PagedListView}. */
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -366,6 +369,43 @@
is(equalTo(downDrawable.getConstantState())));
}
+ @Test
+ public void testSettingAndResettingScrollbarColor() {
+ setUpPagedListView(0);
+
+ final int color = R.color.car_teal_700;
+
+ // Setting non-zero res ID changes color.
+ mPagedListView.setScrollbarColor(color);
+ assertThat(((ColorDrawable)
+ mPagedListView.mScrollBarView.mScrollThumb.getBackground()).getColor(),
+ is(equalTo(InstrumentationRegistry.getContext().getColor(color))));
+
+ // Resets to default color.
+ mPagedListView.resetScrollbarColor();
+ assertThat(((ColorDrawable)
+ mPagedListView.mScrollBarView.mScrollThumb.getBackground()).getColor(),
+ is(equalTo(InstrumentationRegistry.getContext().getColor(
+ R.color.car_scrollbar_thumb))));
+ }
+
+ @Test
+ public void testSettingScrollbarColorIgnoresDayNightStyle() {
+ setUpPagedListView(0);
+
+ final int color = R.color.car_teal_700;
+ mPagedListView.setScrollbarColor(color);
+
+ for (int style : new int[] {DayNightStyle.AUTO, DayNightStyle.AUTO_INVERSE,
+ DayNightStyle.FORCE_NIGHT, DayNightStyle.FORCE_DAY}) {
+ mPagedListView.setDayNightStyle(style);
+
+ assertThat(((ColorDrawable)
+ mPagedListView.mScrollBarView.mScrollThumb.getBackground()).getColor(),
+ is(equalTo(InstrumentationRegistry.getContext().getColor(color))));
+ }
+ }
+
private static String itemText(int index) {
return "Data " + index;
}
diff --git a/car/tests/src/android/support/car/widget/PagedListViewTestActivity.java b/car/tests/src/androidx/car/widget/PagedListViewTestActivity.java
similarity index 93%
rename from car/tests/src/android/support/car/widget/PagedListViewTestActivity.java
rename to car/tests/src/androidx/car/widget/PagedListViewTestActivity.java
index 6371374..741cadd 100644
--- a/car/tests/src/android/support/car/widget/PagedListViewTestActivity.java
+++ b/car/tests/src/androidx/car/widget/PagedListViewTestActivity.java
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.support.car.widget;
+package androidx.car.widget;
import android.app.Activity;
import android.os.Bundle;
-import android.support.car.test.R;
+
+import androidx.car.test.R;
/**
* Simple test activity for {@link PagedListView} class.
diff --git a/compat/api/27.0.0.ignore b/compat/api/27.0.0.ignore
new file mode 100644
index 0000000..b49088f
--- /dev/null
+++ b/compat/api/27.0.0.ignore
@@ -0,0 +1 @@
+8227953
diff --git a/compat/api/current.txt b/compat/api/current.txt
index 5a87c03..66525e2 100644
--- a/compat/api/current.txt
+++ b/compat/api/current.txt
@@ -495,7 +495,7 @@
field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
}
- public final class RemoteInput extends android.support.v4.app.RemoteInputCompatBase.RemoteInput {
+ public final class RemoteInput {
method public static void addDataResultToIntent(android.support.v4.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
method public static void addResultsToIntent(android.support.v4.app.RemoteInput[], android.content.Intent, android.os.Bundle);
method public boolean getAllowFreeFormInput();
@@ -522,19 +522,6 @@
method public android.support.v4.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
}
- deprecated class RemoteInputCompatBase {
- }
-
- public static abstract deprecated class RemoteInputCompatBase.RemoteInput {
- ctor public deprecated RemoteInputCompatBase.RemoteInput();
- method protected abstract deprecated boolean getAllowFreeFormInput();
- method protected abstract deprecated java.util.Set<java.lang.String> getAllowedDataTypes();
- method protected abstract deprecated java.lang.CharSequence[] getChoices();
- method protected abstract deprecated android.os.Bundle getExtras();
- method protected abstract deprecated java.lang.CharSequence getLabel();
- method protected abstract deprecated java.lang.String getResultKey();
- }
-
public final class ServiceCompat {
method public static void stopForeground(android.app.Service, int);
field public static final int START_STICKY = 1; // 0x1
@@ -937,7 +924,7 @@
method public static void requestFont(android.content.Context, android.support.v4.provider.FontRequest, android.support.v4.provider.FontsContractCompat.FontRequestCallback, android.os.Handler);
}
- public static final class FontsContractCompat.Columns {
+ public static final class FontsContractCompat.Columns implements android.provider.BaseColumns {
ctor public FontsContractCompat.Columns();
field public static final java.lang.String FILE_ID = "file_id";
field public static final java.lang.String ITALIC = "font_italic";
@@ -1136,7 +1123,7 @@
method public int size();
}
- public class LongSparseArray<E> {
+ public class LongSparseArray<E> implements java.lang.Cloneable {
ctor public LongSparseArray();
ctor public LongSparseArray(int);
method public void append(long, E);
@@ -1235,7 +1222,7 @@
method public V valueAt(int);
}
- public class SparseArrayCompat<E> {
+ public class SparseArrayCompat<E> implements java.lang.Cloneable {
ctor public SparseArrayCompat();
ctor public SparseArrayCompat(int);
method public void append(int, E);
diff --git a/compat/build.gradle b/compat/build.gradle
index b8ea13b..a26eac8 100644
--- a/compat/build.gradle
+++ b/compat/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,16 +7,16 @@
}
dependencies {
- api project(':support-annotations')
+ api(project(":support-annotations"))
api (libs.arch_lifecycle_runtime) {
exclude module: 'support-annotations'
transitive = true
}
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation project(':support-testutils'), {
exclude group: 'com.android.support', module: 'support-compat'
}
diff --git a/compat/lint-baseline.xml b/compat/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/compat/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/compat/src/main/java/android/support/v4/accessibilityservice/package.html b/compat/src/main/java/android/support/v4/accessibilityservice/package.html
deleted file mode 100755
index 3d017b0..0000000
--- a/compat/src/main/java/android/support/v4/accessibilityservice/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<body>
-
-Support android.accessibilityservice classes to assist with development of applications for
-android API level 4 or later.
-
-</body>
diff --git a/compat/src/main/java/android/support/v4/app/NotificationCompat.java b/compat/src/main/java/android/support/v4/app/NotificationCompat.java
index 1077b1f..80c7757 100644
--- a/compat/src/main/java/android/support/v4/app/NotificationCompat.java
+++ b/compat/src/main/java/android/support/v4/app/NotificationCompat.java
@@ -32,6 +32,7 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
+import android.media.AudioAttributes;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
@@ -116,7 +117,6 @@
* default stream type is {@link AudioManager#STREAM_NOTIFICATION}.
*/
public static final int STREAM_DEFAULT = -1;
-
/**
* Bit set in the Notification flags field when LEDs should be turned on
* for this notification.
@@ -439,6 +439,14 @@
public static final int COLOR_DEFAULT = Color.TRANSPARENT;
/** @hide */
+ @RestrictTo(LIBRARY_GROUP)
+ @IntDef({AudioManager.STREAM_VOICE_CALL, AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING,
+ AudioManager.STREAM_MUSIC, AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
+ AudioManager.STREAM_DTMF, AudioManager.STREAM_ACCESSIBILITY})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StreamType {}
+
+ /** @hide */
@Retention(SOURCE)
@IntDef({VISIBILITY_PUBLIC, VISIBILITY_PRIVATE, VISIBILITY_SECRET})
public @interface NotificationVisibility {}
@@ -957,6 +965,12 @@
public Builder setSound(Uri sound) {
mNotification.sound = sound;
mNotification.audioStreamType = Notification.STREAM_DEFAULT;
+ if (Build.VERSION.SDK_INT >= 21) {
+ mNotification.audioAttributes = new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION)
+ .build();
+ }
return this;
}
@@ -971,9 +985,15 @@
* @see Notification#STREAM_DEFAULT
* @see AudioManager for the <code>STREAM_</code> constants.
*/
- public Builder setSound(Uri sound, int streamType) {
+ public Builder setSound(Uri sound, @StreamType int streamType) {
mNotification.sound = sound;
mNotification.audioStreamType = streamType;
+ if (Build.VERSION.SDK_INT >= 21) {
+ mNotification.audioAttributes = new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setLegacyStreamType(streamType)
+ .build();
+ }
return this;
}
diff --git a/compat/src/main/java/android/support/v4/app/NotificationCompatBuilder.java b/compat/src/main/java/android/support/v4/app/NotificationCompatBuilder.java
index 71f4160..db775a5 100644
--- a/compat/src/main/java/android/support/v4/app/NotificationCompatBuilder.java
+++ b/compat/src/main/java/android/support/v4/app/NotificationCompatBuilder.java
@@ -28,6 +28,7 @@
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RestrictTo;
+import android.text.TextUtils;
import android.util.SparseArray;
import android.widget.RemoteViews;
@@ -69,7 +70,6 @@
.setSmallIcon(n.icon, n.iconLevel)
.setContent(n.contentView)
.setTicker(n.tickerText, b.mTickerView)
- .setSound(n.sound, n.audioStreamType)
.setVibrate(n.vibrate)
.setLights(n.ledARGB, n.ledOnMS, n.ledOffMS)
.setOngoing((n.flags & Notification.FLAG_ONGOING_EVENT) != 0)
@@ -86,6 +86,9 @@
.setLargeIcon(b.mLargeIcon)
.setNumber(b.mNumber)
.setProgress(b.mProgressMax, b.mProgress, b.mProgressIndeterminate);
+ if (Build.VERSION.SDK_INT < 21) {
+ mBuilder.setSound(n.sound, n.audioStreamType);
+ }
if (Build.VERSION.SDK_INT >= 16) {
mBuilder.setSubText(b.mSubText)
.setUsesChronometer(b.mUseChronometer)
@@ -141,7 +144,8 @@
mBuilder.setCategory(b.mCategory)
.setColor(b.mColor)
.setVisibility(b.mVisibility)
- .setPublicVersion(b.mPublicVersion);
+ .setPublicVersion(b.mPublicVersion)
+ .setSound(n.sound, n.audioAttributes);
for (String person: b.mPeople) {
mBuilder.addPerson(person);
@@ -169,6 +173,13 @@
if (b.mColorizedSet) {
mBuilder.setColorized(b.mColorized);
}
+
+ if (!TextUtils.isEmpty(b.mChannelId)) {
+ mBuilder.setSound(null)
+ .setDefaults(0)
+ .setLights(0, 0, 0)
+ .setVibrate(null);
+ }
}
}
diff --git a/compat/src/main/java/android/support/v4/app/NotificationManagerCompat.java b/compat/src/main/java/android/support/v4/app/NotificationManagerCompat.java
index 1a0f1bc..07fcb6c 100644
--- a/compat/src/main/java/android/support/v4/app/NotificationManagerCompat.java
+++ b/compat/src/main/java/android/support/v4/app/NotificationManagerCompat.java
@@ -43,10 +43,10 @@
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -560,7 +560,7 @@
/** The service stub provided by onServiceConnected */
public INotificationSideChannel service;
/** Queue of pending tasks to send to this listener service */
- public LinkedList<Task> taskQueue = new LinkedList<Task>();
+ public ArrayDeque<Task> taskQueue = new ArrayDeque<>();
/** Number of retries attempted while connecting to this listener service */
public int retryCount = 0;
diff --git a/compat/src/main/java/android/support/v4/app/package.html b/compat/src/main/java/android/support/v4/app/package.html
deleted file mode 100755
index 02d1b79..0000000
--- a/compat/src/main/java/android/support/v4/app/package.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<body>
-
-Support android.app classes to assist with development of applications for
-android API level 4 or later. The main features here are backwards-compatible
-versions of {@link android.support.v4.app.FragmentManager} and
-{@link android.support.v4.app.LoaderManager}.
-
-</body>
diff --git a/compat/src/main/java/android/support/v4/content/package.html b/compat/src/main/java/android/support/v4/content/package.html
deleted file mode 100755
index 33bf4b5..0000000
--- a/compat/src/main/java/android/support/v4/content/package.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<body>
-
-Support android.content classes to assist with development of applications for
-android API level 4 or later. The main features here are
-{@link android.support.v4.content.Loader} and related classes and
-{@link android.support.v4.content.LocalBroadcastManager} to
-provide a cleaner implementation of broadcasts that don't need to go outside
-of an app.
-
-</body>
diff --git a/compat/src/main/java/android/support/v4/content/pm/package.html b/compat/src/main/java/android/support/v4/content/pm/package.html
deleted file mode 100755
index da850bd..0000000
--- a/compat/src/main/java/android/support/v4/content/pm/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<body>
-
-Support android.content.pm classes to assist with development of applications for
-android API level 4 or later.
-
-</body>
diff --git a/compat/src/main/java/android/support/v4/database/package.html b/compat/src/main/java/android/support/v4/database/package.html
deleted file mode 100755
index 25ac59a..0000000
--- a/compat/src/main/java/android/support/v4/database/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<body>
-
-Support android.database classes to assist with development of applications for
-android API level 4 or later.
-
-</body>
diff --git a/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi26Impl.java b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi26Impl.java
index 1b55a2e..28ab3ed 100644
--- a/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi26Impl.java
+++ b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi26Impl.java
@@ -196,10 +196,9 @@
/**
* Call FontFamily#abortCreation()
*/
- private static boolean abortCreation(Object family) {
+ private static void abortCreation(Object family) {
try {
- Boolean result = (Boolean) sAbortCreation.invoke(family);
- return result.booleanValue();
+ sAbortCreation.invoke(family);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
@@ -241,6 +240,9 @@
final ContentResolver resolver = context.getContentResolver();
try (ParcelFileDescriptor pfd =
resolver.openFileDescriptor(bestFont.getUri(), "r", cancellationSignal)) {
+ if (pfd == null) {
+ return null;
+ }
return new Typeface.Builder(pfd.getFileDescriptor())
.setWeight(bestFont.getWeight())
.setItalic(bestFont.isItalic())
diff --git a/compat/src/main/java/android/support/v4/os/package.html b/compat/src/main/java/android/support/v4/os/package.html
deleted file mode 100755
index 929c967..0000000
--- a/compat/src/main/java/android/support/v4/os/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<body>
-
-Support android.os classes to assist with development of applications for
-android API level 4 or later.
-
-</body>
diff --git a/compat/src/main/java/android/support/v4/provider/FontsContractCompat.java b/compat/src/main/java/android/support/v4/provider/FontsContractCompat.java
index 0926186..39acf68 100644
--- a/compat/src/main/java/android/support/v4/provider/FontsContractCompat.java
+++ b/compat/src/main/java/android/support/v4/provider/FontsContractCompat.java
@@ -274,7 +274,10 @@
: new ReplyCallback<TypefaceResult>() {
@Override
public void onReply(final TypefaceResult typeface) {
- if (typeface.mResult == FontFamilyResult.STATUS_OK) {
+ if (typeface == null) {
+ fontCallback.callbackFailAsync(
+ FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND, handler);
+ } else if (typeface.mResult == FontFamilyResult.STATUS_OK) {
fontCallback.callbackSuccessAsync(typeface.mTypeface, handler);
} else {
fontCallback.callbackFailAsync(typeface.mResult, handler);
diff --git a/compat/src/main/java/android/support/v4/util/ArraySet.java b/compat/src/main/java/android/support/v4/util/ArraySet.java
index ab080fa..a9a8806 100644
--- a/compat/src/main/java/android/support/v4/util/ArraySet.java
+++ b/compat/src/main/java/android/support/v4/util/ArraySet.java
@@ -16,9 +16,6 @@
package android.support.v4.util;
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.support.annotation.RestrictTo;
import android.util.Log;
import java.lang.reflect.Array;
@@ -74,7 +71,6 @@
static Object[] sTwiceBaseCache;
static int sTwiceBaseCacheSize;
- final boolean mIdentityHashCode;
int[] mHashes;
Object[] mArray;
int mSize;
@@ -238,19 +234,13 @@
* will grow once items are added to it.
*/
public ArraySet() {
- this(0, false);
+ this(0);
}
/**
* Create a new ArraySet with a given initial capacity.
*/
public ArraySet(int capacity) {
- this(capacity, false);
- }
-
- /** {@hide} */
- public ArraySet(int capacity, boolean identityHashCode) {
- mIdentityHashCode = identityHashCode;
if (capacity == 0) {
mHashes = INT;
mArray = OBJECT;
@@ -270,14 +260,6 @@
}
}
- /** {@hide} */
- public ArraySet(Collection<E> set) {
- this();
- if (set != null) {
- addAll(set);
- }
- }
-
/**
* Make the array map empty. All storage is released.
*/
@@ -326,8 +308,7 @@
* @return Returns the index of the value if it exists, else a negative integer.
*/
public int indexOf(Object key) {
- return key == null ? indexOfNull()
- : indexOf(key, mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());
+ return key == null ? indexOfNull() : indexOf(key, key.hashCode());
}
/**
@@ -364,7 +345,7 @@
hash = 0;
index = indexOfNull();
} else {
- hash = mIdentityHashCode ? System.identityHashCode(value) : value.hashCode();
+ hash = value.hashCode();
index = indexOf(value, hash);
}
if (index >= 0) {
@@ -406,36 +387,6 @@
}
/**
- * Special fast path for appending items to the end of the array without validation.
- * The array must already be large enough to contain the item.
- * @hide
- */
- @RestrictTo(LIBRARY_GROUP)
- public void append(E value) {
- final int index = mSize;
- final int hash = value == null ? 0
- : (mIdentityHashCode ? System.identityHashCode(value) : value.hashCode());
- if (index >= mHashes.length) {
- throw new IllegalStateException("Array is full");
- }
- if (index > 0 && mHashes[index - 1] > hash) {
- // Cannot optimize since it would break the sorted order - fallback to add()
- if (DEBUG) {
- RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
- Log.w(TAG, "New hash " + hash
- + " is before end of array hash " + mHashes[index - 1]
- + " at index " + index, e);
- }
- add(value);
- return;
- }
- mSize = index + 1;
- mHashes[index] = hash;
- mArray[index] = value;
- }
-
- /**
* Perform a {@link #add(Object)} of all values in <var>array</var>
* @param array The array whose contents are to be retrieved.
*/
diff --git a/compat/src/main/java/android/support/v4/util/package.html b/compat/src/main/java/android/support/v4/util/package.html
deleted file mode 100644
index afde9b7..0000000
--- a/compat/src/main/java/android/support/v4/util/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<body>
-
-Support android.util classes to assist with development of applications for
-android API level 4 or later.
-
-</body>
diff --git a/compat/src/main/java/android/support/v4/view/accessibility/package.html b/compat/src/main/java/android/support/v4/view/accessibility/package.html
deleted file mode 100755
index 57b084f..0000000
--- a/compat/src/main/java/android/support/v4/view/accessibility/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<body>
-
-Support classes to access some of the android.view.accessibility package features introduced after API level 4 in a backwards compatible fashion.
-
-</body>
diff --git a/compat/src/main/java/android/support/v4/view/package.html b/compat/src/main/java/android/support/v4/view/package.html
deleted file mode 100755
index d80ef70..0000000
--- a/compat/src/main/java/android/support/v4/view/package.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<body>
-
-Support android.util classes to assist with development of applications for
-android API level 4 or later. The main features here are a variety of classes
-for handling backwards compatibility with views (for example
-{@link android.support.v4.view.MotionEventCompat} allows retrieving multi-touch
-data if available), and a new
-{@link android.support.v4.view.ViewPager} widget (which at some point should be moved over
-to the widget package).
-
-</body>
diff --git a/compat/src/main/java/android/support/v4/widget/package.html b/compat/src/main/java/android/support/v4/widget/package.html
deleted file mode 100755
index e2c636d..0000000
--- a/compat/src/main/java/android/support/v4/widget/package.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<body>
-
-Support android.widget classes to assist with development of applications for
-android API level 4 or later. This includes a complete modern implementation
-of {@link android.support.v4.widget.CursorAdapter} and related classes, which
-is needed for use with {@link android.support.v4.content.CursorLoader}.
-
-</body>
diff --git a/compat/tests/java/android/support/v4/app/NotificationCompatTest.java b/compat/tests/java/android/support/v4/app/NotificationCompatTest.java
index dd870dd..7a5a57f 100644
--- a/compat/tests/java/android/support/v4/app/NotificationCompatTest.java
+++ b/compat/tests/java/android/support/v4/app/NotificationCompatTest.java
@@ -34,6 +34,9 @@
import android.annotation.TargetApi;
import android.app.Notification;
import android.content.Context;
+import android.graphics.Color;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -424,6 +427,71 @@
}
}
+ @Test
+ @SdkSuppress(minSdkVersion = 21)
+ public void testHasAudioAttributesFrom21() throws Throwable {
+ Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+ .setSound(Uri.EMPTY)
+ .build();
+ assertNotNull(n.audioAttributes);
+ assertEquals(-1, n.audioStreamType);
+ assertEquals(Uri.EMPTY, n.sound);
+
+ n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+ .setSound(Uri.EMPTY, AudioManager.STREAM_RING)
+ .build();
+ assertNotNull(n.audioAttributes);
+ assertEquals(AudioAttributes.CONTENT_TYPE_SONIFICATION,
+ n.audioAttributes.getContentType());
+ assertEquals(-1, n.audioStreamType);
+ assertEquals(Uri.EMPTY, n.sound);
+ }
+
+ @Test
+ @SdkSuppress(maxSdkVersion = 20)
+ public void testHasStreamTypePre21() throws Throwable {
+ Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+ .setSound(Uri.EMPTY, 34)
+ .build();
+ assertEquals(34, n.audioStreamType);
+ assertEquals(Uri.EMPTY, n.sound);
+ }
+
+ @SdkSuppress(minSdkVersion = 26)
+ @Test
+ public void testClearAlertingFieldsIfUsingChannels() throws Throwable {
+ long[] vibration = new long[]{100};
+
+ // stripped if using channels
+ Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity(), "test")
+ .setSound(Uri.EMPTY)
+ .setDefaults(Notification.DEFAULT_ALL)
+ .setVibrate(vibration)
+ .setLights(Color.BLUE, 100, 100)
+ .build();
+ assertNull(n.sound);
+ assertEquals(0, n.defaults);
+ assertNull(n.vibrate);
+ assertEquals(0, n.ledARGB);
+ assertEquals(0, n.ledOnMS);
+ assertEquals(0, n.ledOffMS);
+
+ // left intact if not using channels
+ n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+ .setSound(Uri.EMPTY)
+ .setDefaults(Notification.DEFAULT_ALL)
+ .setVibrate(vibration)
+ .setLights(Color.BLUE, 100, 100)
+ .build();
+ assertEquals(Uri.EMPTY, n.sound);
+ assertNotNull(n.audioAttributes);
+ assertEquals(Notification.DEFAULT_ALL, n.defaults);
+ assertEquals(vibration, n.vibrate);
+ assertEquals(Color.BLUE, n.ledARGB);
+ assertEquals(100, n.ledOnMS);
+ assertEquals(100, n.ledOffMS);
+ }
+
private static RemoteInput newDataOnlyRemoteInput() {
return new RemoteInput.Builder(DATA_RESULT_KEY)
.setAllowFreeFormInput(false)
diff --git a/compat/tests/java/android/support/v4/provider/FontsContractCompatTest.java b/compat/tests/java/android/support/v4/provider/FontsContractCompatTest.java
index 66bdd50..4edab02 100644
--- a/compat/tests/java/android/support/v4/provider/FontsContractCompatTest.java
+++ b/compat/tests/java/android/support/v4/provider/FontsContractCompatTest.java
@@ -40,9 +40,11 @@
import android.content.pm.ProviderInfo;
import android.content.pm.Signature;
import android.graphics.Typeface;
+import android.support.annotation.NonNull;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.provider.FontsContractCompat.FontFamilyResult;
import android.support.v4.provider.FontsContractCompat.FontInfo;
import android.util.Base64;
@@ -56,6 +58,8 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Unit tests for {@link FontsContractCompat}.
@@ -111,34 +115,6 @@
InstrumentationRegistry.getInstrumentation().getTargetContext());
}
- private static class TestCallback extends FontsContractCompat.FontRequestCallback {
- private Typeface mTypeface;
-
- private int mSuccessCallCount;
- private int mFailedCallCount;
-
- public void onTypefaceRetrieved(Typeface typeface) {
- mTypeface = typeface;
- mSuccessCallCount++;
- }
-
- public void onTypefaceRequestFailed(int reason) {
- mFailedCallCount++;
- }
-
- public Typeface getTypeface() {
- return mTypeface;
- }
-
- public int getSuccessCallCount() {
- return mSuccessCallCount;
- }
-
- public int getFailedCallCount() {
- return mFailedCallCount;
- }
- }
-
@Test
public void typefaceNotCacheTest() throws NameNotFoundException {
FontRequest request = new FontRequest(
@@ -413,4 +389,43 @@
when(packageManager.getPackageInfo(anyString(), anyInt())).thenReturn(packageInfo);
return info;
}
+
+ @Test
+ public void testGetFontSync_invalidUri() throws InterruptedException {
+ final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+ final FontRequest request = new FontRequest(
+ AUTHORITY, PACKAGE, MockFontProvider.INVALID_URI, SIGNATURE);
+ final CountDownLatch latch = new CountDownLatch(1);
+ final FontCallback callback = new FontCallback(latch);
+
+ inst.runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ FontsContractCompat.getFontSync(mContext, request, callback, null,
+ false /* isBlockingFetch */, 300 /* timeout */, Typeface.NORMAL);
+ }
+ });
+ assertTrue(latch.await(5L, TimeUnit.SECONDS));
+ assertNull(callback.mTypeface);
+ }
+
+ public static class FontCallback extends ResourcesCompat.FontCallback {
+ private final CountDownLatch mLatch;
+ Typeface mTypeface;
+
+ FontCallback(CountDownLatch latch) {
+ mLatch = latch;
+ }
+
+ @Override
+ public void onFontRetrieved(@NonNull Typeface typeface) {
+ mTypeface = typeface;
+ mLatch.countDown();
+ }
+
+ @Override
+ public void onFontRetrievalFailed(int reason) {
+ mLatch.countDown();
+ }
+ }
}
diff --git a/compat/tests/java/android/support/v4/provider/MockFontProvider.java b/compat/tests/java/android/support/v4/provider/MockFontProvider.java
index f07d92d..f584d68 100644
--- a/compat/tests/java/android/support/v4/provider/MockFontProvider.java
+++ b/compat/tests/java/android/support/v4/provider/MockFontProvider.java
@@ -43,6 +43,7 @@
static final String[] FONT_FILES = {
"samplefont.ttf", "large_a.ttf", "large_b.ttf", "large_c.ttf", "large_d.ttf"
};
+ private static final int INVALID_FONT_FILE_ID = -1;
private static final int SAMPLE_FONT_FILE_0_ID = 0;
private static final int LARGE_A_FILE_ID = 1;
private static final int LARGE_B_FILE_ID = 2;
@@ -59,6 +60,7 @@
static final String NEGATIVE_ERROR_CODE_QUERY = "negativeCode";
static final String MANDATORY_FIELDS_ONLY_QUERY = "mandatoryFields";
static final String STYLE_TEST_QUERY = "styleTest";
+ static final String INVALID_URI = "invalidURI";
static class Font {
Font(int id, int fileId, int ttcIndex, String varSettings, int weight, int italic,
@@ -176,6 +178,11 @@
Columns.RESULT_CODE_OK, true),
});
+ map.put(INVALID_URI, new Font[] {
+ new Font(id++, INVALID_FONT_FILE_ID, 0, null, 400, 0,
+ Columns.RESULT_CODE_OK, true),
+ });
+
QUERY_MAP = Collections.unmodifiableMap(map);
}
@@ -260,6 +267,9 @@
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) {
final int id = (int) ContentUris.parseId(uri);
+ if (id < 0) {
+ return null;
+ }
final File targetFile = getCopiedFile(getContext(), FONT_FILES[id]);
try {
return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY);
diff --git a/content/build.gradle b/content/build.gradle
index 3639301..9091053 100644
--- a/content/build.gradle
+++ b/content/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -22,12 +23,12 @@
}
dependencies {
- api project(':support-annotations')
- api project(':support-compat')
+ api(project(":support-annotations"))
+ api(project(":support-compat"))
- androidTestImplementation libs.junit
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
+ androidTestImplementation(JUNIT)
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
}
android {
diff --git a/content/lint-baseline.xml b/content/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/content/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/core-ui/api/27.0.0.ignore b/core-ui/api/27.0.0.ignore
new file mode 100644
index 0000000..8dbf04a
--- /dev/null
+++ b/core-ui/api/27.0.0.ignore
@@ -0,0 +1,9 @@
+46690b4
+1670c35
+cde6951
+21047f0
+1416521
+4f63fb9
+2337166
+9e34008
+7546756
diff --git a/core-ui/api/current.txt b/core-ui/api/current.txt
index 346ffc4..77e805d 100644
--- a/core-ui/api/current.txt
+++ b/core-ui/api/current.txt
@@ -1,6 +1,6 @@
package android.support.design.widget {
- public class CoordinatorLayout extends android.view.ViewGroup {
+ public class CoordinatorLayout extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingParent2 {
ctor public CoordinatorLayout(android.content.Context);
ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet);
ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet, int);
@@ -16,7 +16,6 @@
method public void onAttachedToWindow();
method public void onDetachedFromWindow();
method public void onDraw(android.graphics.Canvas);
- method protected void onLayout(boolean, int, int, int, int);
method public void onLayoutChild(android.view.View, int);
method public void onMeasureChild(android.view.View, int, int, int, int);
method public void onNestedPreScroll(android.view.View, int, int, int[], int);
@@ -214,7 +213,6 @@
ctor public PagerTitleStrip(android.content.Context);
ctor public PagerTitleStrip(android.content.Context, android.util.AttributeSet);
method public int getTextSpacing();
- method protected void onLayout(boolean, int, int, int, int);
method public void setGravity(int);
method public void setNonPrimaryAlpha(float);
method public void setTextColor(int);
@@ -239,7 +237,6 @@
method public int getOffscreenPageLimit();
method public int getPageMargin();
method public boolean isFakeDragging();
- method protected void onLayout(boolean, int, int, int, int);
method protected void onPageScrolled(int, float, int);
method public void onRestoreInstanceState(android.os.Parcelable);
method public android.os.Parcelable onSaveInstanceState();
@@ -300,23 +297,18 @@
package android.support.v4.view.animation {
- public class FastOutLinearInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+ public class FastOutLinearInInterpolator implements android.view.animation.Interpolator {
ctor public FastOutLinearInInterpolator();
}
- public class FastOutSlowInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+ public class FastOutSlowInInterpolator implements android.view.animation.Interpolator {
ctor public FastOutSlowInInterpolator();
}
- public class LinearOutSlowInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+ public class LinearOutSlowInInterpolator implements android.view.animation.Interpolator {
ctor public LinearOutSlowInInterpolator();
}
- abstract class LookupTableInterpolator implements android.view.animation.Interpolator {
- ctor public LookupTableInterpolator(float[]);
- method public float getInterpolation(float);
- }
-
}
package android.support.v4.widget {
@@ -348,7 +340,7 @@
field public static final float RELATIVE_UNSPECIFIED = 0.0f;
}
- public class CircularProgressDrawable extends android.graphics.drawable.Drawable {
+ public class CircularProgressDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable {
ctor public CircularProgressDrawable(android.content.Context);
method public void draw(android.graphics.Canvas);
method public boolean getArrowEnabled();
@@ -393,7 +385,7 @@
method public void show();
}
- public abstract class CursorAdapter extends android.widget.BaseAdapter {
+ public abstract class CursorAdapter extends android.widget.BaseAdapter implements android.widget.Filterable {
ctor public deprecated CursorAdapter(android.content.Context, android.database.Cursor);
ctor public CursorAdapter(android.content.Context, android.database.Cursor, boolean);
ctor public CursorAdapter(android.content.Context, android.database.Cursor, int);
@@ -438,7 +430,6 @@
method public boolean isDrawerVisible(android.view.View);
method public boolean isDrawerVisible(int);
method public void onDraw(android.graphics.Canvas);
- method protected void onLayout(boolean, int, int, int, int);
method public void openDrawer(android.view.View);
method public void openDrawer(android.view.View, boolean);
method public void openDrawer(int);
@@ -529,12 +520,18 @@
method public void scrollTargetBy(int, int);
}
- public class NestedScrollView extends android.widget.FrameLayout {
+ public class NestedScrollView extends android.widget.FrameLayout implements android.support.v4.view.NestedScrollingChild2 android.support.v4.view.NestedScrollingParent android.support.v4.view.ScrollingView {
ctor public NestedScrollView(android.content.Context);
ctor public NestedScrollView(android.content.Context, android.util.AttributeSet);
ctor public NestedScrollView(android.content.Context, android.util.AttributeSet, int);
method public boolean arrowScroll(int);
+ method public int computeHorizontalScrollExtent();
+ method public int computeHorizontalScrollOffset();
+ method public int computeHorizontalScrollRange();
method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect);
+ method public int computeVerticalScrollExtent();
+ method public int computeVerticalScrollOffset();
+ method public int computeVerticalScrollRange();
method public boolean dispatchNestedPreScroll(int, int, int[], int[], int);
method public boolean dispatchNestedScroll(int, int, int, int, int[], int);
method public boolean executeKeyEvent(android.view.KeyEvent);
@@ -603,7 +600,6 @@
method public int getSliderFadeColor();
method public boolean isOpen();
method public boolean isSlideable();
- method protected void onLayout(boolean, int, int, int, int);
method public boolean openPane();
method public void setCoveredFadeColor(int);
method public void setPanelSlideListener(android.support.v4.widget.SlidingPaneLayout.PanelSlideListener);
@@ -648,7 +644,7 @@
ctor public Space(android.content.Context);
}
- public class SwipeRefreshLayout extends android.view.ViewGroup {
+ public class SwipeRefreshLayout extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent {
ctor public SwipeRefreshLayout(android.content.Context);
ctor public SwipeRefreshLayout(android.content.Context, android.util.AttributeSet);
method public boolean canChildScrollUp();
@@ -656,7 +652,6 @@
method public int getProgressViewEndOffset();
method public int getProgressViewStartOffset();
method public boolean isRefreshing();
- method protected void onLayout(boolean, int, int, int, int);
method public void onMeasure(int, int);
method public deprecated void setColorScheme(int...);
method public void setColorSchemeColors(int...);
diff --git a/core-ui/build.gradle b/core-ui/build.gradle
index 098440d..f7cd2d7 100644
--- a/core-ui/build.gradle
+++ b/core-ui/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,20 +7,19 @@
}
dependencies {
- api project(':support-annotations')
- api project(':support-compat')
+ api(project(":support-annotations"))
+ api(project(":support-compat"))
api project(':support-core-utils')
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_contrib, { exclude group: 'com.android.support' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(ESPRESSO_CONTRIB, libs.exclude_support)
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation project(':support-testutils'), {
exclude group: 'com.android.support', module: 'support-core-ui'
}
- testImplementation libs.junit
+ testImplementation(JUNIT)
}
android {
diff --git a/core-ui/src/main/java/android/support/design/widget/CoordinatorLayout.java b/core-ui/src/main/java/android/support/design/widget/CoordinatorLayout.java
index c45810e..03cce02 100644
--- a/core-ui/src/main/java/android/support/design/widget/CoordinatorLayout.java
+++ b/core-ui/src/main/java/android/support/design/widget/CoordinatorLayout.java
@@ -400,6 +400,7 @@
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
lp.resetTouchBehaviorTracking();
}
+ mBehaviorTouchView = null;
mDisallowInterceptReset = false;
}
diff --git a/core-ui/src/main/java/android/support/v4/app/package.html b/core-ui/src/main/java/android/support/v4/app/package.html
deleted file mode 100755
index 02d1b79..0000000
--- a/core-ui/src/main/java/android/support/v4/app/package.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<body>
-
-Support android.app classes to assist with development of applications for
-android API level 4 or later. The main features here are backwards-compatible
-versions of {@link android.support.v4.app.FragmentManager} and
-{@link android.support.v4.app.LoaderManager}.
-
-</body>
diff --git a/core-ui/src/main/java/android/support/v4/view/PagerAdapter.java b/core-ui/src/main/java/android/support/v4/view/PagerAdapter.java
index a8fb099..af8e076 100644
--- a/core-ui/src/main/java/android/support/v4/view/PagerAdapter.java
+++ b/core-ui/src/main/java/android/support/v4/view/PagerAdapter.java
@@ -131,6 +131,7 @@
/**
* Called to inform the adapter of which item is currently considered to
* be the "primary", that is the one show to the user as the current page.
+ * This method will not be invoked when the adapter contains no items.
*
* @param container The containing View from which the page will be removed.
* @param position The page position that is now the primary.
diff --git a/core-ui/src/main/java/android/support/v4/view/ViewPager.java b/core-ui/src/main/java/android/support/v4/view/ViewPager.java
index 36d8696..350fe95 100644
--- a/core-ui/src/main/java/android/support/v4/view/ViewPager.java
+++ b/core-ui/src/main/java/android/support/v4/view/ViewPager.java
@@ -1224,6 +1224,8 @@
}
calculatePageOffsets(curItem, curIndex, oldCurInfo);
+
+ mAdapter.setPrimaryItem(this, mCurItem, curItem.object);
}
if (DEBUG) {
@@ -1233,8 +1235,6 @@
}
}
- mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null);
-
mAdapter.finishUpdate(this);
// Check width measurement of current pages and drawing sort order.
diff --git a/core-ui/src/main/java/android/support/v4/view/package.html b/core-ui/src/main/java/android/support/v4/view/package.html
deleted file mode 100755
index d80ef70..0000000
--- a/core-ui/src/main/java/android/support/v4/view/package.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<body>
-
-Support android.util classes to assist with development of applications for
-android API level 4 or later. The main features here are a variety of classes
-for handling backwards compatibility with views (for example
-{@link android.support.v4.view.MotionEventCompat} allows retrieving multi-touch
-data if available), and a new
-{@link android.support.v4.view.ViewPager} widget (which at some point should be moved over
-to the widget package).
-
-</body>
diff --git a/core-ui/src/main/java/android/support/v4/widget/NestedScrollView.java b/core-ui/src/main/java/android/support/v4/widget/NestedScrollView.java
index 73ff084..6fe1928 100644
--- a/core-ui/src/main/java/android/support/v4/widget/NestedScrollView.java
+++ b/core-ui/src/main/java/android/support/v4/widget/NestedScrollView.java
@@ -23,6 +23,7 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -1820,10 +1821,20 @@
final int scrollY = getScrollY();
if (!mEdgeGlowTop.isFinished()) {
final int restoreCount = canvas.save();
- final int width = getWidth() - getPaddingLeft() - getPaddingRight();
-
- canvas.translate(getPaddingLeft(), Math.min(0, scrollY));
- mEdgeGlowTop.setSize(width, getHeight());
+ int width = getWidth();
+ int height = getHeight();
+ int xTranslation = 0;
+ int yTranslation = Math.min(0, scrollY);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || getClipToPadding()) {
+ width -= getPaddingLeft() + getPaddingRight();
+ xTranslation += getPaddingLeft();
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && getClipToPadding()) {
+ height -= getPaddingTop() + getPaddingBottom();
+ yTranslation += getPaddingTop();
+ }
+ canvas.translate(xTranslation, yTranslation);
+ mEdgeGlowTop.setSize(width, height);
if (mEdgeGlowTop.draw(canvas)) {
ViewCompat.postInvalidateOnAnimation(this);
}
@@ -1831,11 +1842,19 @@
}
if (!mEdgeGlowBottom.isFinished()) {
final int restoreCount = canvas.save();
- final int width = getWidth() - getPaddingLeft() - getPaddingRight();
- final int height = getHeight();
-
- canvas.translate(-width + getPaddingLeft(),
- Math.max(getScrollRange(), scrollY) + height);
+ int width = getWidth();
+ int height = getHeight();
+ int xTranslation = 0;
+ int yTranslation = Math.max(getScrollRange(), scrollY) + height;
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || getClipToPadding()) {
+ width -= getPaddingLeft() + getPaddingRight();
+ xTranslation += getPaddingLeft();
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && getClipToPadding()) {
+ height -= getPaddingTop() + getPaddingBottom();
+ yTranslation -= getPaddingBottom();
+ }
+ canvas.translate(xTranslation - width, yTranslation);
canvas.rotate(180, width, 0);
mEdgeGlowBottom.setSize(width, height);
if (mEdgeGlowBottom.draw(canvas)) {
diff --git a/core-ui/src/main/java/android/support/v4/widget/package.html b/core-ui/src/main/java/android/support/v4/widget/package.html
deleted file mode 100755
index e2c636d..0000000
--- a/core-ui/src/main/java/android/support/v4/widget/package.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<body>
-
-Support android.widget classes to assist with development of applications for
-android API level 4 or later. This includes a complete modern implementation
-of {@link android.support.v4.widget.CursorAdapter} and related classes, which
-is needed for use with {@link android.support.v4.content.CursorLoader}.
-
-</body>
diff --git a/core-ui/tests/AndroidManifest.xml b/core-ui/tests/AndroidManifest.xml
index c1b1a75..904111e 100644
--- a/core-ui/tests/AndroidManifest.xml
+++ b/core-ui/tests/AndroidManifest.xml
@@ -36,6 +36,10 @@
<activity android:name="android.support.v4.view.ViewPagerWithTabStripActivity"/>
+ <activity android:name="android.support.v4.view.ViewPagerTest$ViewPagerActivity"/>
+
+ <activity android:name="android.support.design.widget.CoordinatorLayoutActivity"/>
+
</application>
</manifest>
diff --git a/design/tests/src/android/support/design/testutils/CoordinatorLayoutUtils.java b/core-ui/tests/java/android/support/design/testutils/CoordinatorLayoutUtils.java
similarity index 100%
rename from design/tests/src/android/support/design/testutils/CoordinatorLayoutUtils.java
rename to core-ui/tests/java/android/support/design/testutils/CoordinatorLayoutUtils.java
diff --git a/core-ui/tests/java/android/support/design/widget/CoordinatorLayoutActivity.java b/core-ui/tests/java/android/support/design/widget/CoordinatorLayoutActivity.java
new file mode 100644
index 0000000..b7fe740
--- /dev/null
+++ b/core-ui/tests/java/android/support/design/widget/CoordinatorLayoutActivity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 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 android.support.design.widget;
+
+import android.support.coreui.test.R;
+import android.support.v4.BaseTestActivity;
+import android.widget.FrameLayout;
+
+public class CoordinatorLayoutActivity extends BaseTestActivity {
+
+ FrameLayout mContainer;
+ CoordinatorLayout mCoordinatorLayout;
+
+ @Override
+ protected int getContentViewLayoutResId() {
+ return R.layout.activity_coordinator_layout;
+ }
+
+ @Override
+ protected void onContentViewSet() {
+ mContainer = findViewById(R.id.container);
+ mCoordinatorLayout = findViewById(R.id.coordinator);
+ }
+
+}
diff --git a/design/tests/src/android/support/design/widget/CoordinatorLayoutSortTest.java b/core-ui/tests/java/android/support/design/widget/CoordinatorLayoutSortTest.java
similarity index 91%
rename from design/tests/src/android/support/design/widget/CoordinatorLayoutSortTest.java
rename to core-ui/tests/java/android/support/design/widget/CoordinatorLayoutSortTest.java
index 0a407b7..4e0ccfc 100644
--- a/design/tests/src/android/support/design/widget/CoordinatorLayoutSortTest.java
+++ b/core-ui/tests/java/android/support/design/widget/CoordinatorLayoutSortTest.java
@@ -22,8 +22,10 @@
import android.support.design.testutils.CoordinatorLayoutUtils;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
import android.view.View;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -35,8 +37,9 @@
@RunWith(Parameterized.class)
@MediumTest
-public class CoordinatorLayoutSortTest
- extends BaseInstrumentationTestCase<CoordinatorLayoutActivity> {
+public class CoordinatorLayoutSortTest {
+ @Rule
+ public final ActivityTestRule<CoordinatorLayoutActivity> mActivityTestRule;
private static final int NUMBER_VIEWS_DEPENDENCY_SORT = 4;
@@ -60,7 +63,7 @@
public CoordinatorLayoutSortTest(int firstIndex, int secondIndex, int thirdIndex,
int fourthIndex) {
- super(CoordinatorLayoutActivity.class);
+ mActivityTestRule = new ActivityTestRule<>(CoordinatorLayoutActivity.class);
mFirstAddIndex = firstIndex;
mSecondAddIndex = secondIndex;
mThirdAddIndex = thirdIndex;
@@ -86,8 +89,8 @@
// Create a Behavior which depends on the previously added view
View dependency = i > 0 ? views.get(i - 1) : null;
- final CoordinatorLayout.Behavior<View> behavior
- = new CoordinatorLayoutUtils.DependentBehavior(dependency);
+ final CoordinatorLayout.Behavior<View> behavior =
+ new CoordinatorLayoutUtils.DependentBehavior(dependency);
// And set its LayoutParams to use the Behavior
CoordinatorLayout.LayoutParams lp = col.generateDefaultLayoutParams();
diff --git a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java b/core-ui/tests/java/android/support/design/widget/CoordinatorLayoutTest.java
similarity index 97%
rename from design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
rename to core-ui/tests/java/android/support/design/widget/CoordinatorLayoutTest.java
index 3588043..4062efb 100644
--- a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
+++ b/core-ui/tests/java/android/support/design/widget/CoordinatorLayoutTest.java
@@ -42,13 +42,15 @@
import android.content.Context;
import android.graphics.Rect;
import android.support.annotation.NonNull;
-import android.support.design.test.R;
+import android.support.coreui.test.R;
import android.support.design.testutils.CoordinatorLayoutUtils;
import android.support.design.testutils.CoordinatorLayoutUtils.DependentBehavior;
import android.support.design.widget.CoordinatorLayout.Behavior;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.MediumTest;
import android.support.test.filters.SdkSuppress;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.WindowInsetsCompat;
@@ -59,19 +61,24 @@
import android.widget.ImageView;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@MediumTest
-public class CoordinatorLayoutTest extends BaseInstrumentationTestCase<CoordinatorLayoutActivity> {
+@RunWith(AndroidJUnit4.class)
+public class CoordinatorLayoutTest {
+ @Rule
+ public final ActivityTestRule<CoordinatorLayoutActivity> mActivityTestRule;
private Instrumentation mInstrumentation;
public CoordinatorLayoutTest() {
- super(CoordinatorLayoutActivity.class);
+ mActivityTestRule = new ActivityTestRule<>(CoordinatorLayoutActivity.class);
}
@Before
@@ -383,14 +390,14 @@
final View viewA = new View(col.getContext());
final View viewB = new View(col.getContext());
final CoordinatorLayout.LayoutParams lpB = col.generateDefaultLayoutParams();
- final CoordinatorLayout.Behavior behavior
- = new CoordinatorLayoutUtils.DependentBehavior(viewA) {
- @Override
- public void onDependentViewRemoved(CoordinatorLayout parent, View child,
- View dependency) {
- parent.getDependencies(child);
- }
- };
+ final CoordinatorLayout.Behavior behavior =
+ new CoordinatorLayoutUtils.DependentBehavior(viewA) {
+ @Override
+ public void onDependentViewRemoved(
+ CoordinatorLayout parent, View child, View dependency) {
+ parent.getDependencies(child);
+ }
+ };
lpB.setBehavior(behavior);
// Now add views
diff --git a/core-ui/tests/java/android/support/v4/view/ViewPagerTest.java b/core-ui/tests/java/android/support/v4/view/ViewPagerTest.java
new file mode 100644
index 0000000..070a052
--- /dev/null
+++ b/core-ui/tests/java/android/support/v4/view/ViewPagerTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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 android.support.v4.view;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+@MediumTest
+public final class ViewPagerTest {
+ @Rule
+ public final ActivityTestRule<ViewPagerActivity> activityRule = new ActivityTestRule<>(
+ ViewPagerActivity.class);
+
+ public static final class ViewPagerActivity extends Activity {
+ public ViewPager pager;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ pager = new ViewPager(this);
+ setContentView(pager);
+ }
+ }
+
+ @Test
+ public void setPrimaryItemNotCalledWhenAdapterIsEmpty() {
+ ViewPager pager = activityRule.getActivity().pager;
+ final PrimaryItemPagerAdapter adapter = new PrimaryItemPagerAdapter();
+ pager.setAdapter(adapter);
+
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ assertFalse(adapter.primaryCalled);
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ adapter.count = 1;
+ adapter.notifyDataSetChanged();
+ }
+ });
+
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ assertTrue(adapter.primaryCalled);
+ }
+
+ static final class PrimaryItemPagerAdapter extends PagerAdapter {
+ public volatile int count;
+ public volatile boolean primaryCalled;
+
+ @Override
+ public int getCount() {
+ return count;
+ }
+
+ @Override
+ public void setPrimaryItem(@NonNull ViewGroup container, int position,
+ @NonNull Object object) {
+ primaryCalled = true;
+ }
+
+ @Override
+ public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
+ return view == object;
+ }
+
+ @NonNull
+ @Override
+ public Object instantiateItem(@NonNull ViewGroup container, int position) {
+ View view = new View(container.getContext());
+ container.addView(view);
+ return view;
+ }
+
+ @Override
+ public void destroyItem(@NonNull ViewGroup container, int position,
+ @NonNull Object object) {
+ container.removeView((View) object);
+ }
+ }
+}
diff --git a/core-ui/tests/res/layout/activity_coordinator_layout.xml b/core-ui/tests/res/layout/activity_coordinator_layout.xml
new file mode 100644
index 0000000..93bf947
--- /dev/null
+++ b/core-ui/tests/res/layout/activity_coordinator_layout.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.design.widget.CoordinatorLayout
+ android:id="@+id/coordinator"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/design/tests/res/layout/include_nestedscrollview.xml b/core-ui/tests/res/layout/include_nestedscrollview.xml
similarity index 100%
rename from design/tests/res/layout/include_nestedscrollview.xml
rename to core-ui/tests/res/layout/include_nestedscrollview.xml
diff --git a/core-ui/tests/res/values/ids.xml b/core-ui/tests/res/values/ids.xml
index e5fcf63..f3ac9b4 100644
--- a/core-ui/tests/res/values/ids.xml
+++ b/core-ui/tests/res/values/ids.xml
@@ -24,4 +24,5 @@
<item name="page_7" type="id"/>
<item name="page_8" type="id"/>
<item name="page_9" type="id"/>
+ <item name="anchor" type="id"/>
</resources>
\ No newline at end of file
diff --git a/core-utils/build.gradle b/core-utils/build.gradle
index 64c9ff8..3f1efa1 100644
--- a/core-utils/build.gradle
+++ b/core-utils/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,13 +7,13 @@
}
dependencies {
- api project(':support-annotations')
- api project(':support-compat')
+ api(project(":support-annotations"))
+ api(project(":support-compat"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
}
android {
diff --git a/core-utils/java/android/support/v4/app/package.html b/core-utils/java/android/support/v4/app/package.html
deleted file mode 100755
index 02d1b79..0000000
--- a/core-utils/java/android/support/v4/app/package.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<body>
-
-Support android.app classes to assist with development of applications for
-android API level 4 or later. The main features here are backwards-compatible
-versions of {@link android.support.v4.app.FragmentManager} and
-{@link android.support.v4.app.LoaderManager}.
-
-</body>
diff --git a/core-utils/java/android/support/v4/content/package.html b/core-utils/java/android/support/v4/content/package.html
deleted file mode 100755
index 33bf4b5..0000000
--- a/core-utils/java/android/support/v4/content/package.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<body>
-
-Support android.content classes to assist with development of applications for
-android API level 4 or later. The main features here are
-{@link android.support.v4.content.Loader} and related classes and
-{@link android.support.v4.content.LocalBroadcastManager} to
-provide a cleaner implementation of broadcasts that don't need to go outside
-of an app.
-
-</body>
diff --git a/core-utils/lint-baseline.xml b/core-utils/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/core-utils/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/customtabs/build.gradle b/customtabs/build.gradle
index 28b5f99..75e28f7 100644
--- a/customtabs/build.gradle
+++ b/customtabs/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,21 +7,21 @@
}
dependencies {
- api project(':support-compat')
- api project(':support-annotations')
+ api(project(":support-compat"))
+ api(project(":support-annotations"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation project(':support-testutils')
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(project(":support-testutils"))
}
android {
defaultConfig {
- minSdkVersion 15
+ minSdkVersion(15)
}
sourceSets {
- main.aidl.srcDirs = ['src/main/java']
+ main.aidl.srcDirs = ["src/main/java"]
}
}
diff --git a/customtabs/lint-baseline.xml b/customtabs/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/customtabs/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/design/api/27.0.0.ignore b/design/api/27.0.0.ignore
index 533cc49..d982dc1 100644
--- a/design/api/27.0.0.ignore
+++ b/design/api/27.0.0.ignore
@@ -1,5 +1,14 @@
+a1fc27e
197ce1d
88bc57e
9761c3e
86b38bf
c6abd5e
+cea5c29
+8bac7c2
+f02de9f
+1d50e39
+fb2d5b2
+4c9b1f0
+7da565d
+33c90df
diff --git a/design/api/current.txt b/design/api/current.txt
index b15eca1..71de20a 100644
--- a/design/api/current.txt
+++ b/design/api/current.txt
@@ -15,7 +15,7 @@
method public deprecated void setTargetElevation(float);
}
- public static class AppBarLayout.Behavior extends android.support.design.widget.HeaderBehavior {
+ public static class AppBarLayout.Behavior extends android.support.design.widget.CoordinatorLayout.Behavior {
ctor public AppBarLayout.Behavior();
ctor public AppBarLayout.Behavior(android.content.Context, android.util.AttributeSet);
method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int);
@@ -63,7 +63,7 @@
method public abstract void onOffsetChanged(android.support.design.widget.AppBarLayout, int);
}
- public static class AppBarLayout.ScrollingViewBehavior extends android.support.design.widget.HeaderScrollingViewBehavior {
+ public static class AppBarLayout.ScrollingViewBehavior extends android.support.design.widget.CoordinatorLayout.Behavior {
ctor public AppBarLayout.ScrollingViewBehavior();
ctor public AppBarLayout.ScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
@@ -183,7 +183,6 @@
ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet);
ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet, int);
method protected android.support.design.widget.CollapsingToolbarLayout.LayoutParams generateDefaultLayoutParams();
- method public android.widget.FrameLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
method protected android.widget.FrameLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
method public int getCollapsedTitleGravity();
method public android.graphics.Typeface getCollapsedTitleTypeface();
@@ -244,13 +243,14 @@
field public static final int COLLAPSE_MODE_PIN = 1; // 0x1
}
- public class FloatingActionButton extends android.support.design.widget.VisibilityAwareImageButton {
+ public class FloatingActionButton extends android.widget.ImageButton {
ctor public FloatingActionButton(android.content.Context);
ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet);
ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet, int);
method public float getCompatElevation();
method public android.graphics.drawable.Drawable getContentBackground();
method public boolean getContentRect(android.graphics.Rect);
+ method public int getCustomSize();
method public int getRippleColor();
method public int getSize();
method public boolean getUseCompatPadding();
@@ -258,11 +258,13 @@
method public void hide(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
method public void setCompatElevation(float);
+ method public void setCustomSize(int);
method public void setRippleColor(int);
method public void setSize(int);
method public void setUseCompatPadding(boolean);
method public void show();
method public void show(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
+ field public static final int NO_CUSTOM_SIZE = 0; // 0x0
field public static final int SIZE_AUTO = -1; // 0xffffffff
field public static final int SIZE_MINI = 1; // 0x1
field public static final int SIZE_NORMAL = 0; // 0x0
@@ -284,20 +286,6 @@
method public void onShown(android.support.design.widget.FloatingActionButton);
}
- abstract class HeaderBehavior<V extends android.view.View> extends android.support.design.widget.ViewOffsetBehavior {
- ctor public HeaderBehavior();
- ctor public HeaderBehavior(android.content.Context, android.util.AttributeSet);
- }
-
- abstract class HeaderScrollingViewBehavior extends android.support.design.widget.ViewOffsetBehavior {
- ctor public HeaderScrollingViewBehavior();
- ctor public HeaderScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
- method public final int getOverlayTop();
- method protected void layoutChild(android.support.design.widget.CoordinatorLayout, android.view.View, int);
- method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.view.View, int, int, int, int);
- method public final void setOverlayTop(int);
- }
-
public class NavigationView extends android.widget.FrameLayout {
ctor public NavigationView(android.content.Context);
ctor public NavigationView(android.content.Context, android.util.AttributeSet);
@@ -396,7 +384,6 @@
method public void addTab(android.support.design.widget.TabLayout.Tab, boolean);
method public void addTab(android.support.design.widget.TabLayout.Tab, int, boolean);
method public void clearOnTabSelectedListeners();
- method public android.widget.FrameLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
method public int getSelectedTabPosition();
method public android.support.design.widget.TabLayout.Tab getTabAt(int);
method public int getTabCount();
@@ -472,7 +459,7 @@
ctor public TextInputEditText(android.content.Context, android.util.AttributeSet, int);
}
- public class TextInputLayout extends android.widget.LinearLayout {
+ public class TextInputLayout extends android.widget.LinearLayout implements android.support.v7.widget.WithHint {
ctor public TextInputLayout(android.content.Context);
ctor public TextInputLayout(android.content.Context, android.util.AttributeSet);
ctor public TextInputLayout(android.content.Context, android.util.AttributeSet, int);
@@ -508,21 +495,5 @@
method public void setTypeface(android.graphics.Typeface);
}
- class ViewOffsetBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
- ctor public ViewOffsetBehavior();
- ctor public ViewOffsetBehavior(android.content.Context, android.util.AttributeSet);
- method public int getLeftAndRightOffset();
- method public int getTopAndBottomOffset();
- method protected void layoutChild(android.support.design.widget.CoordinatorLayout, V, int);
- method public boolean setLeftAndRightOffset(int);
- method public boolean setTopAndBottomOffset(int);
- }
-
- class VisibilityAwareImageButton extends android.widget.ImageButton {
- ctor public VisibilityAwareImageButton(android.content.Context);
- ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet);
- ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet, int);
- }
-
}
diff --git a/design/build.gradle b/design/build.gradle
index 06a5a55..e7ebc91 100644
--- a/design/build.gradle
+++ b/design/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,16 +7,16 @@
}
dependencies {
- api project(':support-v4')
- api project(':appcompat-v7')
- api project(':recyclerview-v7')
- api project(':transition')
+ api(project(":support-v4"))
+ api(project(":appcompat-v7"))
+ api(project(":recyclerview-v7"))
+ api(project(":transition"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_contrib, { exclude group: 'com.android.support' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(ESPRESSO_CONTRIB, libs.exclude_support)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation project(':support-testutils')
}
diff --git a/design/lint-baseline.xml b/design/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/design/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/design/res/values/attrs.xml b/design/res/values/attrs.xml
index 6cdb22c..8c3536f 100644
--- a/design/res/values/attrs.xml
+++ b/design/res/values/attrs.xml
@@ -23,7 +23,7 @@
<!-- Ripple color for the FAB. -->
<attr name="rippleColor" format="color"/>
- <!-- Size for the FAB. -->
+ <!-- Size for the FAB. If fabCustomSize is set, this will be ignored. -->
<attr name="fabSize">
<!-- A size which will change based on the window size. -->
<enum name="auto" value="-1"/>
@@ -32,6 +32,8 @@
<!-- The mini sized button. -->
<enum name="mini" value="1"/>
</attr>
+ <!-- Custom size for the FAB. If this is set, fabSize will be ignored. -->
+ <attr name="fabCustomSize" format="dimension"/>
<!-- Elevation value for the FAB -->
<attr name="elevation"/>
<!-- TranslationZ value for the FAB when pressed-->
diff --git a/design/src/android/support/design/widget/FloatingActionButton.java b/design/src/android/support/design/widget/FloatingActionButton.java
index a53096e..f37b379 100644
--- a/design/src/android/support/design/widget/FloatingActionButton.java
+++ b/design/src/android/support/design/widget/FloatingActionButton.java
@@ -117,6 +117,11 @@
public static final int SIZE_AUTO = -1;
/**
+ * Indicates that FloatingActionButton should not have a custom size.
+ */
+ public static final int NO_CUSTOM_SIZE = 0;
+
+ /**
* The switch point for the largest screen edge where SIZE_AUTO switches from mini to normal.
*/
private static final int AUTO_MINI_LARGEST_SCREEN_WIDTH = 470;
@@ -133,6 +138,7 @@
private int mBorderWidth;
private int mRippleColor;
private int mSize;
+ private int mCustomSize;
int mImagePadding;
private int mMaxImageSize;
@@ -165,6 +171,8 @@
R.styleable.FloatingActionButton_backgroundTintMode, -1), null);
mRippleColor = a.getColor(R.styleable.FloatingActionButton_rippleColor, 0);
mSize = a.getInt(R.styleable.FloatingActionButton_fabSize, SIZE_AUTO);
+ mCustomSize = a.getDimensionPixelSize(R.styleable.FloatingActionButton_fabCustomSize,
+ 0);
mBorderWidth = a.getDimensionPixelSize(R.styleable.FloatingActionButton_borderWidth, 0);
final float elevation = a.getDimension(R.styleable.FloatingActionButton_elevation, 0f);
final float pressedTranslationZ = a.getDimension(
@@ -431,12 +439,41 @@
};
}
+ /**
+ * Sets the size of the button to be a custom value in pixels. If set to
+ * {@link #NO_CUSTOM_SIZE}, custom size will not be used and size will be calculated according
+ * to {@link #setSize(int)} method.
+ *
+ * @param size preferred size in pixels, or zero
+ *
+ * @attr ref android.support.design.R.styleable#FloatingActionButton_fabCustomSize
+ */
+ public void setCustomSize(int size) {
+ if (size < 0) {
+ throw new IllegalArgumentException("Custom size should be non-negative.");
+ }
+ mCustomSize = size;
+ }
+
+ /**
+ * Returns the custom size for this button.
+ *
+ * @return size in pixels, or {@link #NO_CUSTOM_SIZE}
+ */
+ public int getCustomSize() {
+ return mCustomSize;
+ }
+
int getSizeDimension() {
return getSizeDimension(mSize);
}
private int getSizeDimension(@Size final int size) {
final Resources res = getResources();
+ // If custom size is set, return it
+ if (mCustomSize != NO_CUSTOM_SIZE) {
+ return mCustomSize;
+ }
switch (size) {
case SIZE_AUTO:
// If we're set to auto, grab the size from resources and refresh
diff --git a/design/tests/res/values/ids.xml b/design/tests/res/values/ids.xml
index 73540b7..52b8356 100644
--- a/design/tests/res/values/ids.xml
+++ b/design/tests/res/values/ids.xml
@@ -26,5 +26,4 @@
<item name="page_9" type="id"/>
<item name="textinputlayout" type="id"/>
<item name="textinputedittext" type="id"/>
- <item name="anchor" type="id"/>
</resources>
\ No newline at end of file
diff --git a/design/tests/src/android/support/design/testutils/FloatingActionButtonActions.java b/design/tests/src/android/support/design/testutils/FloatingActionButtonActions.java
index 97949e6..a166f6b 100644
--- a/design/tests/src/android/support/design/testutils/FloatingActionButtonActions.java
+++ b/design/tests/src/android/support/design/testutils/FloatingActionButtonActions.java
@@ -107,6 +107,30 @@
};
}
+ public static ViewAction setCustomSize(final int size) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isAssignableFrom(FloatingActionButton.class);
+ }
+
+ @Override
+ public String getDescription() {
+ return "Sets FloatingActionButton custom size";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ final FloatingActionButton fab = (FloatingActionButton) view;
+ fab.setCustomSize(size);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
public static ViewAction setCompatElevation(final float size) {
return new ViewAction() {
@Override
diff --git a/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java b/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java
index 36cdee6..46bb982 100644
--- a/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java
+++ b/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java
@@ -268,6 +268,36 @@
}
/**
+ * Returns a matcher that matches FloatingActionButtons with the specified custom size.
+ */
+ public static Matcher withFabCustomSize(final int customSize) {
+ return new BoundedMatcher<View, View>(View.class) {
+ private String mFailedCheckDescription;
+
+ @Override
+ public void describeTo(final Description description) {
+ description.appendText(mFailedCheckDescription);
+ }
+
+ @Override
+ public boolean matchesSafely(final View view) {
+ if (!(view instanceof FloatingActionButton)) {
+ return false;
+ }
+
+ final FloatingActionButton fab = (FloatingActionButton) view;
+ if (Math.abs(fab.getCustomSize() - customSize) > 1.0f) {
+ mFailedCheckDescription =
+ "Custom size " + fab.getCustomSize() + " is different than expected "
+ + customSize;
+ return false;
+ }
+ return true;
+ }
+ };
+ }
+
+ /**
* Returns a matcher that matches FloatingActionButtons with the specified background
* fill color.
*/
diff --git a/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java b/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java
index 1037235..f7e9286 100644
--- a/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java
+++ b/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java
@@ -20,6 +20,7 @@
import static android.support.design.testutils.FloatingActionButtonActions.setBackgroundTintColor;
import static android.support.design.testutils.FloatingActionButtonActions.setBackgroundTintList;
import static android.support.design.testutils.FloatingActionButtonActions.setCompatElevation;
+import static android.support.design.testutils.FloatingActionButtonActions.setCustomSize;
import static android.support.design.testutils.FloatingActionButtonActions.setImageResource;
import static android.support.design.testutils.FloatingActionButtonActions.setLayoutGravity;
import static android.support.design.testutils.FloatingActionButtonActions.setSize;
@@ -31,6 +32,7 @@
import static android.support.design.testutils.TestUtilsMatchers.withFabBackgroundFill;
import static android.support.design.testutils.TestUtilsMatchers.withFabContentAreaOnMargins;
import static android.support.design.testutils.TestUtilsMatchers.withFabContentHeight;
+import static android.support.design.testutils.TestUtilsMatchers.withFabCustomSize;
import static android.support.design.widget.DesignViewActions.setVisibility;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
@@ -271,4 +273,16 @@
.perform(setEnabled(true))
.perform(setCompatElevation(8));
}
+
+ @SmallTest
+ @Test
+ public void testSetCustomSize() {
+ onView(withId(R.id.fab_standard))
+ .perform(setCustomSize(10))
+ .check(matches(withFabCustomSize(10)));
+
+ onView(withId(R.id.fab_standard))
+ .perform(setCustomSize(20))
+ .check(matches(withFabCustomSize(20)));
+ }
}
diff --git a/dynamic-animation/build.gradle b/dynamic-animation/build.gradle
index 5069a73..ac5623d 100644
--- a/dynamic-animation/build.gradle
+++ b/dynamic-animation/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,12 +7,12 @@
}
dependencies {
- api project(':support-core-utils')
+ api(project(":support-core-utils"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
}
android {
diff --git a/dynamic-animation/lint-baseline.xml b/dynamic-animation/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/dynamic-animation/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/emoji/appcompat/build.gradle b/emoji/appcompat/build.gradle
index 7912c52..3fe04d8 100644
--- a/emoji/appcompat/build.gradle
+++ b/emoji/appcompat/build.gradle
@@ -23,8 +23,8 @@
dependencies {
api fileTree(include: ['*.jar'], dir: 'libs')
- api project(':support-emoji')
- api project(':appcompat-v7')
+ api(project(":support-emoji"))
+ api(project(":appcompat-v7"))
}
android {
diff --git a/emoji/appcompat/lint-baseline.xml b/emoji/appcompat/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/emoji/appcompat/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/emoji/bundled/build.gradle b/emoji/bundled/build.gradle
index c0613f2..013ab85 100644
--- a/emoji/bundled/build.gradle
+++ b/emoji/bundled/build.gradle
@@ -20,7 +20,7 @@
}
dependencies {
- api project(':support-emoji')
+ api(project(":support-emoji"))
}
supportLibrary {
diff --git a/emoji/bundled/lint-baseline.xml b/emoji/bundled/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/emoji/bundled/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/emoji/core/build.gradle b/emoji/core/build.gradle
index f07c277..a311f25 100644
--- a/emoji/core/build.gradle
+++ b/emoji/core/build.gradle
@@ -1,5 +1,8 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
+import java.util.zip.ZipException
+import java.util.zip.ZipFile
plugins {
id("SupportAndroidLibraryPlugin")
@@ -19,12 +22,12 @@
// treats this as local jar and package it inside the aar.
api files(configurations.repackage)
- api project(':support-compat')
+ api(project(":support-compat"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation project(':support-testutils')
}
@@ -76,3 +79,53 @@
url = "http://www.unicode.org/copyright.html#License"
}
}
+
+import org.gradle.api.Task
+import org.gradle.api.tasks.TaskAction
+
+class ValidateJarInput extends DefaultTask {
+ Task syncTask
+
+ @TaskAction
+ void validate() {
+ for (File f : syncTask.inputs.files.files) {
+ if (f.name.endsWith(".jar")) {
+ ZipFile zip = null
+ for (def i : 0..3) {
+ try {
+ zip = new ZipFile(f)
+ if (i > 0) {
+ // If we get here, we know this is some timing issues. The jar file is
+ // properly created, but only if we wait.
+ logger.error("Succeeded in opening jar file '$f' after $i retries. Failing build.")
+ throw new RuntimeException("Failed opening zip file earlier.")
+ }
+ break
+ } catch (ZipException e) {
+ logger.error("Error opening jar file '$f' (attempt: $i): $e.message")
+ sleep(1000)
+ } finally {
+ if (zip != null) {
+ zip.close()
+ }
+ }
+ if (i == 3) {
+ // We failed after 3 retries, this means the generated file is not a proper
+ // jar file.
+ throw new RuntimeException("Failed opening zip file after 3 retries.")
+ }
+ }
+ }
+ }
+ }
+}
+
+afterEvaluate {
+ def syncJniTask = tasks.getByName("transformNativeLibsWithSyncJniLibsForRelease")
+ println "found $syncJniTask.name"
+ def validateTask = tasks.create("validateJarInputsForRelease", ValidateJarInput.class) { t ->
+ t.syncTask = syncJniTask
+ }
+ validateTask.dependsOn(syncJniTask.getDependsOn().collect())
+ syncJniTask.dependsOn(validateTask)
+}
diff --git a/emoji/core/lint-baseline.xml b/emoji/core/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/emoji/core/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/emoji/core/src/main/java/android/support/text/emoji/EmojiCompat.java b/emoji/core/src/main/java/android/support/text/emoji/EmojiCompat.java
index f258c12..5436aa2 100644
--- a/emoji/core/src/main/java/android/support/text/emoji/EmojiCompat.java
+++ b/emoji/core/src/main/java/android/support/text/emoji/EmojiCompat.java
@@ -221,6 +221,7 @@
*
* @see EmojiCompat.Config
*/
+ @SuppressWarnings("GuardedBy")
public static EmojiCompat init(@NonNull final Config config) {
if (sInstance == null) {
synchronized (sInstanceLock) {
@@ -238,6 +239,7 @@
*
* @hide
*/
+ @SuppressWarnings("GuardedBy")
@RestrictTo(LIBRARY_GROUP)
@VisibleForTesting
public static EmojiCompat reset(@NonNull final Config config) {
@@ -252,6 +254,7 @@
*
* @hide
*/
+ @SuppressWarnings("GuardedBy")
@RestrictTo(LIBRARY_GROUP)
@VisibleForTesting
public static EmojiCompat reset(final EmojiCompat emojiCompat) {
diff --git a/emoji/core/src/main/java/android/support/text/emoji/EmojiMetadata.java b/emoji/core/src/main/java/android/support/text/emoji/EmojiMetadata.java
index 488dcf9..7d495ed 100644
--- a/emoji/core/src/main/java/android/support/text/emoji/EmojiMetadata.java
+++ b/emoji/core/src/main/java/android/support/text/emoji/EmojiMetadata.java
@@ -26,12 +26,13 @@
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.annotation.RestrictTo;
-import android.support.text.emoji.flatbuffer.MetadataItem;
-import android.support.text.emoji.flatbuffer.MetadataList;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import androidx.text.emoji.flatbuffer.MetadataItem;
+import androidx.text.emoji.flatbuffer.MetadataList;
+
/**
* Information about a single emoji.
*
diff --git a/emoji/core/src/main/java/android/support/text/emoji/MetadataListReader.java b/emoji/core/src/main/java/android/support/text/emoji/MetadataListReader.java
index 6034726..02856cb 100644
--- a/emoji/core/src/main/java/android/support/text/emoji/MetadataListReader.java
+++ b/emoji/core/src/main/java/android/support/text/emoji/MetadataListReader.java
@@ -22,13 +22,14 @@
import android.support.annotation.IntRange;
import android.support.annotation.RequiresApi;
import android.support.annotation.RestrictTo;
-import android.support.text.emoji.flatbuffer.MetadataList;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import androidx.text.emoji.flatbuffer.MetadataList;
+
/**
* Reads the emoji metadata from a given InputStream or ByteBuffer.
*
@@ -275,7 +276,7 @@
@Override
public void skip(int numOfBytes) throws IOException {
while (numOfBytes > 0) {
- long skipped = mInputStream.skip(numOfBytes);
+ int skipped = (int) mInputStream.skip(numOfBytes);
if (skipped < 1) {
throw new IOException("Skip didn't move at least 1 byte forward");
}
diff --git a/emoji/core/src/main/java/android/support/text/emoji/MetadataRepo.java b/emoji/core/src/main/java/android/support/text/emoji/MetadataRepo.java
index e86277e..f5afec8 100644
--- a/emoji/core/src/main/java/android/support/text/emoji/MetadataRepo.java
+++ b/emoji/core/src/main/java/android/support/text/emoji/MetadataRepo.java
@@ -24,7 +24,6 @@
import android.support.annotation.RequiresApi;
import android.support.annotation.RestrictTo;
import android.support.annotation.VisibleForTesting;
-import android.support.text.emoji.flatbuffer.MetadataList;
import android.support.v4.util.Preconditions;
import android.util.SparseArray;
@@ -32,6 +31,8 @@
import java.io.InputStream;
import java.nio.ByteBuffer;
+import androidx.text.emoji.flatbuffer.MetadataList;
+
/**
* Class to hold the emoji metadata required to process and draw emojis.
*/
diff --git a/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiEditableFactory.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiEditableFactory.java
index 9793c9d..20cde4f 100644
--- a/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiEditableFactory.java
+++ b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiEditableFactory.java
@@ -55,6 +55,7 @@
}
}
+ @SuppressWarnings("GuardedBy")
public static Editable.Factory getInstance() {
if (sInstance == null) {
synchronized (sInstanceLock) {
diff --git a/exifinterface/build.gradle b/exifinterface/build.gradle
index b7218f9..fa4d7b4 100644
--- a/exifinterface/build.gradle
+++ b/exifinterface/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,9 +7,9 @@
}
dependencies {
- api project(':support-annotations')
+ api(project(":support-annotations"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
+ androidTestImplementation(TEST_RUNNER)
}
android {
diff --git a/exifinterface/lint-baseline.xml b/exifinterface/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/exifinterface/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/exifinterface/src/main/java/android/support/media/ExifInterface.java b/exifinterface/src/main/java/android/support/media/ExifInterface.java
index 72b61cb..eea69ab 100644
--- a/exifinterface/src/main/java/android/support/media/ExifInterface.java
+++ b/exifinterface/src/main/java/android/support/media/ExifInterface.java
@@ -4678,9 +4678,7 @@
private int getMimeType(BufferedInputStream in) throws IOException {
in.mark(SIGNATURE_CHECK_SIZE);
byte[] signatureCheckBytes = new byte[SIGNATURE_CHECK_SIZE];
- if (in.read(signatureCheckBytes) != SIGNATURE_CHECK_SIZE) {
- throw new EOFException();
- }
+ in.read(signatureCheckBytes);
in.reset();
if (isJpegFormat(signatureCheckBytes)) {
return IMAGE_TYPE_JPEG;
@@ -5333,7 +5331,7 @@
int dataFormat = dataInputStream.readUnsignedShort();
int numberOfComponents = dataInputStream.readInt();
// Next four bytes is for data offset or value.
- long nextEntryOffset = dataInputStream.peek() + 4;
+ long nextEntryOffset = dataInputStream.peek() + 4L;
// Look up a corresponding tag from tag number
ExifTag tag = (ExifTag) sExifTagMapsForReading[ifdType].get(tagNumber);
diff --git a/fragment/api/current.txt b/fragment/api/current.txt
index ccd6f4f..df78c30 100644
--- a/fragment/api/current.txt
+++ b/fragment/api/current.txt
@@ -22,7 +22,7 @@
field public static final int STYLE_NO_TITLE = 1; // 0x1
}
- public class Fragment implements android.content.ComponentCallbacks android.view.View.OnCreateContextMenuListener {
+ public class Fragment implements android.content.ComponentCallbacks android.arch.lifecycle.LifecycleOwner android.view.View.OnCreateContextMenuListener {
ctor public Fragment();
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public final boolean equals(java.lang.Object);
@@ -141,7 +141,7 @@
field public static final android.os.Parcelable.Creator<android.support.v4.app.Fragment.SavedState> CREATOR;
}
- public class FragmentActivity extends android.support.v4.app.SupportActivity {
+ public class FragmentActivity extends android.support.v4.app.SupportActivity implements android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback android.support.v4.app.ActivityCompat.RequestPermissionsRequestCodeValidator {
ctor public FragmentActivity();
method public java.lang.Object getLastCustomNonConfigurationInstance();
method public android.support.v4.app.FragmentManager getSupportFragmentManager();
diff --git a/fragment/build.gradle b/fragment/build.gradle
index 73977c2..b1cc47e 100644
--- a/fragment/build.gradle
+++ b/fragment/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,15 +7,15 @@
}
dependencies {
- api project(':support-compat')
- api project(':support-core-ui')
- api project(':support-core-utils')
- api project(':support-annotations')
+ api(project(":support-compat"))
+ api(project(":support-core-ui"))
+ api(project(":support-core-utils"))
+ api(project(":support-annotations"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has its own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has its own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation project(':support-testutils'), {
exclude group: 'com.android.support', module: 'support-fragment'
}
diff --git a/fragment/lint-baseline.xml b/fragment/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/fragment/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/fragment/src/main/java/android/support/v4/app/Fragment.java b/fragment/src/main/java/android/support/v4/app/Fragment.java
index e734a27..5b560cd 100644
--- a/fragment/src/main/java/android/support/v4/app/Fragment.java
+++ b/fragment/src/main/java/android/support/v4/app/Fragment.java
@@ -1816,8 +1816,9 @@
* use the same value as set in {@link #setEnterTransition(Object)}.
*
* @param transition The Transition to use to move Views out of the Scene when the Fragment
- * is preparing to close. <code>transition</code> must be an
- * android.transition.Transition.
+ * is preparing to close. <code>transition</code> must be an
+ * {@link android.transition.Transition android.transition.Transition} or
+ * {@link android.support.transition.Transition android.support.transition.Transition}.
*/
public void setReturnTransition(@Nullable Object transition) {
ensureAnimationInfo().mReturnTransition = transition;
@@ -1854,8 +1855,10 @@
* remain unaffected.
*
* @param transition The Transition to use to move Views out of the Scene when the Fragment
- * is being closed not due to popping the back stack. <code>transition</code>
- * must be an android.transition.Transition.
+ * is being closed not due to popping the back stack. <code>transition</code>
+ * must be an
+ * {@link android.transition.Transition android.transition.Transition} or
+ * {@link android.support.transition.Transition android.support.transition.Transition}.
*/
public void setExitTransition(@Nullable Object transition) {
ensureAnimationInfo().mExitTransition = transition;
@@ -1891,8 +1894,10 @@
* transition as {@link #setExitTransition(Object)}.
*
* @param transition The Transition to use to move Views into the scene when reentering from a
- * previously-started Activity. <code>transition</code>
- * must be an android.transition.Transition.
+ * previously-started Activity. <code>transition</code>
+ * must be an
+ * {@link android.transition.Transition android.transition.Transition} or
+ * {@link android.support.transition.Transition android.support.transition.Transition}.
*/
public void setReenterTransition(@Nullable Object transition) {
ensureAnimationInfo().mReenterTransition = transition;
@@ -1925,7 +1930,9 @@
* value will cause transferred shared elements to blink to the final position.
*
* @param transition The Transition to use for shared elements transferred into the content
- * Scene. <code>transition</code> must be an android.transition.Transition.
+ * Scene. <code>transition</code> must be an
+ * {@link android.transition.Transition android.transition.Transition} or
+ * {@link android.support.transition.Transition android.support.transition.Transition}.
*/
public void setSharedElementEnterTransition(@Nullable Object transition) {
ensureAnimationInfo().mSharedElementEnterTransition = transition;
@@ -1958,7 +1965,9 @@
* {@link #setSharedElementEnterTransition(Object)}.
*
* @param transition The Transition to use for shared elements transferred out of the content
- * Scene. <code>transition</code> must be an android.transition.Transition.
+ * Scene. <code>transition</code> must be an
+ * {@link android.transition.Transition android.transition.Transition} or
+ * {@link android.support.transition.Transition android.support.transition.Transition}.
*/
public void setSharedElementReturnTransition(@Nullable Object transition) {
ensureAnimationInfo().mSharedElementReturnTransition = transition;
diff --git a/fragment/src/main/java/android/support/v4/app/package.html b/fragment/src/main/java/android/support/v4/app/package.html
deleted file mode 100755
index 02d1b79..0000000
--- a/fragment/src/main/java/android/support/v4/app/package.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<body>
-
-Support android.app classes to assist with development of applications for
-android API level 4 or later. The main features here are backwards-compatible
-versions of {@link android.support.v4.app.FragmentManager} and
-{@link android.support.v4.app.LoaderManager}.
-
-</body>
diff --git a/graphics/drawable/animated/api/27.0.0.ignore b/graphics/drawable/animated/api/27.0.0.ignore
new file mode 100644
index 0000000..34748c7
--- /dev/null
+++ b/graphics/drawable/animated/api/27.0.0.ignore
@@ -0,0 +1 @@
+da32427
diff --git a/graphics/drawable/animated/api/current.txt b/graphics/drawable/animated/api/current.txt
index f2601de..ebdc90b 100644
--- a/graphics/drawable/animated/api/current.txt
+++ b/graphics/drawable/animated/api/current.txt
@@ -1,6 +1,6 @@
package android.support.graphics.drawable {
- public abstract interface Animatable2Compat {
+ public abstract interface Animatable2Compat implements android.graphics.drawable.Animatable {
method public abstract void clearAnimationCallbacks();
method public abstract void registerAnimationCallback(android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
method public abstract boolean unregisterAnimationCallback(android.support.graphics.drawable.Animatable2Compat.AnimationCallback);
@@ -12,7 +12,7 @@
method public void onAnimationStart(android.graphics.drawable.Drawable);
}
- public class AnimatedVectorDrawableCompat extends android.support.graphics.drawable.VectorDrawableCommon implements android.support.graphics.drawable.Animatable2Compat {
+ public class AnimatedVectorDrawableCompat extends android.graphics.drawable.Drawable implements android.support.graphics.drawable.Animatable2Compat android.support.v4.graphics.drawable.TintAwareDrawable {
method public void clearAnimationCallbacks();
method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable);
method public static android.support.graphics.drawable.AnimatedVectorDrawableCompat create(android.content.Context, int);
diff --git a/graphics/drawable/animated/build.gradle b/graphics/drawable/animated/build.gradle
index bfe405f..e76f846 100644
--- a/graphics/drawable/animated/build.gradle
+++ b/graphics/drawable/animated/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,26 +7,26 @@
}
dependencies {
- api project(':support-vector-drawable')
- api project(':support-core-ui')
+ api(project(":support-vector-drawable"))
+ api(project(":support-core-ui"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
}
android {
defaultConfig {
- minSdkVersion 14
+ minSdkVersion(14)
// This disables the builds tools automatic vector -> PNG generation
generatedDensities = []
}
aaptOptions {
- additionalParameters "--no-version-vectors"
+ additionalParameters("--no-version-vectors")
}
buildTypes.all {
- consumerProguardFiles 'proguard-rules.pro'
+ consumerProguardFiles("proguard-rules.pro")
}
}
diff --git a/graphics/drawable/static/api/27.0.0.ignore b/graphics/drawable/static/api/27.0.0.ignore
new file mode 100644
index 0000000..dc31648
--- /dev/null
+++ b/graphics/drawable/static/api/27.0.0.ignore
@@ -0,0 +1,2 @@
+57adc08
+4aae3d4
diff --git a/graphics/drawable/static/api/current.txt b/graphics/drawable/static/api/current.txt
index db07bf2..2fe60b8 100644
--- a/graphics/drawable/static/api/current.txt
+++ b/graphics/drawable/static/api/current.txt
@@ -1,9 +1,6 @@
package android.support.graphics.drawable {
- abstract class VectorDrawableCommon extends android.graphics.drawable.Drawable {
- }
-
- public class VectorDrawableCompat extends android.support.graphics.drawable.VectorDrawableCommon {
+ public class VectorDrawableCompat extends android.graphics.drawable.Drawable implements android.support.v4.graphics.drawable.TintAwareDrawable {
method public static android.support.graphics.drawable.VectorDrawableCompat create(android.content.res.Resources, int, android.content.res.Resources.Theme);
method public static android.support.graphics.drawable.VectorDrawableCompat createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public void draw(android.graphics.Canvas);
diff --git a/graphics/drawable/static/build.gradle b/graphics/drawable/static/build.gradle
index b8ab699..8575d6a 100644
--- a/graphics/drawable/static/build.gradle
+++ b/graphics/drawable/static/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,10 +7,10 @@
}
dependencies {
- api project(':support-annotations')
- api project(':support-compat')
+ api(project(":support-annotations"))
+ api(project(":support-compat"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
+ androidTestImplementation(TEST_RUNNER)
}
android {
diff --git a/graphics/drawable/static/lint-baseline.xml b/graphics/drawable/static/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/graphics/drawable/static/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/graphics/drawable/static/src/main/java/android/support/graphics/drawable/VectorDrawableCompat.java b/graphics/drawable/static/src/main/java/android/support/graphics/drawable/VectorDrawableCompat.java
index 2c7ae41..943f1aa 100644
--- a/graphics/drawable/static/src/main/java/android/support/graphics/drawable/VectorDrawableCompat.java
+++ b/graphics/drawable/static/src/main/java/android/support/graphics/drawable/VectorDrawableCompat.java
@@ -56,8 +56,8 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.Stack;
/**
* For API 24 and above, this class is delegating to the framework's {@link VectorDrawable}.
@@ -173,6 +173,10 @@
* <dd>Sets the lineJoin for a stroked path: miter,round,bevel. Default is miter.</dd>
* <dt><code>android:strokeMiterLimit</code></dt>
* <dd>Sets the Miter limit for a stroked path. Default is 4.</dd>
+ * <dt><code>android:fillType</code></dt>
+ * <dd>Sets the fillType for a path. The types can be either "evenOdd" or "nonZero". They behave the
+ * same as SVG's "fill-rule" properties. Default is nonZero. For more details, see
+ * <a href="https://www.w3.org/TR/SVG/painting.html#FillRuleProperty">FillRuleProperty</a></dd>
* </dl></dd>
* </dl>
*
@@ -726,7 +730,7 @@
// Use a stack to help to build the group tree.
// The top of the stack is always the current group.
- final Stack<VGroup> groupStack = new Stack<VGroup>();
+ final ArrayDeque<VGroup> groupStack = new ArrayDeque<>();
groupStack.push(pathRenderer.mRootGroup);
int eventType = parser.getEventType();
@@ -781,14 +785,7 @@
}
if (noPathTag) {
- final StringBuffer tag = new StringBuffer();
-
- if (tag.length() > 0) {
- tag.append(" or ");
- }
- tag.append(SHAPE_PATH);
-
- throw new XmlPullParserException("no " + tag + " defined");
+ throw new XmlPullParserException("no " + SHAPE_PATH + " defined");
}
}
diff --git a/jetifier/.gitignore b/jetifier/.gitignore
new file mode 100644
index 0000000..4469528
--- /dev/null
+++ b/jetifier/.gitignore
@@ -0,0 +1 @@
+**/build
diff --git a/jetifier/jetifier/build.gradle b/jetifier/jetifier/build.gradle
new file mode 100644
index 0000000..c817220
--- /dev/null
+++ b/jetifier/jetifier/build.gradle
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 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
+ */
+
+buildscript {
+ ext.supportRootFolder = "${project.projectDir}/../../"
+ apply from: "$supportRootFolder/buildSrc/repos.gradle"
+
+ ext.kotlin_version = '1.2.0'
+
+ repos.addMavenRepositories(repositories)
+
+ dependencies {
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+subprojects {
+ group 'android.support.tools.jetifier'
+
+ ext.supportRootFolder = "${project.projectDir}/../../.."
+
+ apply plugin: 'kotlin'
+ apply from: "$supportRootFolder/buildSrc/repos.gradle"
+
+ compileKotlin {
+ kotlinOptions.jvmTarget = "1.8"
+ }
+ compileTestKotlin {
+ kotlinOptions.jvmTarget = "1.8"
+ }
+
+ repos.addMavenRepositories(repositories)
+
+ dependencies {
+ compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ }
+}
+
+ext.runningInBuildServer = System.env.DIST_DIR != null && System.env.OUT_DIR != null
+def setupOutDirs() {
+ /*
+ * With the build server you are given two env variables.
+ * The OUT_DIR is a temporary directory you can use to put things during the build.
+ * The DIST_DIR is where you want to save things from the build.
+ *
+ * The build server will copy the contents of DIST_DIR to somewhere and make it available.
+ */
+ if (ext.runningInBuildServer) {
+ buildDir = new File(System.env.OUT_DIR + '/gradle/frameworks/support/build')
+ .getCanonicalFile()
+ project.ext.distDir = new File(System.env.DIST_DIR).getCanonicalFile()
+
+ // the build server should always print out full stack traces for any failures.
+ gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS
+ } else {
+ buildDir = file("${ext.supportRootFolder}/../../out/host/gradle/frameworks/support/jetifier/build")
+ project.ext.distDir = new File("${ext.supportRootFolder}/../../out/dist")
+ }
+ subprojects {
+ // Change buildDir so that all plugins pick up the new value.
+ project.buildDir = new File("$project.parent.buildDir/../$project.name/build")
+ project.ext.distDir = new File("${ext.supportRootFolder}/../../out/dist")
+ }
+}
+
+def configureBuildOnServer() {
+ def buildOnServerTask = rootProject.tasks.create("buildOnServer")
+ rootProject.tasks.whenTaskAdded { task ->
+ if ("build".equals(task.name)) {
+ buildOnServerTask.dependsOn task
+ }
+ }
+ subprojects {
+ project.tasks.whenTaskAdded { task ->
+ if ("fatJar".equals(task.name)) {
+ buildOnServerTask.dependsOn task
+ }
+ }
+ }
+}
+
+setupOutDirs()
+configureBuildOnServer()
diff --git a/jetifier/jetifier/core/build.gradle b/jetifier/jetifier/core/build.gradle
new file mode 100644
index 0000000..1ac3f36
--- /dev/null
+++ b/jetifier/jetifier/core/build.gradle
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 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
+ */
+
+version '1.0'
+
+dependencies {
+ compile group: 'org.ow2.asm', name: 'asm', version: '5.2'
+ compile group: 'org.ow2.asm', name: 'asm-commons', version: '5.2'
+ compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0'
+ compile group: 'org.jdom', name: 'jdom2', version: '2.0.6'
+ testCompile group: 'junit', name: 'junit', version: '4.12'
+ testCompile group: 'com.google.truth', name: 'truth', version: '0.31'
+}
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/Processor.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/Processor.kt
new file mode 100644
index 0000000..5af8fb2
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/Processor.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core
+
+import android.support.tools.jetifier.core.archive.Archive
+import android.support.tools.jetifier.core.archive.ArchiveFile
+import android.support.tools.jetifier.core.archive.ArchiveItemVisitor
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.transform.TransformationContext
+import android.support.tools.jetifier.core.transform.Transformer
+import android.support.tools.jetifier.core.transform.bytecode.ByteCodeTransformer
+import android.support.tools.jetifier.core.transform.pom.PomDocument
+import android.support.tools.jetifier.core.transform.pom.PomScanner
+import android.support.tools.jetifier.core.transform.proguard.ProGuardTransformer
+import android.support.tools.jetifier.core.transform.resource.XmlResourcesTransformer
+import android.support.tools.jetifier.core.utils.Log
+import java.io.File
+import java.io.FileNotFoundException
+import java.nio.file.Files
+import java.nio.file.Path
+
+/**
+ * The main entry point to the library. Extracts any given archive recursively and runs all
+ * the registered [Transformer]s over the set and creates new archives that will contain the
+ * transformed files.
+ */
+class Processor(private val config : Config) : ArchiveItemVisitor {
+
+ companion object {
+ private const val TAG = "Processor"
+ }
+
+ private val context = TransformationContext(config)
+
+ private val transformers = listOf(
+ // Register your transformers here
+ ByteCodeTransformer(context),
+ XmlResourcesTransformer(context),
+ ProGuardTransformer(context)
+ )
+
+ /**
+ * Transforms the input libraries given in [inputLibraries] using all the registered
+ * [Transformer]s and returns new libraries stored in [outputPath].
+ *
+ * Currently we have the following transformers:
+ * - [ByteCodeTransformer] for java native code
+ * - [XmlResourcesTransformer] for java native code
+ * - [ProGuardTransformer] for PorGuard files
+ */
+ fun transform(inputLibraries: Set<File>, outputPath: Path) : TransformationResult {
+ // 1) Extract and load all libraries
+ val libraries = loadLibraries(inputLibraries)
+
+ // 2) Search for POM files
+ val pomFiles = scanPomFiles(libraries)
+
+ // 3) Transform all the libraries
+ libraries.forEach{ transformLibrary(it) }
+
+ if (context.wasErrorFound()) {
+ throw IllegalArgumentException("There were ${context.mappingNotFoundFailuresCount}" +
+ " errors found during the remapping. Check the logs for more details.")
+ }
+
+ // TODO: Here we might need to modify the POM files if they point at a library that we have
+ // just refactored.
+
+ // 4) Transform the previously discovered POM files
+ transformPomFiles(pomFiles)
+
+ // 5) Repackage the libraries back to archives
+ val outputLibraries = libraries.map{ it.writeSelfToDir(outputPath) }.toSet()
+
+ // TODO: Filter out only the libraries that have been really changed
+ return TransformationResult(
+ filesToRemove = inputLibraries,
+ filesToAdd = outputLibraries)
+ }
+
+ private fun loadLibraries(inputLibraries : Iterable<File>) : List<Archive> {
+ val libraries = mutableListOf<Archive>()
+ for (library in inputLibraries) {
+ if (!library.canRead()) {
+ throw FileNotFoundException("Cannot open a library at '$library'")
+ }
+
+ libraries.add(Archive.Builder.extract(library))
+ }
+ return libraries.toList()
+ }
+
+ private fun scanPomFiles(libraries: List<Archive>) : List<PomDocument> {
+ val scanner = PomScanner(config)
+
+ libraries.forEach { scanner.scanArchiveForPomFile(it) }
+ if (scanner.wasErrorFound()) {
+ throw IllegalArgumentException("At least one of the libraries depends on an older" +
+ " version of support library. Check the logs for more details.")
+ }
+
+ return scanner.pomFiles
+ }
+
+ private fun transformPomFiles(files: List<PomDocument>) {
+ files.forEach {
+ it.applyRules(config.pomRewriteRules)
+ it.saveBackToFileIfNeeded()
+ }
+ }
+
+ private fun transformLibrary(archive: Archive) {
+ Log.i(TAG, "Started new transformation")
+ Log.i(TAG, "- Input file: %s", archive.relativePath)
+
+ archive.accept(this)
+ }
+
+ override fun visit(archive: Archive) {
+ archive.files.forEach{ it.accept(this) }
+ }
+
+ override fun visit(archiveFile: ArchiveFile) {
+ val transformer = transformers.firstOrNull { it.canTransform(archiveFile) }
+
+ if (transformer == null) {
+ Log.i(TAG, "[Skipped] %s", archiveFile.relativePath)
+ return
+ }
+
+ Log.i(TAG, "[Applied: %s] %s", transformer.javaClass.simpleName, archiveFile.relativePath)
+ transformer.runTransform(archiveFile)
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/TransformationResult.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/TransformationResult.kt
new file mode 100644
index 0000000..3e90483
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/TransformationResult.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core
+
+import java.io.File
+
+/**
+ * Result of the transformation done by the [Processor]
+ *
+ * @param filesToRemove files to be removed from project's dependencies
+ * @param filesToAdd files generated by Jetifier to be added to project's dependencies
+ */
+data class TransformationResult(val filesToRemove: Set<File>, val filesToAdd: Set<File>)
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/Archive.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/Archive.kt
new file mode 100644
index 0000000..70ea68c
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/Archive.kt
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.archive
+
+import android.support.tools.jetifier.core.utils.Log
+import java.io.BufferedOutputStream
+import java.io.File
+import java.io.FileInputStream
+import java.io.FileOutputStream
+import java.io.IOException
+import java.io.InputStream
+import java.io.OutputStream
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.Paths
+import java.util.zip.ZipEntry
+import java.util.zip.ZipInputStream
+import java.util.zip.ZipOutputStream
+
+/**
+ * Represents an archive (zip, jar, aar ...)
+ */
+class Archive(
+ override val relativePath: Path,
+ val files: List<ArchiveItem>)
+ : ArchiveItem {
+
+ companion object {
+ /** Defines file extensions that are recognized as archives */
+ val ARCHIVE_EXTENSIONS = listOf(".jar", ".zip", ".aar")
+
+ const val TAG = "Archive"
+ }
+
+ override val fileName: String = relativePath.fileName.toString()
+
+ override fun accept(visitor: ArchiveItemVisitor) {
+ visitor.visit(this)
+ }
+
+ @Throws(IOException::class)
+ fun writeSelfToDir(outputDirPath: Path) : File {
+ val outputPath = Paths.get(outputDirPath.toString(), fileName)
+
+ if (Files.exists(outputPath)) {
+ Log.i(TAG, "Deleting old output file")
+ Files.delete(outputPath)
+ }
+
+ // Create directories if they don't exist yet
+ Files.createDirectories(outputDirPath)
+
+ Log.i(TAG, "Writing archive: %s", outputPath.toUri())
+ val file = outputPath.toFile()
+ Files.createFile(outputPath)
+ val stream = BufferedOutputStream(FileOutputStream(file))
+ writeSelfTo(stream)
+ stream.close()
+ return file
+ }
+
+ @Throws(IOException::class)
+ override fun writeSelfTo(outputStream: OutputStream) {
+ val out = ZipOutputStream(outputStream)
+
+ for (file in files) {
+ Log.d(TAG, "Writing file: %s", file.relativePath)
+
+ val entry = ZipEntry(file.relativePath.toString())
+ out.putNextEntry(entry)
+ file.writeSelfTo(out)
+ out.closeEntry()
+ }
+ out.finish()
+ }
+
+
+ object Builder {
+
+ @Throws(IOException::class)
+ fun extract(archiveFile: File): Archive {
+ Log.i(TAG, "Extracting: %s", archiveFile.absolutePath)
+
+ val inputStream = FileInputStream(archiveFile)
+ inputStream.use {
+ return extractArchive(it, archiveFile.toPath())
+ }
+ }
+
+ @Throws(IOException::class)
+ private fun extractArchive(inputStream: InputStream, relativePath: Path)
+ : Archive {
+ val zipIn = ZipInputStream(inputStream)
+ val files = mutableListOf<ArchiveItem>()
+
+ var entry: ZipEntry? = zipIn.nextEntry
+ // iterates over entries in the zip file
+ while (entry != null) {
+ if (!entry.isDirectory) {
+ val entryPath = Paths.get(entry.name)
+ if (isArchive(entry)) {
+ Log.i(TAG, "Extracting nested: %s", entryPath)
+ files.add(extractArchive(zipIn, entryPath))
+ } else {
+ files.add(extractFile(zipIn, entryPath))
+ }
+ }
+ zipIn.closeEntry()
+ entry = zipIn.nextEntry
+ }
+ // Cannot close the zip stream at this moment as that would close also any parent zip
+ // streams in case we are processing a nested archive.
+
+ return Archive(relativePath, files.toList())
+ }
+
+ @Throws(IOException::class)
+ private fun extractFile(zipIn: ZipInputStream, relativePath: Path): ArchiveFile {
+ Log.d(TAG, "Extracting archive: %s", relativePath)
+
+ val data = zipIn.readBytes()
+ return ArchiveFile(relativePath, data)
+ }
+
+ private fun isArchive(zipEntry: ZipEntry) : Boolean {
+ return ARCHIVE_EXTENSIONS.any { zipEntry.name.endsWith(it, ignoreCase = true) }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveFile.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveFile.kt
new file mode 100644
index 0000000..3054b71
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveFile.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.archive
+
+import java.io.IOException
+import java.io.OutputStream
+import java.nio.file.Path
+
+/**
+ * Represents a file in the archive that is not an archive.
+ */
+class ArchiveFile(override val relativePath: Path, var data: ByteArray) : ArchiveItem {
+
+ override val fileName: String = relativePath.fileName.toString()
+
+ override fun accept(visitor: ArchiveItemVisitor) {
+ visitor.visit(this)
+ }
+
+ @Throws(IOException::class)
+ override fun writeSelfTo(outputStream: OutputStream) {
+ outputStream.write(data)
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveItem.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveItem.kt
new file mode 100644
index 0000000..2d35e13
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveItem.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.archive
+
+import java.io.OutputStream
+import java.nio.file.Path
+
+/**
+ * Abstraction to represent archive and its files as a one thing.
+ */
+interface ArchiveItem {
+
+ /**
+ * Relative path of the item according to its location in the archive.
+ *
+ * Files in a nested archive have a path relative to that archive not to the parent of
+ * the archive. The root archive has the file system path set as its relative path.
+ */
+ val relativePath : Path
+
+ /**
+ * Name of the file.
+ */
+ val fileName : String
+
+ /**
+ * Accepts visitor.
+ */
+ fun accept(visitor: ArchiveItemVisitor)
+
+ /**
+ * Writes its internal data (or other nested files) into the given output stream.
+ */
+ fun writeSelfTo(outputStream: OutputStream)
+
+
+ fun isPomFile() = fileName.equals("pom.xml", ignoreCase = true)
+
+ fun isClassFile() = fileName.endsWith(".class", ignoreCase = true)
+
+ fun isXmlFile() = fileName.endsWith(".xml", ignoreCase = true)
+
+ fun isProGuardFile () = fileName.equals("proguard.txt", ignoreCase = true)
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveItemVisitor.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveItemVisitor.kt
new file mode 100644
index 0000000..7c99fd9
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveItemVisitor.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.archive
+
+/**
+ * Visitor for [ArchiveItem]
+ */
+interface ArchiveItemVisitor {
+
+ fun visit(archive: Archive)
+
+ fun visit(archiveFile: ArchiveFile)
+
+}
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/config/Config.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/config/Config.kt
new file mode 100644
index 0000000..8d70d87
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/config/Config.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.config
+
+import android.support.tools.jetifier.core.rules.RewriteRule
+import android.support.tools.jetifier.core.transform.pom.PomRewriteRule
+import android.support.tools.jetifier.core.map.TypesMap
+import android.support.tools.jetifier.core.transform.proguard.ProGuardTypesMap
+import com.google.gson.annotations.SerializedName
+
+/**
+ * The main and only one configuration that is used by the tool and all its transformers.
+ *
+ * [restrictToPackagePrefixes] Package prefixes that limit the scope of the rewriting
+ * [rewriteRules] Rules to scan support libraries to generate [TypesMap]
+ * [pomRewriteRules] Rules to rewrite POM files
+ * [typesMap] Map of all java types and fields to be used to rewrite libraries.
+ */
+data class Config(
+ val restrictToPackagePrefixes: List<String>,
+ val rewriteRules: List<RewriteRule>,
+ val pomRewriteRules: List<PomRewriteRule>,
+ val typesMap: TypesMap,
+ val proGuardMap: ProGuardTypesMap) {
+
+ companion object {
+ /** Path to the default config file located within the jar file. */
+ const val DEFAULT_CONFIG_RES_PATH = "/default.generated.config"
+ }
+
+ fun setNewMap(mappings: TypesMap) : Config {
+ return Config(
+ restrictToPackagePrefixes, rewriteRules, pomRewriteRules, mappings, proGuardMap)
+ }
+
+ /** Returns JSON data model of this class */
+ fun toJson() : JsonData {
+ return JsonData(
+ restrictToPackagePrefixes,
+ rewriteRules.map { it.toJson() }.toList(),
+ pomRewriteRules.map { it.toJson() }.toList(),
+ typesMap.toJson(),
+ proGuardMap.toJson()
+ )
+ }
+
+
+ /**
+ * JSON data model for [Config].
+ */
+ data class JsonData(
+ @SerializedName("restrictToPackagePrefixes")
+ val restrictToPackages: List<String?>,
+
+ @SerializedName("rules")
+ val rules: List<RewriteRule.JsonData?>,
+
+ @SerializedName("pomRules")
+ val pomRules: List<PomRewriteRule.JsonData?>,
+
+ @SerializedName("map")
+ val mappings: TypesMap.JsonData? = null,
+
+ @SerializedName("proGuardMap")
+ val proGuardMap: ProGuardTypesMap.JsonData? = null) {
+
+ /** Creates instance of [Config] */
+ fun toConfig() : Config {
+ return Config(
+ restrictToPackages.filterNotNull(),
+ rules.filterNotNull().map { it.toRule() },
+ pomRules.filterNotNull().map { it.toRule() },
+ mappings?.toMappings() ?: TypesMap.EMPTY,
+ proGuardMap?.toMappings() ?: ProGuardTypesMap.EMPTY
+ )
+ }
+ }
+
+}
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/config/ConfigParser.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/config/ConfigParser.kt
new file mode 100644
index 0000000..50d510c
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/config/ConfigParser.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.config
+
+import android.support.tools.jetifier.core.utils.Log
+import com.google.gson.GsonBuilder
+import java.io.FileNotFoundException
+import java.io.FileWriter
+import java.nio.file.Files
+import java.nio.file.Path
+
+object ConfigParser {
+
+ private const val TAG : String = "Config"
+
+ private val gson = GsonBuilder().setPrettyPrinting().create()
+
+ fun writeToString(config: Config) : String {
+ return gson.toJson(config.toJson())
+ }
+
+ fun writeToFile(config: Config, outputPath: Path) {
+ FileWriter(outputPath.toFile()).use {
+ gson.toJson(config.toJson(), it)
+ }
+ }
+
+ fun parseFromString(inputText: String) : Config? {
+ return gson.fromJson(inputText, Config.JsonData::class.java).toConfig()
+ }
+
+ fun loadFromFile(configPath: Path) : Config? {
+ return loadConfigFileInternal(configPath)
+ }
+
+ fun loadDefaultConfig() : Config? {
+ Log.v(TAG, "Using the default config '%s'", Config.DEFAULT_CONFIG_RES_PATH)
+
+ val inputStream = javaClass.getResourceAsStream(Config.DEFAULT_CONFIG_RES_PATH)
+ return parseFromString(inputStream.reader().readText())
+ }
+
+ fun loadConfigOrFail(configPath: Path?) : Config {
+ if (configPath != null) {
+ val config = loadConfigFileInternal(configPath)
+ if (config != null) {
+ return config
+ }
+ throw FileNotFoundException("Config file was not found at '$configPath'")
+ }
+
+ val config = loadDefaultConfig()
+ if (config != null) {
+ return config
+ }
+ throw AssertionError("The default config could not be found!")
+ }
+
+ private fun loadConfigFileInternal(configPath: Path) : Config? {
+ if (!Files.isReadable(configPath)) {
+ Log.e(TAG, "Cannot access the config file: '%s'", configPath)
+ return null
+ }
+
+ Log.i(TAG, "Parsing config file: '%s'", configPath.toUri())
+ val config = parseFromString(configPath.toFile().readText())
+
+ if (config == null) {
+ Log.e(TAG, "Failed to parseFromString the config file")
+ return null
+ }
+
+ return config
+ }
+}
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/LibraryMapGenerator.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/LibraryMapGenerator.kt
new file mode 100644
index 0000000..de5a17f
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/LibraryMapGenerator.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.map
+
+import android.support.tools.jetifier.core.archive.Archive
+import android.support.tools.jetifier.core.archive.ArchiveFile
+import android.support.tools.jetifier.core.archive.ArchiveItemVisitor
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.transform.Transformer
+import org.objectweb.asm.ClassReader
+import org.objectweb.asm.ClassWriter
+
+/**
+ * Scans a library java files using [MapGeneratorRemapper] to create [TypesMap].
+ */
+class LibraryMapGenerator constructor(config: Config) : ArchiveItemVisitor {
+
+ val remapper = MapGeneratorRemapper(config)
+
+ /**
+ * Scans the given [library] to extend the types map meta-data. The final map can be retrieved
+ * using [generateMap].
+ */
+ fun scanLibrary(library: Archive) {
+ library.accept(this)
+ }
+
+ /**
+ * Creates the [TypesMap] based on the meta-data aggregated via previous [scanFile] calls
+ */
+ fun generateMap() : TypesMap {
+ return remapper.createTypesMap()
+ }
+
+ override fun visit(archive: Archive) {
+ archive.files.forEach{ it.accept(this) }
+ }
+
+ override fun visit(archiveFile: ArchiveFile) {
+ if (archiveFile.isClassFile()) {
+ scanFile(archiveFile)
+ }
+ }
+
+ private fun scanFile(file: ArchiveFile) {
+ val reader = ClassReader(file.data)
+ val writer = ClassWriter(0 /* flags */)
+
+ val visitor = remapper.createClassRemapper(writer)
+
+ reader.accept(visitor, 0 /* flags */)
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/MapGeneratorRemapper.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/MapGeneratorRemapper.kt
new file mode 100644
index 0000000..374e213
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/MapGeneratorRemapper.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.map
+
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.rules.JavaField
+import android.support.tools.jetifier.core.rules.JavaType
+import android.support.tools.jetifier.core.transform.bytecode.CoreRemapper
+import android.support.tools.jetifier.core.transform.bytecode.asm.CustomClassRemapper
+import android.support.tools.jetifier.core.transform.bytecode.asm.CustomRemapper
+import android.support.tools.jetifier.core.utils.Log
+import org.objectweb.asm.ClassVisitor
+import java.util.regex.Pattern
+
+/**
+ * Hooks to asm remapping to collect data for [TypesMap] by applying all the [RewriteRule]s from the
+ * given [config] on all discovered and eligible types and fields.
+ */
+class MapGeneratorRemapper(private val config: Config) : CoreRemapper {
+
+ companion object {
+ private const val TAG : String = "MapGeneratorRemapper"
+ }
+
+ private val typesRewritesMap = hashMapOf<JavaType, JavaType>()
+ private val fieldsRewritesMap = hashMapOf<JavaField, JavaField>()
+
+ var isMapNotComplete = false
+ private set
+
+ /**
+ * Ignore mPrefix types and anything that contains $ as these are internal fields that won't be
+ * ever referenced.
+ */
+ private val ignoredFields = Pattern.compile("(^m[A-Z]+.*$)|(.*\\$.*)")
+
+ /**
+ * Ignores types ending with '$digit' as these are private inner classes and won't be ever
+ * referenced.
+ */
+ private val ignoredTypes = Pattern.compile("^(.*)\\$[0-9]+$")
+
+ fun createClassRemapper(visitor: ClassVisitor): CustomClassRemapper {
+ return CustomClassRemapper(visitor, CustomRemapper(this))
+ }
+
+ override fun rewriteType(type: JavaType): JavaType {
+ if (!isTypeSupported(type)) {
+ return type
+ }
+
+ if (typesRewritesMap.contains(type)) {
+ return type
+ }
+
+ if (isTypeIgnored(type)) {
+ return type
+ }
+
+ // Try to find a rule
+ for (rule in config.rewriteRules) {
+ val mappedTypeName = rule.apply(type) ?: continue
+ typesRewritesMap.put(type, mappedTypeName)
+
+ Log.i(TAG, " map: %s -> %s", type, mappedTypeName)
+ return mappedTypeName
+ }
+
+ isMapNotComplete = true
+ Log.e(TAG, "No rule for: " + type)
+ typesRewritesMap.put(type, type) // Identity
+ return type
+ }
+
+ override fun rewriteField(field : JavaField): JavaField {
+ if (!isTypeSupported(field.owner)) {
+ return field
+ }
+
+ if (isTypeIgnored(field.owner) || isFieldIgnored(field)) {
+ return field
+ }
+
+ if (fieldsRewritesMap.contains(field)) {
+ return field
+ }
+
+ // Try to find a rule
+ for (rule in config.rewriteRules) {
+ val mappedFieldName = rule.apply(field) ?: continue
+ fieldsRewritesMap.put(field, mappedFieldName)
+
+ Log.i(TAG, " map: %s -> %s", field, mappedFieldName)
+ return mappedFieldName
+ }
+
+ isMapNotComplete = true
+ Log.e(TAG, "No rule for: " + field)
+ fieldsRewritesMap.put(field, field) // Identity
+ return field
+ }
+
+ fun createTypesMap() : TypesMap {
+ return TypesMap(typesRewritesMap, fieldsRewritesMap)
+ }
+
+ private fun isTypeSupported(type: JavaType) : Boolean {
+ return config.restrictToPackagePrefixes.any{ type.fullName.startsWith(it) }
+ }
+
+ private fun isTypeIgnored(type: JavaType) : Boolean {
+ return ignoredTypes.matcher(type.fullName).matches()
+ }
+
+ private fun isFieldIgnored(field: JavaField) : Boolean {
+ return ignoredFields.matcher(field.name).matches()
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/TypesMap.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/TypesMap.kt
new file mode 100644
index 0000000..ce02026
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/TypesMap.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.map
+
+import android.support.tools.jetifier.core.rules.JavaField
+import android.support.tools.jetifier.core.rules.JavaType
+import android.support.tools.jetifier.core.rules.RewriteRule
+
+/**
+ * Contains all the mappings needed to rewrite java types and fields.
+ *
+ * These mappings are generated by the preprocessor from existing support libraries and by applying
+ * the given [RewriteRule]s.
+ */
+data class TypesMap(
+ val types: Map<JavaType, JavaType>,
+ val fields: Map<JavaField, JavaField>) {
+
+ companion object {
+ val EMPTY = TypesMap(emptyMap(), emptyMap())
+ }
+
+ /** Returns JSON data model of this class */
+ fun toJson() : JsonData {
+ return JsonData(
+ types = types.map { it.key.fullName to it.value.fullName }
+ .toMap(),
+ fields = mapFields())
+ }
+
+ private fun mapFields() : Map<String, Map<String, List<String>>> {
+ val rawMap = mutableMapOf<String, MutableMap<String, MutableList<String>>>()
+
+ fields.forEach{
+ rawMap
+ .getOrPut(it.key.owner.fullName, { mutableMapOf<String, MutableList<String>>()} )
+ .getOrPut(it.value.owner.fullName, { mutableListOf() })
+ .add(it.key.name)
+ }
+ return rawMap
+ }
+
+ /**
+ * JSON data model for [TypesMap].
+ */
+ data class JsonData(
+ val types: Map<String, String>,
+ val fields: Map<String, Map<String, List<String>>>) {
+
+ /** Creates instance of [TypesMap] */
+ fun toMappings() : TypesMap {
+ return TypesMap(
+ types = types
+ .orEmpty()
+ .map { JavaType(it.key) to JavaType(it.value) }
+ .toMap(),
+ fields = fields
+ .orEmpty().entries
+ .flatMap {
+ top ->
+ top.value.flatMap {
+ mid ->
+ mid.value.map {
+ JavaField(top.key, it) to JavaField(mid.key, it)
+ }
+ }
+ }
+ .toMap())
+ }
+ }
+}
+
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaField.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaField.kt
new file mode 100644
index 0000000..c423f0a
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaField.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.rules
+
+/**
+ * Wrapper for Java field declaration.
+ */
+data class JavaField(val owner : JavaType, val name : String) {
+
+ constructor(owner : String, name : String) : this(JavaType(owner), name)
+
+
+ fun renameOwner(newOwner: JavaType) = JavaField(newOwner, name)
+
+ override fun toString() = owner.toString() + "." + name
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaType.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaType.kt
new file mode 100644
index 0000000..d7a077b
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaType.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.rules
+
+/**
+ * Wrapper for Java type declaration.
+ */
+data class JavaType(val fullName: String) {
+
+ init {
+ if (fullName.contains('.')) {
+ throw IllegalArgumentException("The type does not support '.' as package separator!")
+ }
+ }
+
+ companion object {
+ /** Creates the type from notation where packages are separated using '.' */
+ fun fromDotVersion(fullName: String) : JavaType {
+ return JavaType(fullName.replace('.', '/'))
+ }
+ }
+
+ /** Returns the type as a string where packages are separated using '.' */
+ fun toDotNotation() : String {
+ return fullName.replace('/', '.')
+ }
+
+
+ override fun toString() = fullName
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaTypeXmlRef.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaTypeXmlRef.kt
new file mode 100644
index 0000000..9d58046
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaTypeXmlRef.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.rules
+
+/**
+ * Wrapper for Java type reference used in XML.
+ *
+ * In XML we use '.' as a package separator.
+ */
+data class JavaTypeXmlRef(val fullName : String) {
+
+ constructor(type: JavaType)
+ : this(type.fullName.replace('/', '.'))
+
+ fun toJavaType() : JavaType {
+ return JavaType(fullName.replace('.', '/'))
+ }
+
+ override fun toString() = fullName
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/RewriteRule.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/RewriteRule.kt
new file mode 100644
index 0000000..700e757
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/RewriteRule.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.rules
+
+import com.google.gson.annotations.SerializedName
+import java.util.regex.Pattern
+
+/**
+ * Rule that rewrites a Java type or field based on the given arguments.
+ *
+ * Used in the preprocessor when generating [TypesMap].
+ *
+ * @param from Regular expression where packages are separated via '/' and inner class separator
+ * is "$". Used to match the input type.
+ * @param to A string to be used as a replacement if the 'from' pattern is matched. It can also
+ * apply groups matched from the original pattern using {x} annotation, e.g. {0}.
+ * @param fieldSelectors Collection of regular expressions that are used to match fields. If the
+ * type is matched (using 'from') and the field is matched (or the list of fields selectors is
+ * empty) the field's type gets rewritten according to the 'to' parameter.
+ */
+class RewriteRule(
+ private val from: String,
+ private val to: String,
+ private val fieldSelectors: List<String> = emptyList()) {
+
+ // We escape '$' so we don't conflict with regular expression symbols.
+ private val inputPattern = Pattern.compile("^${from.replace("$", "\\$")}$")
+ private val outputPattern = to.replace("$", "\$")
+
+ private val fields = fieldSelectors.map { Pattern.compile("^$it$") }
+
+ /**
+ * Rewrites the given java type. Returns null if this rule is not applicable for the given type.
+ */
+ fun apply(input: JavaType): JavaType? {
+ if (fields.isNotEmpty()) {
+ return null
+ }
+
+ return applyInternal(input)
+ }
+
+ /**
+ * Rewrites the given field type. Returns null if this rule is not applicable for the given
+ * type.
+ */
+ fun apply(inputField: JavaField) : JavaField? {
+ val typeRewriteResult = applyInternal(inputField.owner) ?: return null
+
+ val isFieldInTheFilter = fields.isEmpty()
+ || fields.any { it.matcher(inputField.name).matches() }
+ if (isFieldInTheFilter) {
+ return inputField.renameOwner(typeRewriteResult)
+ }
+
+ return null
+ }
+
+ private fun applyInternal(input: JavaType): JavaType? {
+ val matcher = inputPattern.matcher(input.fullName)
+ if (!matcher.matches()) {
+ return null
+ }
+
+ var result = outputPattern
+ for (i in 0..matcher.groupCount() - 1) {
+ result = result.replace("{$i}", matcher.group(i + 1))
+ }
+
+ return JavaType(result)
+ }
+
+ override fun toString() : String {
+ return "$inputPattern -> $outputPattern " + fields.joinToString { it.toString() }
+ }
+
+ /** Returns JSON data model of this class */
+ fun toJson() : JsonData {
+ return JsonData(from, to, fieldSelectors)
+ }
+
+
+ /**
+ * JSON data model for [RewriteRule].
+ */
+ data class JsonData(
+ @SerializedName("from")
+ val from: String,
+
+ @SerializedName("to")
+ val to: String,
+
+ @SerializedName("fieldSelectors")
+ val fieldSelectors: List<String>? = null) {
+
+ /** Creates instance of [RewriteRule] */
+ fun toRule() : RewriteRule {
+ return RewriteRule(from, to, fieldSelectors.orEmpty())
+ }
+ }
+
+}
+
+
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/TransformationContext.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/TransformationContext.kt
new file mode 100644
index 0000000..3f8af95
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/TransformationContext.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform
+
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.rules.JavaType
+import android.support.tools.jetifier.core.transform.proguard.ProGuardType
+import java.util.regex.Pattern
+
+/**
+ * Context to share the transformation state between individual [Transformer]s.
+ */
+class TransformationContext(val config: Config) {
+
+ // Merges all packages prefixes into one regEx pattern
+ private val packagePrefixPattern = Pattern.compile(
+ "^(" + config.restrictToPackagePrefixes.map { "($it)" }.joinToString("|") + ").*$")
+
+ /** Counter for [reportNoMappingFoundFailure] calls. */
+ var mappingNotFoundFailuresCount = 0
+ private set
+
+ /** Counter for [reportNoProGuardMappingFoundFailure] calls. */
+ var proGuardMappingNotFoundFailuresCount = 0
+ private set
+
+ /** Returns whether any errors were found during the transformation process */
+ fun wasErrorFound() = mappingNotFoundFailuresCount > 0
+
+ /**
+ * Returns whether the given type is eligible for rewrite.
+ *
+ * If not, the transformers should ignore it.
+ */
+ fun isEligibleForRewrite(type: JavaType) : Boolean {
+ if (config.restrictToPackagePrefixes.isEmpty()) {
+ return false
+ }
+ return packagePrefixPattern.matcher(type.fullName).matches()
+ }
+
+ /**
+ * Returns whether the given ProGuard type reference is eligible for rewrite.
+ *
+ * Keep in mind that his has limited capabilities - mainly when * is used as a prefix. Rules
+ * like *.v7 are not matched by prefix support.v7. So don't rely on it and use
+ * the [ProGuardTypesMap] as first.
+ */
+ fun isEligibleForRewrite(type: ProGuardType) : Boolean {
+ if (config.restrictToPackagePrefixes.isEmpty()) {
+ return false
+ }
+ return packagePrefixPattern.matcher(type.value).matches()
+ }
+
+ /**
+ * Used to report that there was a reference found that satisfies [isEligibleForRewrite] but no
+ * mapping was found to rewrite it.
+ */
+ fun reportNoMappingFoundFailure() {
+ mappingNotFoundFailuresCount++
+ }
+
+ /**
+ * Used to report that there was a reference found in the ProGuard file that satisfies
+ * [isEligibleForRewrite] but no mapping was found to rewrite it.
+ */
+ fun reportNoProGuardMappingFoundFailure() {
+ proGuardMappingNotFoundFailuresCount++
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/Transformer.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/Transformer.kt
new file mode 100644
index 0000000..0c6c8aa
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/Transformer.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform
+
+import android.support.tools.jetifier.core.archive.ArchiveFile
+
+/**
+ * Interface to be implemented by any class that wants process files.
+ */
+interface Transformer {
+
+ /**
+ * Returns whether this instance can process the given file.
+ */
+ fun canTransform(file: ArchiveFile): Boolean
+
+ /**
+ * Runs transformation of the given file.
+ */
+ fun runTransform(file: ArchiveFile)
+
+}
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/ByteCodeTransformer.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/ByteCodeTransformer.kt
new file mode 100644
index 0000000..33235e0
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/ByteCodeTransformer.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.bytecode
+
+import android.support.tools.jetifier.core.archive.ArchiveFile
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.transform.TransformationContext
+import android.support.tools.jetifier.core.transform.Transformer
+import org.objectweb.asm.ClassReader
+import org.objectweb.asm.ClassWriter
+
+/**
+ * The [Transformer] responsible for java byte code refactoring.
+ */
+class ByteCodeTransformer internal constructor(context: TransformationContext) : Transformer {
+
+ private val remapper: CoreRemapperImpl = CoreRemapperImpl(context)
+
+
+ override fun canTransform(file: ArchiveFile) = file.isClassFile()
+
+ override fun runTransform(file: ArchiveFile) {
+ val reader = ClassReader(file.data)
+ val writer = ClassWriter(0 /* flags */)
+
+ val visitor = remapper.createClassRemapper(writer)
+
+ reader.accept(visitor, 0 /* flags */)
+
+ file.data = writer.toByteArray()
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapper.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapper.kt
new file mode 100644
index 0000000..50f3b31
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapper.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.bytecode
+
+import android.support.tools.jetifier.core.rules.JavaField
+import android.support.tools.jetifier.core.rules.JavaType
+
+/**
+ * High-level re-mapping interface to provide only the refactorings needed by jetifier.
+ */
+interface CoreRemapper {
+ fun rewriteType(type: JavaType) : JavaType
+
+ fun rewriteField(field: JavaField) : JavaField
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapperImpl.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapperImpl.kt
new file mode 100644
index 0000000..486cc25
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapperImpl.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.bytecode
+
+import android.support.tools.jetifier.core.map.TypesMap
+import android.support.tools.jetifier.core.rules.JavaField
+import android.support.tools.jetifier.core.rules.JavaType
+import android.support.tools.jetifier.core.transform.TransformationContext
+import android.support.tools.jetifier.core.transform.bytecode.asm.CustomClassRemapper
+import android.support.tools.jetifier.core.transform.bytecode.asm.CustomRemapper
+import android.support.tools.jetifier.core.utils.Log
+import org.objectweb.asm.ClassVisitor
+
+/**
+ * Applies mappings defined in [TypesMap] during the remapping process.
+ */
+class CoreRemapperImpl(private val context: TransformationContext) : CoreRemapper {
+
+ companion object {
+ const val TAG = "CoreRemapperImpl"
+ }
+
+ private val typesMap = context.config.typesMap
+
+ fun createClassRemapper(visitor: ClassVisitor): CustomClassRemapper {
+ return CustomClassRemapper(visitor, CustomRemapper(this))
+ }
+
+ override fun rewriteType(type: JavaType): JavaType {
+ val result = typesMap.types[type]
+
+ if (!context.isEligibleForRewrite(type)) {
+ return type
+ }
+
+ if (result != null) {
+ Log.i(TAG, " map: %s -> %s", type, result)
+ return result
+ }
+
+ context.reportNoMappingFoundFailure()
+ Log.e(TAG, "No mapping for: " + type)
+ return type
+ }
+
+ override fun rewriteField(field : JavaField): JavaField {
+ val result = typesMap.fields[field]
+
+ if (!context.isEligibleForRewrite(field.owner)) {
+ return field
+ }
+
+ if (result != null) {
+ Log.i(TAG, " map: %s -> %s", field, result)
+ return result
+ }
+
+ context.reportNoMappingFoundFailure()
+ Log.e(TAG, "No mapping for: " + field)
+ return field
+ }
+
+}
+
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomClassRemapper.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomClassRemapper.kt
new file mode 100644
index 0000000..692e65d
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomClassRemapper.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.bytecode.asm
+
+import org.objectweb.asm.ClassVisitor
+import org.objectweb.asm.FieldVisitor
+import org.objectweb.asm.MethodVisitor
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.commons.ClassRemapper
+
+/**
+ * Currently only adds field context awareness into [ClassRemapper] and substitutes the default
+ * method remapper with [CustomMethodRemapper]
+ */
+class CustomClassRemapper(cv: ClassVisitor, private val customRemapper: CustomRemapper)
+ : ClassRemapper(Opcodes.ASM5, cv, customRemapper) {
+
+ override fun visitField(access: Int,
+ name: String,
+ desc: String?,
+ signature: String?,
+ value: Any?) : FieldVisitor? {
+ cv ?: return null
+
+ val field = customRemapper.mapField(className, name)
+ val fieldVisitor = cv.visitField(
+ access,
+ field.name,
+ remapper.mapDesc(desc),
+ remapper.mapSignature(signature, true),
+ remapper.mapValue(value))
+
+ fieldVisitor ?: return null
+
+ return createFieldRemapper(fieldVisitor)
+ }
+
+ override fun createMethodRemapper(mv: MethodVisitor) : MethodVisitor {
+ return CustomMethodRemapper(mv, customRemapper)
+ }
+}
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomMethodRemapper.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomMethodRemapper.kt
new file mode 100644
index 0000000..cc60cbf
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomMethodRemapper.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.bytecode.asm
+
+import org.objectweb.asm.MethodVisitor
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.commons.MethodRemapper
+
+/**
+ * Currently only adds field context awareness into [MethodRemapper]
+ */
+internal class CustomMethodRemapper(mv:MethodVisitor,
+ private val customRemapper: CustomRemapper)
+ : MethodRemapper(Opcodes.ASM5, mv, customRemapper) {
+
+ override fun visitFieldInsn(opcode: Int, owner: String, name: String, desc: String?) {
+ mv ?: return
+
+ val field = customRemapper.mapField(owner, name)
+ mv.visitFieldInsn(opcode, field.owner.fullName, field.name, remapper.mapDesc(desc))
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomRemapper.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomRemapper.kt
new file mode 100644
index 0000000..5debf70
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomRemapper.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.bytecode.asm
+
+import android.support.tools.jetifier.core.rules.JavaField
+import android.support.tools.jetifier.core.rules.JavaType
+import android.support.tools.jetifier.core.transform.bytecode.CoreRemapper
+import org.objectweb.asm.commons.Remapper
+
+/**
+ * Extends [Remapper] with a capability to rewrite field names together with their owner.
+ */
+class CustomRemapper(val remapperImpl: CoreRemapper) : Remapper() {
+
+ override fun map(typeName: String): String {
+ return remapperImpl.rewriteType(JavaType(typeName)).fullName
+ }
+
+ fun mapField(ownerName: String, fieldName: String): JavaField {
+ return remapperImpl.rewriteField(JavaField(ownerName, fieldName))
+ }
+
+ override fun mapFieldName(owner: String?, name: String, desc: String?): String {
+ throw RuntimeException("This should not be called")
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomDependency.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomDependency.kt
new file mode 100644
index 0000000..1622fd7
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomDependency.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.pom
+
+import com.google.gson.annotations.SerializedName
+import org.jdom2.Document
+import org.jdom2.Element
+
+/**
+ * Represents a '<dependency>' XML node of a POM file.
+ *
+ * See documentation of the content at https://maven.apache.org/pom.html#Dependencies
+ */
+data class PomDependency(
+ @SerializedName("groupId")
+ val groupId: String? = null,
+
+ @SerializedName("artifactId")
+ val artifactId: String? = null,
+
+ @SerializedName("version")
+ var version: String? = null,
+
+ @SerializedName("classifier")
+ val classifier: String? = null,
+
+ @SerializedName("type")
+ val type: String? = null,
+
+ @SerializedName("scope")
+ val scope: String? = null,
+
+ @SerializedName("systemPath")
+ val systemPath: String? = null,
+
+ @SerializedName("optional")
+ val optional: String? = null) {
+
+ companion object {
+
+ /**
+ * Creates a new [PomDependency] from the given XML [Element].
+ */
+ fun fromXmlElement(node: Element, properties: Map<String, String>) : PomDependency {
+ var groupId : String? = null
+ var artifactId : String? = null
+ var version : String? = null
+ var classifier : String? = null
+ var type : String? = null
+ var scope : String? = null
+ var systemPath : String? = null
+ var optional : String? = null
+
+ for (childNode in node.children) {
+ when (childNode.name) {
+ "groupId" -> groupId = XmlUtils.resolveValue(childNode.value, properties)
+ "artifactId" -> artifactId = XmlUtils.resolveValue(childNode.value, properties)
+ "version" -> version = XmlUtils.resolveValue(childNode.value, properties)
+ "classifier" -> classifier = XmlUtils.resolveValue(childNode.value, properties)
+ "type" -> type = XmlUtils.resolveValue(childNode.value, properties)
+ "scope" -> scope = XmlUtils.resolveValue(childNode.value, properties)
+ "systemPath" -> systemPath = XmlUtils.resolveValue(childNode.value, properties)
+ "optional" -> optional = XmlUtils.resolveValue(childNode.value, properties)
+ }
+ }
+
+ return PomDependency(
+ groupId = groupId,
+ artifactId = artifactId,
+ version = version,
+ classifier = classifier,
+ type = type,
+ scope = scope,
+ systemPath = systemPath,
+ optional = optional)
+ }
+
+ }
+
+ init {
+ if (version != null) {
+ version = version!!.toLowerCase()
+ }
+ }
+
+ /**
+ * Whether this dependency should be skipped from the rewriting process
+ */
+ fun shouldSkipRewrite() : Boolean {
+ return scope != null && scope.toLowerCase() == "test"
+ }
+
+ /**
+ * Returns a new dependency created by taking all the items from the [input] dependency and then
+ * overwriting these with all of its non-null items.
+ */
+ fun rewrite(input: PomDependency) : PomDependency {
+ return PomDependency(
+ groupId = groupId ?: input.groupId,
+ artifactId = artifactId ?: input.artifactId,
+ version = version ?: input.version,
+ classifier = classifier ?: input.classifier,
+ type = type ?: input.type,
+ scope = scope ?: input.scope,
+ systemPath = systemPath ?: input.systemPath,
+ optional = optional ?: input.optional
+ )
+ }
+
+ /**
+ * Transforms the current data into XML '<dependency>' node.
+ */
+ fun toXmlElement(document: Document) : Element {
+ val node = Element("dependency")
+ node.namespace = document.rootElement.namespace
+
+ XmlUtils.addStringNodeToNode(node, "groupId", groupId)
+ XmlUtils.addStringNodeToNode(node, "artifactId", artifactId)
+ XmlUtils.addStringNodeToNode(node, "version", version)
+ XmlUtils.addStringNodeToNode(node, "classifier", classifier)
+ XmlUtils.addStringNodeToNode(node, "type", type)
+ XmlUtils.addStringNodeToNode(node, "scope", scope)
+ XmlUtils.addStringNodeToNode(node, "systemPath", systemPath)
+ XmlUtils.addStringNodeToNode(node, "optional", optional)
+
+ return node
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomDocument.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomDocument.kt
new file mode 100644
index 0000000..d5bdc3a
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomDocument.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.pom
+
+import android.support.tools.jetifier.core.archive.ArchiveFile
+import android.support.tools.jetifier.core.utils.Log
+import org.jdom2.Document
+import org.jdom2.Element
+
+/**
+ * Wraps a single POM XML [ArchiveFile] with parsed metadata about transformation related sections.
+ */
+class PomDocument(val file: ArchiveFile, private val document: Document) {
+
+ companion object {
+ private const val TAG = "Pom"
+
+ fun loadFrom(file: ArchiveFile) : PomDocument {
+ val document = XmlUtils.createDocumentFromByteArray(file.data)
+ val pomDoc = PomDocument(file, document)
+ pomDoc.initialize()
+ return pomDoc
+ }
+ }
+
+ val dependencies : MutableSet<PomDependency> = mutableSetOf()
+ private val properties : MutableMap<String, String> = mutableMapOf()
+ private var dependenciesGroup : Element? = null
+ private var hasChanged : Boolean = false
+
+ private fun initialize() {
+ val propertiesGroup = document.rootElement
+ .getChild("properties", document.rootElement.namespace)
+ if (propertiesGroup != null) {
+ propertiesGroup.children
+ .filterNot { it.value.isNullOrEmpty() }
+ .forEach { properties[it.name] = it.value }
+ }
+
+ dependenciesGroup = document.rootElement
+ .getChild("dependencies", document.rootElement.namespace) ?: return
+ dependenciesGroup!!.children.mapTo(dependencies) {
+ PomDependency.fromXmlElement(it, properties)
+ }
+ }
+
+ /**
+ * Validates that this document is consistent with the provided [rules].
+ *
+ * Currently it checks that all the dependencies that are going to be rewritten by the given
+ * rules satisfy the minimal version requirements defined by the rules.
+ */
+ fun validate(rules: List<PomRewriteRule>) : Boolean {
+ if (dependenciesGroup == null) {
+ // Nothing to validate as this file has no dependencies section
+ return true
+ }
+
+ return dependencies.all { dep -> rules.all { it.validateVersion(dep) } }
+ }
+
+ /**
+ * Applies the given [rules] to rewrite the POM file.
+ *
+ * Changes are not saved back until requested.
+ */
+ fun applyRules(rules: List<PomRewriteRule>) {
+ if (dependenciesGroup == null) {
+ // Nothing to transform as this file has no dependencies section
+ return
+ }
+
+ val newDependencies = mutableSetOf<PomDependency>()
+ for (dependency in dependencies) {
+ if (dependency.shouldSkipRewrite()) {
+ continue
+ }
+
+ val rule = rules.firstOrNull { it.matches(dependency) }
+ if (rule == null) {
+ // No rule to rewrite => keep it
+ newDependencies.add(dependency)
+ } else {
+ // Replace with new dependencies
+ newDependencies.addAll(rule.to.mapTo(newDependencies){ it.rewrite(dependency) })
+ }
+ }
+
+ if (newDependencies.isEmpty()) {
+ // No changes
+ return
+ }
+
+ dependenciesGroup!!.children.clear()
+ newDependencies.forEach { dependenciesGroup!!.addContent(it.toXmlElement(document)) }
+ hasChanged = true
+ }
+
+ /**
+ * Saves any current pending changes back to the file if needed.
+ */
+ fun saveBackToFileIfNeeded() {
+ if (!hasChanged) {
+ return
+ }
+
+ file.data = XmlUtils.convertDocumentToByteArray(document)
+ }
+
+ /**
+ * Logs the information about the current file using info level.
+ */
+ fun logDocumentDetails() {
+ Log.i(TAG, "POM file at: '%s'", file.relativePath)
+ for ((groupId, artifactId, version) in dependencies) {
+ Log.i(TAG, "- Dep: %s:%s:%s", groupId, artifactId, version)
+ }
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomRewriteRule.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomRewriteRule.kt
new file mode 100644
index 0000000..070a640
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomRewriteRule.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.pom
+
+import android.support.tools.jetifier.core.utils.Log
+import com.google.gson.annotations.SerializedName
+
+/**
+ * Rule that defines how to rewrite a dependency element in a POM file.
+ *
+ * Any dependency that is matched against [from] should be rewritten to list of the dependencies
+ * defined in [to].
+ */
+data class PomRewriteRule(val from: PomDependency, val to: List<PomDependency>) {
+
+ companion object {
+ val TAG : String = "PomRule"
+ }
+
+ /**
+ * Validates that the given [input] dependency has a valid version.
+ */
+ fun validateVersion(input: PomDependency, document: PomDocument? = null) : Boolean {
+ if (from.version == null || input.version == null) {
+ return true
+ }
+
+ if (!matches(input)) {
+ return true
+ }
+
+ if (!areVersionsMatching(from.version!!, input.version!!)) {
+ Log.e(TAG, "Version mismatch! Expected version '%s' but found version '%s' for " +
+ "'%s:%s' in '%s' file.", from.version, input.version, input.groupId,
+ input.artifactId, document?.file?.relativePath)
+ return false
+ }
+
+ return true
+ }
+
+ /**
+ * Checks if the given [version] is supported to be rewritten with a rule having [ourVersion].
+ *
+ * Version entry can be actually quite complicated, see the full documentation at:
+ * https://maven.apache.org/pom.html#Dependencies
+ */
+ private fun areVersionsMatching(ourVersion: String, version: String) : Boolean {
+ if (version == "latest" || version == "release") {
+ return true
+ }
+
+ if (version.endsWith(",)") || version.endsWith(",]")) {
+ return true
+ }
+
+ if (version.endsWith("$ourVersion]")) {
+ return true
+ }
+
+ return ourVersion == version
+ }
+
+ fun matches(input: PomDependency) : Boolean {
+ return input.artifactId == from.artifactId && input.groupId == from.groupId
+ }
+
+ /** Returns JSON data model of this class */
+ fun toJson() : PomRewriteRule.JsonData {
+ return PomRewriteRule.JsonData(from, to)
+ }
+
+
+ /**
+ * JSON data model for [PomRewriteRule].
+ */
+ data class JsonData(
+ @SerializedName("from")
+ val from: PomDependency,
+ @SerializedName("to")
+ val to: List<PomDependency>) {
+
+ /** Creates instance of [PomRewriteRule] */
+ fun toRule() : PomRewriteRule {
+ return PomRewriteRule(from, to.filterNotNull())
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomScanner.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomScanner.kt
new file mode 100644
index 0000000..e9cc511
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomScanner.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.pom
+
+import android.support.tools.jetifier.core.archive.Archive
+import android.support.tools.jetifier.core.archive.ArchiveFile
+import android.support.tools.jetifier.core.archive.ArchiveItemVisitor
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.utils.Log
+
+/**
+ * Helper to scan [Archive]s to find their POM files.
+ */
+class PomScanner(private val config: Config) {
+
+ companion object {
+ private const val TAG = "PomScanner"
+ }
+
+ private val pomFilesInternal = mutableListOf<PomDocument>()
+
+ private var validationFailuresCount = 0
+
+ val pomFiles : List<PomDocument> = pomFilesInternal
+
+ fun wasErrorFound() = validationFailuresCount > 0
+
+ /**
+ * Scans the given [archive] for a POM file
+ *
+ * @return null if POM file was not found
+ */
+ fun scanArchiveForPomFile(archive: Archive) : PomDocument? {
+ val session = PomScannerSession()
+ archive.accept(session)
+
+ if (session.pomFile == null) {
+ return null
+ }
+ val pomFile = session.pomFile!!
+
+ pomFile.logDocumentDetails()
+
+ if (!pomFile.validate(config.pomRewriteRules)) {
+ Log.e(TAG, "Version mismatch!")
+ validationFailuresCount++
+ }
+
+ pomFilesInternal.add(session.pomFile!!)
+
+ return session.pomFile
+ }
+
+
+ private class PomScannerSession : ArchiveItemVisitor {
+
+ var pomFile : PomDocument? = null
+
+ override fun visit(archive: Archive) {
+ for (archiveItem in archive.files) {
+ if (pomFile != null) {
+ break
+ }
+ archiveItem.accept(this)
+ }
+ }
+
+ override fun visit(archiveFile: ArchiveFile) {
+ if (archiveFile.isPomFile()) {
+ pomFile = PomDocument.loadFrom(archiveFile)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/XmlUtils.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/XmlUtils.kt
new file mode 100644
index 0000000..67b7a3d
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/XmlUtils.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.pom
+
+import android.support.tools.jetifier.core.utils.Log
+import org.jdom2.Document
+import org.jdom2.Element
+import org.jdom2.input.SAXBuilder
+import org.jdom2.output.Format
+import org.jdom2.output.XMLOutputter
+import java.io.ByteArrayOutputStream
+import java.util.regex.Pattern
+
+/**
+ * Utilities for handling XML documents.
+ */
+class XmlUtils {
+
+ companion object {
+
+ private val variablePattern = Pattern.compile("\\$\\{([^}]*)}")
+
+ /** Saves the given [Document] to a new byte array */
+ fun convertDocumentToByteArray(document : Document) : ByteArray {
+ val xmlOutput = XMLOutputter()
+ ByteArrayOutputStream().use {
+ xmlOutput.format = Format.getPrettyFormat()
+ xmlOutput.output(document, it)
+ return it.toByteArray()
+ }
+ }
+
+ /** Creates a new [Document] from the given [ByteArray] */
+ fun createDocumentFromByteArray(data: ByteArray) : Document {
+ val builder = SAXBuilder()
+ data.inputStream().use {
+ return builder.build(it)
+ }
+ }
+
+ /**
+ * Creates a new XML element with the given [id] and text given in [value] and puts it under
+ * the given [parent]. Nothing is created if the [value] argument is null or empty.
+ */
+ fun addStringNodeToNode(parent: Element, id: String, value: String?) {
+ if (value.isNullOrEmpty()) {
+ return
+ }
+
+ val element = Element(id)
+ element.text = value
+ element.namespace = parent.namespace
+ parent.children.add(element)
+ }
+
+
+ fun resolveValue(value: String?, properties: Map<String, String>) : String? {
+ if (value == null) {
+ return null
+ }
+
+ val matcher = variablePattern.matcher(value)
+ if (matcher.matches()) {
+ val variableName = matcher.group(1)
+ val varValue = properties[variableName]
+ if (varValue == null) {
+ Log.e("TAG", "Failed to resolve variable '%s'", value)
+ return value
+ }
+ return varValue
+ }
+
+ return value
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardClassFilterParser.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardClassFilterParser.kt
new file mode 100644
index 0000000..c431572
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardClassFilterParser.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import android.support.tools.jetifier.core.transform.proguard.patterns.GroupsReplacer
+import android.support.tools.jetifier.core.transform.proguard.patterns.PatternHelper
+import java.util.regex.Pattern
+
+/**
+ * Parses and rewrites ProGuard rules that contain class filters. See ProGuard documentation
+ * https://www.guardsquare.com/en/proguard/manual/usage#filters
+ */
+class ProGuardClassFilterParser(private val mapper : ProGuardTypesMapper) {
+
+ companion object {
+ private const val RULES = "(adaptclassstrings|dontnote|dontwarn)"
+ }
+
+ val replacer = GroupsReplacer(
+ pattern = PatternHelper.build("^ *-$RULES ⦅[^-]+ï½ *$", Pattern.MULTILINE),
+ groupsMap = listOf(
+ { filter : String -> rewriteClassFilter(filter) }
+ )
+ )
+
+ private fun rewriteClassFilter(classFilter: String) : String {
+ return classFilter
+ .splitToSequence(",")
+ .filterNotNull()
+ .map { it.trim() }
+ .filter { it.isNotEmpty() }
+ .map { replaceTypeInClassFilter(it) }
+ .joinToString(separator = ", ")
+ }
+
+ private fun replaceTypeInClassFilter(type: String) : String {
+ if (!type.startsWith('!')) {
+ return mapper.replaceType(type)
+ }
+
+ val withoutNegation = type.substring(1, type.length)
+ return '!' + mapper.replaceType(withoutNegation)
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardClassSpecParser.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardClassSpecParser.kt
new file mode 100644
index 0000000..933ff08
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardClassSpecParser.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import android.support.tools.jetifier.core.transform.proguard.patterns.GroupsReplacer
+import android.support.tools.jetifier.core.transform.proguard.patterns.PatternHelper
+
+/**
+ * Parses and rewrites ProGuard rules that contain class specification. See ProGuard documentation
+ * https://www.guardsquare.com/en/proguard/manual/usage#classspecification
+ */
+class ProGuardClassSpecParser(private val mapper : ProGuardTypesMapper) {
+
+ companion object {
+ private const val RULES = "(keep[a-z]*|whyareyoukeeping|assumenosideeffects)"
+ private const val RULES_MODIFIERS =
+ "(includedescriptorclasses|allowshrinking|allowoptimization|allowobfuscation)"
+
+ private const val CLASS_NAME = "[\\w.$?*_%]+"
+ private const val CLASS_MODIFIERS = "[!]?(public|final|abstract)"
+ private const val CLASS_TYPES = "[!]?(interface|class|enum)"
+
+ private const val ANNOTATION_TYPE = CLASS_NAME
+
+ private const val FIELD_NAME = "[\\w?*_%]+"
+ private const val FIELD_TYPE = CLASS_NAME
+ private const val FIELD_MODIFIERS =
+ "[!]?(public|private|protected|static|volatile|transient)"
+
+ private const val METHOD_MODIFIERS =
+ "[!]?(public|private|protected|static|synchronized|native|abstract|strictfp)"
+ private const val RETURN_TYPE_NAME = CLASS_NAME
+ private const val METHOD_NAME = "[\\w?*_]+"
+ private const val ARGS = "[^)]*"
+ }
+
+ val replacer = GroupsReplacer(
+ pattern = PatternHelper.build(
+ "-$RULES ($RULES_MODIFIERS )*(@⦅$ANNOTATION_TYPEï½ )?($CLASS_MODIFIERS )*$CLASS_TYPES " +
+ "⦅$CLASS_NAMEï½ ( (extends|implements) ⦅$CLASS_NAMEï½ )?+ *( *\\{⦅[^}]*ï½ \\} *)?+"),
+ groupsMap = listOf(
+ { annotation : String -> mapper.replaceType(annotation) },
+ { className : String -> mapper.replaceType(className) },
+ { className2 : String -> mapper.replaceType(className2) },
+ { bodyGroup : String -> rewriteBodyGroup(bodyGroup) }
+ )
+ )
+
+ private val bodyReplacers = listOf(
+ // [@annotation] [[!]public|private|etc...] <fields>;
+ GroupsReplacer(
+ pattern = PatternHelper.build(
+ "^ *(@⦅$ANNOTATION_TYPEï½ )?($FIELD_MODIFIERS )*<fields> *$"),
+ groupsMap = listOf(
+ { annotation : String -> mapper.replaceType(annotation) }
+ )),
+
+ // [@annotation] [[!]public|private|etc...] fieldType fieldName;
+ GroupsReplacer(
+ pattern = PatternHelper.build(
+ "^ *(@⦅$ANNOTATION_TYPEï½ )?($FIELD_MODIFIERS )*(⦅$FIELD_TYPEï½ $FIELD_NAME) *$"),
+ groupsMap = listOf(
+ { annotation : String -> mapper.replaceType(annotation) },
+ { fieldType : String -> mapper.replaceType(fieldType) }
+ )),
+
+ // [@annotation] [[!]public|private|etc...] <methods>;
+ GroupsReplacer(
+ pattern = PatternHelper.build(
+ "^ *(@⦅$ANNOTATION_TYPEï½ )?($METHOD_MODIFIERS )*<methods> *$"),
+ groupsMap = listOf(
+ { annotation : String -> mapper.replaceType(annotation) }
+ )),
+
+ // [@annotation] [[!]public|private|etc...] className(argumentType,...));
+ GroupsReplacer(
+ pattern = PatternHelper.build(
+ "^ *(@⦅$ANNOTATION_TYPEï½ )?($METHOD_MODIFIERS )*⦅$CLASS_NAMEï½ *\\(⦅$ARGSï½ \\) *$"),
+ groupsMap = listOf(
+ { annotation : String -> mapper.replaceType(annotation) },
+ { className : String -> mapper.replaceType(className) },
+ { argsType : String -> mapper.replaceMethodArgs(argsType) }
+ )
+ ),
+
+ // [@annotation] [[!]public|private|etc...] <init>(argumentType,...));
+ GroupsReplacer(
+ pattern = PatternHelper.build(
+ "^ *(@⦅$ANNOTATION_TYPEï½ )?($METHOD_MODIFIERS )*<init> *\\(⦅$ARGSï½ \\) *$"),
+ groupsMap = listOf(
+ { annotation : String -> mapper.replaceType(annotation) },
+ { argsType : String -> mapper.replaceMethodArgs(argsType) }
+ )),
+
+ // [@annotation] [[!]public|private|etc...] returnType methodName(argumentType,...));
+ GroupsReplacer(
+ pattern = PatternHelper.build("^ *(@⦅$ANNOTATION_TYPEï½ )?($METHOD_MODIFIERS )*" +
+ "⦅$RETURN_TYPE_NAMEï½ $METHOD_NAME *\\(⦅$ARGSï½ \\) *$"),
+ groupsMap = listOf(
+ { annotation : String -> mapper.replaceType(annotation) },
+ { returnType : String -> mapper.replaceType(returnType) },
+ { argsType : String -> mapper.replaceMethodArgs(argsType) }
+ ))
+ )
+
+ private fun rewriteBodyGroup(bodyGroup: String) : String {
+ if (bodyGroup == "*" || bodyGroup == "**") {
+ return bodyGroup
+ }
+
+ return bodyGroup
+ .split(';')
+ .map {
+ for (replacer in bodyReplacers) {
+ val matcher = replacer.pattern.matcher(it)
+ if (matcher.matches()) {
+ return@map replacer.runReplacements(matcher)
+ }
+ }
+ return@map it
+ }
+ .joinToString(";")
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTransformer.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTransformer.kt
new file mode 100644
index 0000000..423bf05
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTransformer.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import android.support.tools.jetifier.core.archive.ArchiveFile
+import android.support.tools.jetifier.core.transform.TransformationContext
+import android.support.tools.jetifier.core.transform.Transformer
+import android.support.tools.jetifier.core.transform.proguard.patterns.ReplacersRunner
+import java.nio.charset.StandardCharsets
+
+/**
+ * The [Transformer] responsible for ProGuard files refactoring.
+ */
+class ProGuardTransformer internal constructor(context: TransformationContext) : Transformer {
+
+ private val mapper = ProGuardTypesMapper(context)
+
+ val replacer = ReplacersRunner(listOf(
+ ProGuardClassSpecParser(mapper).replacer,
+ ProGuardClassFilterParser(mapper).replacer
+ ))
+
+ override fun canTransform(file: ArchiveFile): Boolean {
+ return file.isProGuardFile()
+ }
+
+ override fun runTransform(file: ArchiveFile) {
+ val sb = StringBuilder(file.data.toString(StandardCharsets.UTF_8))
+ val result = replacer.applyReplacers(sb.toString())
+ file.data = result.toByteArray()
+ }
+}
+
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardType.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardType.kt
new file mode 100644
index 0000000..be15fbf
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardType.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import android.support.tools.jetifier.core.rules.JavaType
+
+/**
+ * Represents a type reference in ProGuard file. This type is similar to the regular java type but
+ * can also contain wildcards (*,**,?).
+ */
+data class ProGuardType(val value: String) {
+
+ init {
+ if (value.contains('.')) {
+ throw IllegalArgumentException("The type does not support '.' as package separator!")
+ }
+ }
+
+ companion object {
+ /** Creates the type reference from notation where packages are separated using '.' */
+ fun fromDotNotation(type: String) : ProGuardType {
+ return ProGuardType(type.replace('.', '/'))
+ }
+ }
+
+ /**
+ * Whether the type reference is trivial such as "*".
+ */
+ fun isTrivial() = value == "*" || value == "**" || value == "***" || value == "%"
+
+ fun toJavaType() : JavaType? {
+ if (value.contains('*') || value.contains('?')) {
+ return null
+ }
+ return JavaType(value)
+ }
+
+ /** Returns the type reference as a string where packages are separated using '.' */
+ fun toDotNotation() : String {
+ return value.replace('/', '.')
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMap.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMap.kt
new file mode 100644
index 0000000..03d6282
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMap.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+/**
+ * Contains custom mappings to map support library types referenced in ProGuard to new ones.
+ */
+data class ProGuardTypesMap(val rules: Map<ProGuardType, ProGuardType>) {
+
+ companion object {
+ val EMPTY = ProGuardTypesMap(emptyMap())
+ }
+
+ /** Returns JSON data model of this class */
+ fun toJson() : JsonData {
+ return JsonData(rules.map { it.key.value to it.value.value }.toMap())
+ }
+
+ /**
+ * JSON data model for [ProGuardTypesMap].
+ */
+ data class JsonData(val rules: Map<String, String>) {
+
+ /** Creates instance of [ProGuardTypesMap] */
+ fun toMappings() : ProGuardTypesMap {
+ return ProGuardTypesMap(rules.map { ProGuardType(it.key) to ProGuardType(it.value) }.toMap())
+ }
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMapper.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMapper.kt
new file mode 100644
index 0000000..28195a3
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMapper.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import android.support.tools.jetifier.core.transform.TransformationContext
+import android.support.tools.jetifier.core.utils.Log
+
+/**
+ * Maps ProGuard types using [TypesMap] and [ProGuardTypesMap].
+ */
+class ProGuardTypesMapper(private val context: TransformationContext) {
+
+ companion object {
+ const val TAG = "ProGuardTypesMapper"
+ }
+
+ private val config = context.config
+
+ /**
+ * Replaces the given ProGuard type that was parsed from the ProGuard file (thus having '.' as
+ * a separator.
+ */
+ fun replaceType(typeToReplace: String) : String {
+ val type = ProGuardType.fromDotNotation(typeToReplace)
+ if (type.isTrivial()) {
+ return typeToReplace
+ }
+
+ val javaType = type.toJavaType()
+ if (javaType != null) {
+ // We are dealing with an explicit type definition
+ if (!context.isEligibleForRewrite(javaType)) {
+ return typeToReplace
+ }
+
+ val result = config.typesMap.types[javaType]
+ if (result == null) {
+ context.reportNoProGuardMappingFoundFailure()
+ Log.e(TAG, "No mapping for: " + type)
+ return typeToReplace
+ }
+
+ Log.i(TAG, " map: %s -> %s", type, result)
+ return result.toDotNotation()
+ }
+
+ // Type contains wildcards - try custom rules map
+ val result = config.proGuardMap.rules[type]
+ if (result != null) {
+ Log.i(TAG, " map: %s -> %s", type, result)
+ return result.toDotNotation()
+ }
+
+ // Report error only when we are sure
+ if (context.isEligibleForRewrite(type)) {
+ context.reportNoProGuardMappingFoundFailure()
+ Log.e(TAG, "No mapping for: " + type)
+ }
+ return typeToReplace
+ }
+
+ /**
+ * Replaces the given arguments list used in a ProGuard method rule. Argument must be separated
+ * with ','. The method also accepts '...' symbol as defined in the spec.
+ */
+ fun replaceMethodArgs(argsTypes: String) : String {
+ if (argsTypes.isEmpty() || argsTypes == "...") {
+ return argsTypes
+ }
+
+ return argsTypes
+ .splitToSequence(",")
+ .filterNotNull()
+ .map { it.trim() }
+ .filter { it.isNotEmpty() }
+ .map { replaceType(it) }
+ .joinToString(separator = ", ")
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/patterns/GroupsReplacer.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/patterns/GroupsReplacer.kt
new file mode 100644
index 0000000..6213a55
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/patterns/GroupsReplacer.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard.patterns
+
+import java.util.regex.Matcher
+import java.util.regex.Pattern
+
+/**
+ * Applies replacements on a matched string using the given [pattern] and its groups. Each group is
+ * mapped using a lambda from [groupsMap].
+ */
+class GroupsReplacer(val pattern: Pattern,
+ private val groupsMap: List<(String) -> String>) {
+
+ /**
+ * Takes the given [matcher] and replace its matched groups using mapping functions given in
+ * [groupsMap].
+ */
+ fun runReplacements(matcher: Matcher) : String {
+ var result = matcher.group(0)
+
+ // We go intentionally backwards to replace using indexes
+ for (i in groupsMap.size - 1 downTo 0) {
+ val groupVal = matcher.group(i + 1) ?: continue
+ val localStart = matcher.start(i + 1) - matcher.start()
+ val localEnd = matcher.end(i + 1) - matcher.start()
+
+ result = result.replaceRange(
+ startIndex = localStart,
+ endIndex = localEnd,
+ replacement = groupsMap[i].invoke(groupVal))
+ }
+ return result
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/patterns/PatternHelper.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/patterns/PatternHelper.kt
new file mode 100644
index 0000000..3171185
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/patterns/PatternHelper.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard.patterns
+
+import java.util.regex.Pattern
+
+/**
+ * Helps to build regular expression [Pattern]s defined with less verbose syntax.
+ *
+ * You can use following shortcuts:
+ * 'ï½Ÿï½ ' - denotes a capturing group (normally '()' is capturing group)
+ * '()' - denotes non-capturing group (normally (?:) is non-capturing group)
+ * ' ' - denotes a whitespace characters (at least one)
+ * ' *' - denotes a whitespace characters (any)
+ * ';' - denotes ' *;'
+ */
+object PatternHelper {
+
+ private val rewrites = listOf(
+ " *" to "[\\s]*", // Optional space
+ " " to "[\\s]+", // Space
+ "⦅" to "(", // Capturing group start
+ "ï½ " to ")", // Capturing group end
+ ";" to "[\\s]*;" // Allow spaces in front of ';'
+ )
+
+ /**
+ * Transforms the given [toReplace] according to the rules defined in documentation of this
+ * class and compiles it to a [Pattern].
+ */
+ fun build(toReplace: String, flags : Int = 0) : Pattern {
+ var result = toReplace
+ result = result.replace("(?<!\\\\)\\(".toRegex(), "(?:")
+ rewrites.forEach { result = result.replace(it.first, it.second) }
+ return Pattern.compile(result, flags)
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/patterns/ReplacersRunner.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/patterns/ReplacersRunner.kt
new file mode 100644
index 0000000..54501f9
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/patterns/ReplacersRunner.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard.patterns
+
+/**
+ * Runs multiple [GroupsReplacer]s on given strings.
+ */
+class ReplacersRunner(val replacers: List<GroupsReplacer>) {
+
+ /**
+ * Runs all the [GroupsReplacer]s on the given [input].
+ *
+ * The replacers have to be distinct as this method can't guarantee that output of one replacer
+ * won't be matched by another replacer.
+ */
+ fun applyReplacers(input : String) : String {
+ val sb = StringBuilder()
+ var lastSeenChar = 0
+ var processedInput = input
+
+ for (replacer in replacers) {
+ val matcher = replacer.pattern.matcher(processedInput)
+
+ while (matcher.find()) {
+ if (lastSeenChar < matcher.start()) {
+ sb.append(input, lastSeenChar, matcher.start())
+ }
+
+ val result = replacer.runReplacements(matcher)
+ sb.append(result)
+ lastSeenChar = matcher.end()
+ }
+
+ if (lastSeenChar == 0) {
+ continue
+ }
+
+ if (lastSeenChar <= processedInput.length - 1) {
+ sb.append(processedInput, lastSeenChar, processedInput.length)
+ }
+
+ lastSeenChar = 0
+ processedInput = sb.toString()
+ sb.setLength(0)
+ }
+
+ return processedInput
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformer.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformer.kt
new file mode 100644
index 0000000..0a29828
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformer.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.resource
+
+import android.support.tools.jetifier.core.archive.ArchiveFile
+import android.support.tools.jetifier.core.map.TypesMap
+import android.support.tools.jetifier.core.rules.JavaTypeXmlRef
+import android.support.tools.jetifier.core.transform.TransformationContext
+import android.support.tools.jetifier.core.transform.Transformer
+import android.support.tools.jetifier.core.utils.Log
+import java.nio.charset.Charset
+import java.nio.charset.StandardCharsets
+import java.util.regex.Pattern
+import javax.xml.stream.XMLInputFactory
+
+/**
+ * Transformer for XML resource files.
+ *
+ * Searches for any java type reference that is pointing to the support library and rewrites it
+ * using the available mappings from [TypesMap].
+ */
+class XmlResourcesTransformer internal constructor(private val context: TransformationContext)
+ : Transformer {
+
+ companion object {
+ const val TAG = "XmlResourcesTransformer"
+
+ const val PATTERN_TYPE_GROUP = 1
+ }
+
+ /**
+ * List of regular expression patterns used to find support library references in XML files.
+ *
+ * Matches xml tags in form of:
+ * 1. '<(/)prefix(SOMETHING)'.
+ * 2. <view ... class="prefix(SOMETHING)" ...>
+ *
+ * Note that this can also rewrite commented blocks of XML. But on a library level we don't care
+ * much about comments.
+ */
+ private val patterns = listOf(
+ Pattern.compile("</?([a-zA-Z0-9.]+)"),
+ Pattern.compile("<view[^>]*class=\"([a-zA-Z0-9.\$_]+)\"[^>]*>")
+ )
+
+ private val typesMap = context.config.typesMap
+
+ override fun canTransform(file: ArchiveFile) = file.isXmlFile() && !file.isPomFile()
+
+ override fun runTransform(file: ArchiveFile) {
+ file.data = transform(file.data)
+ }
+
+ fun transform(data: ByteArray) : ByteArray {
+ var changesDone = false
+
+ val charset = getCharset(data)
+ val sb = StringBuilder(data.toString(charset))
+ for (pattern in patterns) {
+ var matcher = pattern.matcher(sb)
+ while (matcher.find()) {
+ val typeToReplace = JavaTypeXmlRef(matcher.group(PATTERN_TYPE_GROUP))
+ val result = rewriteType(typeToReplace)
+ if (result == typeToReplace) {
+ continue
+ }
+ sb.replace(matcher.start(PATTERN_TYPE_GROUP), matcher.end(PATTERN_TYPE_GROUP),
+ result.fullName)
+ changesDone = true
+ matcher = pattern.matcher(sb)
+ }
+ }
+
+ if (changesDone) {
+ return sb.toString().toByteArray(charset)
+ }
+
+ return data
+ }
+
+ fun getCharset(data: ByteArray) : Charset {
+ data.inputStream().use {
+ val xmlReader = XMLInputFactory.newInstance().createXMLStreamReader(it)
+
+ xmlReader.encoding ?: return StandardCharsets.UTF_8 // Encoding was not detected
+
+ val result = Charset.forName(xmlReader.encoding)
+ if (result == null) {
+ Log.e(TAG, "Failed to find charset for encoding '%s'", xmlReader.encoding)
+ return StandardCharsets.UTF_8
+ }
+ return result
+ }
+ }
+
+ fun rewriteType(type: JavaTypeXmlRef): JavaTypeXmlRef {
+ val javaType = type.toJavaType()
+ if (!context.isEligibleForRewrite(javaType)) {
+ return type
+ }
+
+ val result = typesMap.types[javaType]
+ if (result != null) {
+ Log.i(TAG, " map: %s -> %s", type, result)
+ return JavaTypeXmlRef(result)
+ }
+
+ context.reportNoMappingFoundFailure()
+ Log.e(TAG, "No mapping for: " + type)
+ return type
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/Log.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/Log.kt
new file mode 100644
index 0000000..902dea4
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/Log.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.utils
+
+object Log {
+
+ var currentLevel : LogLevel = LogLevel.INFO
+
+ var logConsumer : LogConsumer = StdOutLogConsumer()
+
+ fun setLevel(level: String?) {
+ currentLevel = when (level) {
+ "debug" -> LogLevel.DEBUG
+ "verbose" -> LogLevel.VERBOSE
+ else -> LogLevel.INFO
+ }
+
+ }
+
+ fun e(tag: String, message: String, vararg args: Any?) {
+ if (currentLevel >= LogLevel.ERROR) {
+ logConsumer.error("[$tag] $message".format(*args))
+ }
+ }
+
+ fun d(tag: String, message: String, vararg args: Any?) {
+ if (currentLevel >= LogLevel.DEBUG) {
+ logConsumer.debug("[$tag] $message".format(*args))
+ }
+ }
+
+ fun i(tag: String, message: String, vararg args: Any?) {
+ if (currentLevel >= LogLevel.INFO) {
+ logConsumer.info("[$tag] $message".format(*args))
+ }
+ }
+
+ fun v(tag: String, message: String, vararg args: Any?) {
+ if (currentLevel >= LogLevel.VERBOSE) {
+ logConsumer.verbose("[$tag] $message".format(*args))
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/LogConsumer.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/LogConsumer.kt
new file mode 100644
index 0000000..ddebd25
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/LogConsumer.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.utils
+
+/**
+ * Interface to plug custom logs consumers to [Log].
+ */
+interface LogConsumer {
+
+ fun error(message: String)
+
+ fun info(message: String)
+
+ fun verbose(message: String)
+
+ fun debug(message: String)
+
+}
+
diff --git a/buildSrc/src/main/kotlin/android/support/KotlinNoOp.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/LogLevel.kt
similarity index 62%
copy from buildSrc/src/main/kotlin/android/support/KotlinNoOp.kt
copy to jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/LogLevel.kt
index 968f6ca..f46b8f6 100644
--- a/buildSrc/src/main/kotlin/android/support/KotlinNoOp.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/LogLevel.kt
@@ -1,24 +1,24 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright (C) 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
+ * 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.
+ * limitations under the License
*/
-package android.support
+package android.support.tools.jetifier.core.utils
-class KotlinNoOp {
-
- fun noOp() {
- }
-
+enum class LogLevel(val priority : Int) {
+ ERROR(0),
+ INFO(1),
+ VERBOSE(2),
+ DEBUG(3),
}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/StdOutLogConsumer.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/StdOutLogConsumer.kt
new file mode 100644
index 0000000..7cfd25e
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/StdOutLogConsumer.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.utils
+
+/**
+ * Prints logs to the standard output.
+ */
+class StdOutLogConsumer : LogConsumer {
+
+ override fun error(message: String) {
+ println("ERROR: $message")
+ }
+
+ override fun info(message: String) {
+ println("INFO: $message")
+ }
+
+ override fun verbose(message: String) {
+ println("VERBOSE: $message")
+ }
+
+ override fun debug(message: String) {
+ println("DEBUG: $message")
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/resources/default.config b/jetifier/jetifier/core/src/main/resources/default.config
new file mode 100644
index 0000000..a95f7cb
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/resources/default.config
@@ -0,0 +1,251 @@
+# Copyright (C) 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
+
+{
+ # Skip packages that don't match the following regex
+ restrictToPackagePrefixes: [
+ "android/support/"
+ ],
+ rules: [
+ {
+ from: "android/support/design/widget/CoordinatorLayout",
+ to: "androidx/widget/CoordinatorLayout"
+ },
+ {
+ from: "android/support/design/widget/DirectedAcyclicGraph",
+ to: "androidx/widget/DirectedAcyclicGraph"
+ },
+ {
+ from: "android/support/design/widget/ViewGroupUtils",
+ to: "androidx/widget/ViewGroupUtils"
+ },
+ {
+ from: "android/support/v4/view/ViewPager",
+ to: "androidx/widget/ViewPager"
+ },
+ {
+ from: "android/support/v4/view/PagerAdapter",
+ to: "androidx/widget/PagerAdapter"
+ },
+ {
+ from: "android/support/v4/view/PagerTabStrip",
+ to: "androidx/widget/PagerTabStrip"
+ },
+ {
+ from: "android/support/v4/view/PagerTitleStrip",
+ to: "androidx/widget/PagerTitleStrip"
+ },
+ {
+ from: "android/support/v17/preference/(.*)",
+ to: "androidx/leanback/preference/{0}"
+ },
+ {
+ from: "android/support/customtabs/(.*)",
+ to: "androidx/browser/customtabs/{0}"
+ },
+ {
+ from: "android/support/v4/(.*)",
+ to: "androidx/{0}"
+ },
+ {
+ from: "android/support/v7/graphics/ColorCutQuantizer",
+ to: "androidx/graphics/palette/ColorCutQuantizer"
+ },
+ {
+ from: "android/support/v7/graphics/Palette",
+ to: "androidx/graphics/palette/Palette"
+ },
+ {
+ from: "android/support/v7/graphics/Target",
+ to: "androidx/graphics/palette/Target"
+ },
+ {
+ from: "android/support/v7/(.*)",
+ to: "androidx/{0}"
+ },
+ {
+ from: "android/support/v13/(.*)",
+ to: "androidx/{0}"
+ },
+ {
+ from: "android/support/v14/(.*)",
+ to: "androidx/{0}"
+ },
+ {
+ from: "android/support/v17/(.*)",
+ to: "androidx/{0}"
+ },
+ {
+ from: "android/support/percent/(.*)",
+ to: "androidx/{0}"
+ },
+ {
+ from: "android/support/(.*)",
+ to: "androidx/{0}"
+ },
+ {
+ from: "android/arch/(.*)",
+ to: "androidx/{0}"
+ }
+ ],
+ pomRules: [
+ {
+ from: { groupId: "com.android.support", artifactId: "animated-vector-drawable", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "animated-vector-drawable", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "appcompat-v7", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "appcompat", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "cardview-v7", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "cardview", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "customtabs", version: "27.0.1" },
+ to: [{ groupId: "com.androidx.browser", artifactId: "customtabs", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "design", version: "27.0.1" },
+ to: [
+ { groupId: "com.androidx", artifactId: "design", version: "28.0.0" },
+ { groupId: "com.androidx", artifactId: "widget", version: "28.0.0" }
+ ]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "exifinterface", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "exifinterface", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "gridlayout-v7", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "gridlayout", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "instantvideo", version: "26.0.0-alpha1" },
+ to: [{ groupId: "com.androidx", artifactId: "instantvideo", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "leanback-v17", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "leanback", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "multidex", version: "1.0.2" },
+ to: [{ groupId: "com.androidx", artifactId: "multidex", version: "2.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "multidex-instrumentation", version: "1.0.2" },
+ to: [{ groupId: "com.androidx", artifactId: "multidex-instrumentation", version: "2.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "palette-v7", version: "27.0.1" },
+ to: [{ groupId: "com.androidx.graphics", artifactId: "palette", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "percent", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "widget", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "preference-leanback-v17", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "preference-leanback", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "preference-v14", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "preference", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "preference-v7", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "preference", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "recommendation", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "recommendation", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "recyclerview-v7", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "recyclerview", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-annotations", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "annotations", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-compat", version: "27.0.1" },
+ to: [{ groupId: "com.androidx.browser", artifactId: "compat", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-content", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "content", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-core-ui", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "core-ui", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-core-utils", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "core-utils", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-dynamic-animation", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "dynamic-animation", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-emoji", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "emoji", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-emoji-appcompat", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "emoji-appcompat", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-emoji-bundled", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "emoji-bundled", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-fragment", version: "27.0.1" },
+ to: [{ groupId: "com.androidx.browser", artifactId: "fragment", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-media-compat", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "media-compat", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-tv-provider", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "tv-provider", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-v13", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "androidx", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-v4", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "androidx", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "support-vector-drawable", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "vector-drawable", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "transition", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "transition", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "wear", version: "27.0.1" },
+ to: [{ groupId: "com.androidx", artifactId: "wear", version: "28.0.0" }]
+ },
+ {
+ from: { groupId: "com.android.support", artifactId: "wearable", version: "26.0.0-alpha1" },
+ to: [{ groupId: "com.androidx", artifactId: "wearable", version: "28.0.0" }]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/resources/default.generated.config b/jetifier/jetifier/core/src/main/resources/default.generated.config
new file mode 100644
index 0000000..3965e19
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/resources/default.generated.config
@@ -0,0 +1,14526 @@
+# Copyright (C) 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
+
+# DO NOT EDIT MANUALLY! This file was auto-generated using Jetifier preprocessor.
+# To make some changes in the configuration edit "default.config" and run
+# preprocessor/scripts/processDefaultConfig.sh script to update this file.
+
+{
+ "restrictToPackagePrefixes": [
+ "android/support/"
+ ],
+ "rules": [
+ {
+ "from": "android/support/design/widget/CoordinatorLayout",
+ "to": "androidx/widget/CoordinatorLayout",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/design/widget/DirectedAcyclicGraph",
+ "to": "androidx/widget/DirectedAcyclicGraph",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/design/widget/ViewGroupUtils",
+ "to": "androidx/widget/ViewGroupUtils",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/v4/view/ViewPager",
+ "to": "androidx/widget/ViewPager",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/v4/view/PagerAdapter",
+ "to": "androidx/widget/PagerAdapter",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/v4/view/PagerTabStrip",
+ "to": "androidx/widget/PagerTabStrip",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/v4/view/PagerTitleStrip",
+ "to": "androidx/widget/PagerTitleStrip",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/v17/preference/(.*)",
+ "to": "androidx/leanback/preference/{0}",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/customtabs/(.*)",
+ "to": "androidx/browser/customtabs/{0}",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/v4/(.*)",
+ "to": "androidx/{0}",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/v7/graphics/ColorCutQuantizer",
+ "to": "androidx/graphics/palette/ColorCutQuantizer",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/v7/graphics/Palette",
+ "to": "androidx/graphics/palette/Palette",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/v7/graphics/Target",
+ "to": "androidx/graphics/palette/Target",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/v7/(.*)",
+ "to": "androidx/{0}",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/v13/(.*)",
+ "to": "androidx/{0}",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/v14/(.*)",
+ "to": "androidx/{0}",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/v17/(.*)",
+ "to": "androidx/{0}",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/percent/(.*)",
+ "to": "androidx/{0}",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/support/(.*)",
+ "to": "androidx/{0}",
+ "fieldSelectors": []
+ },
+ {
+ "from": "android/arch/(.*)",
+ "to": "androidx/{0}",
+ "fieldSelectors": []
+ }
+ ],
+ "pomRules": [
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "animated-vector-drawable",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "animated-vector-drawable",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "appcompat-v7",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "appcompat",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "cardview-v7",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "cardview",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "customtabs",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx.browser",
+ "artifactId": "customtabs",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "design",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "design",
+ "version": "28.0.0"
+ },
+ {
+ "groupId": "com.androidx",
+ "artifactId": "widget",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "exifinterface",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "exifinterface",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "gridlayout-v7",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "gridlayout",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "instantvideo",
+ "version": "26.0.0-alpha1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "instantvideo",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "leanback-v17",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "leanback",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "multidex",
+ "version": "1.0.2"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "multidex",
+ "version": "2.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "multidex-instrumentation",
+ "version": "1.0.2"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "multidex-instrumentation",
+ "version": "2.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "palette-v7",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx.graphics",
+ "artifactId": "palette",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "percent",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "widget",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "preference-leanback-v17",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "preference-leanback",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "preference-v14",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "preference",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "preference-v7",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "preference",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "recommendation",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "recommendation",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "recyclerview-v7",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "recyclerview",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-annotations",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "annotations",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-compat",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx.browser",
+ "artifactId": "compat",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-content",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "content",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-core-ui",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "core-ui",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-core-utils",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "core-utils",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-dynamic-animation",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "dynamic-animation",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-emoji",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "emoji",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-emoji-appcompat",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "emoji-appcompat",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-emoji-bundled",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "emoji-bundled",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-fragment",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx.browser",
+ "artifactId": "fragment",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-media-compat",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "media-compat",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-tv-provider",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "tv-provider",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-v13",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "androidx",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-v4",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "androidx",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "support-vector-drawable",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "vector-drawable",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "transition",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "transition",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "wear",
+ "version": "27.0.1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "wear",
+ "version": "28.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
+ "artifactId": "wearable",
+ "version": "26.0.0-alpha1"
+ },
+ "to": [
+ {
+ "groupId": "com.androidx",
+ "artifactId": "wearable",
+ "version": "28.0.0"
+ }
+ ]
+ }
+ ],
+ "map": {
+ "types": {
+ "android/support/v4/provider/FontsContractCompat$Columns": "androidx/provider/FontsContractCompat$Columns",
+ "android/support/design/widget/AppBarLayout$Behavior$SavedState": "androidx/design/widget/AppBarLayout$Behavior$SavedState",
+ "android/support/v4/internal/view/SupportMenu": "androidx/internal/view/SupportMenu",
+ "android/support/v4/media/MediaDescriptionCompat": "androidx/media/MediaDescriptionCompat",
+ "android/support/transition/ChangeTransform$GhostListener": "androidx/transition/ChangeTransform$GhostListener",
+ "android/support/design/widget/BaseTransientBottomBar$BaseCallback": "androidx/design/widget/BaseTransientBottomBar$BaseCallback",
+ "android/support/v4/print/PrintHelper$ColorMode": "androidx/print/PrintHelper$ColorMode",
+ "android/support/annotation/RequiresPermission$Write": "androidx/annotation/RequiresPermission$Write",
+ "android/support/v7/widget/FastScroller$AnimatorUpdater": "androidx/widget/FastScroller$AnimatorUpdater",
+ "android/support/multidex/MultiDex$V14": "androidx/multidex/MultiDex$V14",
+ "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentAdapterRegistry": "androidx/leanback/app/BrowseSupportFragment$MainFragmentAdapterRegistry",
+ "android/support/v7/preference/PreferenceDataStore": "androidx/preference/PreferenceDataStore",
+ "android/support/v17/leanback/app/DetailsBackgroundVideoHelper$PlaybackControlStateCallback": "androidx/leanback/app/DetailsBackgroundVideoHelper$PlaybackControlStateCallback",
+ "android/support/v4/content/LocalBroadcastManager": "androidx/content/LocalBroadcastManager",
+ "android/support/v7/view/ActionBarPolicy": "androidx/view/ActionBarPolicy",
+ "android/support/v4/content/Loader$OnLoadCanceledListener": "androidx/content/Loader$OnLoadCanceledListener",
+ "android/support/v4/view/GestureDetectorCompat$GestureDetectorCompatImplBase": "androidx/view/GestureDetectorCompat$GestureDetectorCompatImplBase",
+ "android/support/v4/app/SharedElementCallback$OnSharedElementsReadyListener": "androidx/app/SharedElementCallback$OnSharedElementsReadyListener",
+ "android/support/v7/app/MediaRouteVolumeSlider": "androidx/app/MediaRouteVolumeSlider",
+ "android/support/multidex/MultiDex$V19": "androidx/multidex/MultiDex$V19",
+ "android/support/v17/leanback/widget/StaggeredGridDefault": "androidx/leanback/widget/StaggeredGridDefault",
+ "android/support/v17/leanback/widget/GuidedActionAdapter$ActionOnKeyListener": "androidx/leanback/widget/GuidedActionAdapter$ActionOnKeyListener",
+ "android/support/design/widget/BottomNavigationView$OnNavigationItemReselectedListener": "androidx/design/widget/BottomNavigationView$OnNavigationItemReselectedListener",
+ "android/support/app/recommendation/ContentRecommendation$ContentPricing": "androidx/app/recommendation/ContentRecommendation$ContentPricing",
+ "android/support/v17/leanback/widget/BaseCardView$LayoutParams": "androidx/leanback/widget/BaseCardView$LayoutParams",
+ "android/support/text/emoji/MetadataListReader": "androidx/text/emoji/MetadataListReader",
+ "android/support/v7/appcompat/R$drawable": "androidx/appcompat/R$drawable",
+ "android/support/design/widget/BaseTransientBottomBar$OnAttachStateChangeListener": "androidx/design/widget/BaseTransientBottomBar$OnAttachStateChangeListener",
+ "android/support/v4/view/GravityCompat": "androidx/view/GravityCompat",
+ "android/support/v7/view/menu/SubMenuWrapperICS": "androidx/view/menu/SubMenuWrapperICS",
+ "android/support/graphics/drawable/VectorDrawableCompat": "androidx/graphics/drawable/VectorDrawableCompat",
+ "android/support/v4/view/AsyncLayoutInflater$InflateRequest": "androidx/view/AsyncLayoutInflater$InflateRequest",
+ "android/support/v17/leanback/app/HeadersFragment$NoOverlappingFrameLayout": "androidx/leanback/app/HeadersFragment$NoOverlappingFrameLayout",
+ "android/support/v17/leanback/widget/ShadowHelperJbmr2": "androidx/leanback/widget/ShadowHelperJbmr2",
+ "android/support/design/internal/ScrimInsetsFrameLayout": "androidx/design/internal/ScrimInsetsFrameLayout",
+ "android/support/v17/leanback/widget/HorizontalHoverCardSwitcher": "androidx/leanback/widget/HorizontalHoverCardSwitcher",
+ "android/support/v7/widget/RecyclerView$Recycler": "androidx/widget/RecyclerView$Recycler",
+ "android/support/v7/widget/FastScroller$State": "androidx/widget/FastScroller$State",
+ "android/support/v7/media/SystemMediaRouteProvider$JellybeanMr2Impl": "androidx/media/SystemMediaRouteProvider$JellybeanMr2Impl",
+ "android/support/wear/R$id": "androidx/wear/R$id",
+ "android/support/v17/leanback/widget/FocusHighlight": "androidx/leanback/widget/FocusHighlight",
+ "android/support/v7/view/menu/ExpandedMenuView": "androidx/view/menu/ExpandedMenuView",
+ "android/support/graphics/drawable/PathInterpolatorCompat": "androidx/graphics/drawable/PathInterpolatorCompat",
+ "android/support/v17/leanback/widget/MediaItemActionPresenter": "androidx/leanback/widget/MediaItemActionPresenter",
+ "android/support/v4/content/Loader$OnLoadCompleteListener": "androidx/content/Loader$OnLoadCompleteListener",
+ "android/support/v17/leanback/widget/NonOverlappingLinearLayout": "androidx/leanback/widget/NonOverlappingLinearLayout",
+ "android/support/v7/view/menu/MenuItemWrapperICS$CollapsibleActionViewWrapper": "androidx/view/menu/MenuItemWrapperICS$CollapsibleActionViewWrapper",
+ "android/support/v4/widget/SlidingPaneLayout$SlidingPanelLayoutImplJB": "androidx/widget/SlidingPaneLayout$SlidingPanelLayoutImplJB",
+ "android/support/v17/leanback/app/ErrorFragment": "androidx/leanback/app/ErrorFragment",
+ "android/support/v7/view/menu/MenuItemWrapperICS$OnActionExpandListenerWrapper": "androidx/view/menu/MenuItemWrapperICS$OnActionExpandListenerWrapper",
+ "android/support/v7/app/AppCompatActivity": "androidx/app/AppCompatActivity",
+ "android/support/v17/preference/LeanbackSettingsFragment$DummyFragment": "androidx/leanback/preference/LeanbackSettingsFragment$DummyFragment",
+ "android/support/app/recommendation/ContentRecommendation$IntentType": "androidx/app/recommendation/ContentRecommendation$IntentType",
+ "android/support/v17/leanback/widget/PlaybackControlsRowView": "androidx/leanback/widget/PlaybackControlsRowView",
+ "android/support/v4/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicLocale": "androidx/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicLocale",
+ "android/support/v4/util/SparseArrayCompat": "androidx/util/SparseArrayCompat",
+ "android/support/v4/net/TrafficStatsCompat": "androidx/net/TrafficStatsCompat",
+ "android/support/design/widget/TabLayout$Tab": "androidx/design/widget/TabLayout$Tab",
+ "android/support/v7/view/CollapsibleActionView": "androidx/view/CollapsibleActionView",
+ "android/support/v17/leanback/R$id": "androidx/leanback/R$id",
+ "android/support/v4/content/MimeTypeFilter": "androidx/content/MimeTypeFilter",
+ "android/support/media/tv/TvContractCompat$WatchNextPrograms$WatchNextType": "androidx/media/tv/TvContractCompat$WatchNextPrograms$WatchNextType",
+ "android/support/transition/ViewUtilsImpl": "androidx/transition/ViewUtilsImpl",
+ "android/support/v17/leanback/app/DetailsFragment$SetSelectionRunnable": "androidx/leanback/app/DetailsFragment$SetSelectionRunnable",
+ "android/support/v7/app/MediaRouteControllerDialog$ClickListener": "androidx/app/MediaRouteControllerDialog$ClickListener",
+ "android/support/design/widget/VisibilityAwareImageButton": "androidx/design/widget/VisibilityAwareImageButton",
+ "android/support/transition/ViewGroupUtilsImpl": "androidx/transition/ViewGroupUtilsImpl",
+ "android/support/design/internal/package-info": "androidx/design/internal/package-info",
+ "android/support/v7/widget/SearchView$SearchAutoComplete": "androidx/widget/SearchView$SearchAutoComplete",
+ "android/support/v17/leanback/widget/GuidedActionAdapterGroup": "androidx/leanback/widget/GuidedActionAdapterGroup",
+ "android/support/v7/widget/AppCompatBackgroundHelper": "androidx/widget/AppCompatBackgroundHelper",
+ "android/support/v4/widget/EdgeEffectCompat$EdgeEffectApi21Impl": "androidx/widget/EdgeEffectCompat$EdgeEffectApi21Impl",
+ "android/support/v17/leanback/R$fraction": "androidx/leanback/R$fraction",
+ "android/support/wear/widget/drawer/WearableActionDrawerMenu": "androidx/wear/widget/drawer/WearableActionDrawerMenu",
+ "android/support/v4/content/IntentCompat": "androidx/content/IntentCompat",
+ "android/support/compat/R": "androidx/compat/R",
+ "android/support/v7/widget/RecyclerView$ViewCacheExtension": "androidx/widget/RecyclerView$ViewCacheExtension",
+ "android/support/v7/widget/DecorContentParent": "androidx/widget/DecorContentParent",
+ "android/support/design/widget/BaseTransientBottomBar$Behavior": "androidx/design/widget/BaseTransientBottomBar$Behavior",
+ "android/support/design/widget/TabLayout$ViewPagerOnTabSelectedListener": "androidx/design/widget/TabLayout$ViewPagerOnTabSelectedListener",
+ "android/support/v7/preference/EditTextPreference$SavedState": "androidx/preference/EditTextPreference$SavedState",
+ "android/support/design/widget/ShadowViewDelegate": "androidx/design/widget/ShadowViewDelegate",
+ "android/support/v7/cardview/BuildConfig": "androidx/cardview/BuildConfig",
+ "android/support/v7/app/AlertController$ButtonHandler": "androidx/app/AlertController$ButtonHandler",
+ "android/support/v4/widget/AutoScrollHelper$ScrollAnimationRunnable": "androidx/widget/AutoScrollHelper$ScrollAnimationRunnable",
+ "android/support/v7/view/menu/ShowableListMenu": "androidx/view/menu/ShowableListMenu",
+ "android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper": "androidx/leanback/widget/DetailsOverviewSharedElementHelper",
+ "android/support/v7/widget/MenuPopupWindow$MenuDropDownListView": "androidx/widget/MenuPopupWindow$MenuDropDownListView",
+ "android/support/v17/leanback/transition/LeanbackTransitionHelper": "androidx/leanback/transition/LeanbackTransitionHelper",
+ "android/support/design/widget/BottomSheetDialogFragment": "androidx/design/widget/BottomSheetDialogFragment",
+ "android/support/v4/app/NotificationCompat$Extender": "androidx/app/NotificationCompat$Extender",
+ "android/support/v4/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicInternal": "androidx/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicInternal",
+ "android/support/wear/widget/SwipeDismissLayout$OnPreSwipeListener": "androidx/wear/widget/SwipeDismissLayout$OnPreSwipeListener",
+ "android/support/v4/graphics/BitmapCompat$BitmapCompatApi18Impl": "androidx/graphics/BitmapCompat$BitmapCompatApi18Impl",
+ "android/support/v4/view/ViewCompat$AutofillImportance": "androidx/view/ViewCompat$AutofillImportance",
+ "android/support/v4/app/AppOpsManagerCompat": "androidx/app/AppOpsManagerCompat",
+ "android/support/annotation/FractionRes": "androidx/annotation/FractionRes",
+ "android/support/media/instantvideo/widget/InstantVideoView": "androidx/media/instantvideo/widget/InstantVideoView",
+ "android/support/design/internal/NavigationMenuPresenter$NormalViewHolder": "androidx/design/internal/NavigationMenuPresenter$NormalViewHolder",
+ "android/support/v4/view/accessibility/AccessibilityRecordCompat": "androidx/view/accessibility/AccessibilityRecordCompat",
+ "android/support/v7/view/menu/MenuWrapperFactory": "androidx/view/menu/MenuWrapperFactory",
+ "android/support/v17/leanback/app/HeadersSupportFragment$NoOverlappingFrameLayout": "androidx/leanback/app/HeadersSupportFragment$NoOverlappingFrameLayout",
+ "android/support/v7/widget/ScrollingTabContainerView$VisibilityAnimListener": "androidx/widget/ScrollingTabContainerView$VisibilityAnimListener",
+ "android/support/v7/internal/package-info": "androidx/internal/package-info",
+ "android/support/v4/media/MediaBrowserServiceCompatApi26$ResultWrapper": "androidx/media/MediaBrowserServiceCompatApi26$ResultWrapper",
+ "android/support/v4/media/MediaBrowserServiceCompat$ResultFlags": "androidx/media/MediaBrowserServiceCompat$ResultFlags",
+ "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi21$ExtraBinderRequestResultReceiver": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi21$ExtraBinderRequestResultReceiver",
+ "android/support/v17/leanback/widget/OnChildSelectedListener": "androidx/leanback/widget/OnChildSelectedListener",
+ "android/support/v7/mediarouter/BuildConfig": "androidx/mediarouter/BuildConfig",
+ "android/support/v4/os/LocaleListHelper": "androidx/os/LocaleListHelper",
+ "android/support/v7/widget/ChildHelper": "androidx/widget/ChildHelper",
+ "android/support/v17/leanback/widget/BaseOnItemViewClickedListener": "androidx/leanback/widget/BaseOnItemViewClickedListener",
+ "android/support/v17/leanback/widget/VerticalGridPresenter": "androidx/leanback/widget/VerticalGridPresenter",
+ "android/support/v7/widget/Toolbar$LayoutParams": "androidx/widget/Toolbar$LayoutParams",
+ "android/support/v4/provider/SelfDestructiveThread": "androidx/provider/SelfDestructiveThread",
+ "android/support/v17/leanback/widget/DetailsParallax": "androidx/leanback/widget/DetailsParallax",
+ "android/support/v4/content/pm/ActivityInfoCompat": "androidx/content/pm/ActivityInfoCompat",
+ "android/support/percent/PercentFrameLayout$LayoutParams": "androidx/PercentFrameLayout$LayoutParams",
+ "android/support/v7/widget/RecyclerView$ItemAnimator$ItemAnimatorFinishedListener": "androidx/widget/RecyclerView$ItemAnimator$ItemAnimatorFinishedListener",
+ "android/support/v4/media/MediaBrowserCompat$ConnectionCallback": "androidx/media/MediaBrowserCompat$ConnectionCallback",
+ "android/support/design/widget/ThemeUtils": "androidx/design/widget/ThemeUtils",
+ "android/support/wear/widget/drawer/RecyclerViewFlingWatcher": "androidx/wear/widget/drawer/RecyclerViewFlingWatcher",
+ "android/support/v4/app/SupportActivity": "androidx/app/SupportActivity",
+ "android/support/transition/TransitionUtils": "androidx/transition/TransitionUtils",
+ "android/support/v4/graphics/TypefaceCompatApi21Impl": "androidx/graphics/TypefaceCompatApi21Impl",
+ "android/support/v7/media/MediaRouter$CallbackRecord": "androidx/media/MediaRouter$CallbackRecord",
+ "android/support/wear/widget/drawer/NestedScrollViewFlingWatcher": "androidx/wear/widget/drawer/NestedScrollViewFlingWatcher",
+ "android/support/v4/graphics/drawable/TintAwareDrawable": "androidx/graphics/drawable/TintAwareDrawable",
+ "android/support/text/emoji/widget/EmojiTextViewHelper$HelperInternal": "androidx/text/emoji/widget/EmojiTextViewHelper$HelperInternal",
+ "android/support/transition/Styleable": "androidx/transition/Styleable",
+ "android/support/v17/leanback/widget/BaseCardView": "androidx/leanback/widget/BaseCardView",
+ "android/support/v17/leanback/app/DetailsSupportFragment": "androidx/leanback/app/DetailsSupportFragment",
+ "android/support/design/internal/NavigationMenuPresenter$NavigationMenuSeparatorItem": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuSeparatorItem",
+ "android/support/app/recommendation/ContentRecommendation$IntentData": "androidx/app/recommendation/ContentRecommendation$IntentData",
+ "android/support/wear/widget/drawer/WearableDrawerLayout$DrawerStateCallback": "androidx/wear/widget/drawer/WearableDrawerLayout$DrawerStateCallback",
+ "android/support/wear/widget/CircularProgressLayoutController$CircularProgressTimer": "androidx/wear/widget/CircularProgressLayoutController$CircularProgressTimer",
+ "android/support/v4/widget/CircleImageView": "androidx/widget/CircleImageView",
+ "android/support/v17/leanback/app/BaseRowFragment": "androidx/leanback/app/BaseRowFragment",
+ "android/support/text/emoji/EmojiCompat$ReplaceStrategy": "androidx/text/emoji/EmojiCompat$ReplaceStrategy",
+ "android/support/v7/widget/ViewInfoStore$InfoRecord": "androidx/widget/ViewInfoStore$InfoRecord",
+ "android/support/transition/TransitionInflater": "androidx/transition/TransitionInflater",
+ "android/support/v17/leanback/media/PlaybackControlGlue$UpdatePlaybackStateHandler": "androidx/leanback/media/PlaybackControlGlue$UpdatePlaybackStateHandler",
+ "android/support/v7/widget/RecyclerView$State$LayoutState": "androidx/widget/RecyclerView$State$LayoutState",
+ "android/support/v17/leanback/widget/RoundedRectHelper": "androidx/leanback/widget/RoundedRectHelper",
+ "android/support/v4/app/ServiceCompat": "androidx/app/ServiceCompat",
+ "android/support/percent/PercentRelativeLayout$LayoutParams": "androidx/PercentRelativeLayout$LayoutParams",
+ "android/support/v17/leanback/widget/RowHeaderPresenter": "androidx/leanback/widget/RowHeaderPresenter",
+ "android/support/v7/widget/SearchView$UpdatableTouchDelegate": "androidx/widget/SearchView$UpdatableTouchDelegate",
+ "android/support/media/tv/TvContractCompat$PreviewProgramColumns$AspectRatio": "androidx/media/tv/TvContractCompat$PreviewProgramColumns$AspectRatio",
+ "android/support/text/emoji/EmojiMetadata$HasGlyph": "androidx/text/emoji/EmojiMetadata$HasGlyph",
+ "android/support/media/tv/BasePreviewProgram$Builder": "androidx/media/tv/BasePreviewProgram$Builder",
+ "android/support/multidex/ZipUtil$CentralDirectory": "androidx/multidex/ZipUtil$CentralDirectory",
+ "android/support/v7/widget/helper/ItemTouchUIUtil": "androidx/widget/helper/ItemTouchUIUtil",
+ "android/support/v4/widget/DrawerLayout$ChildAccessibilityDelegate": "androidx/widget/DrawerLayout$ChildAccessibilityDelegate",
+ "android/support/v7/media/SystemMediaRouteProvider": "androidx/media/SystemMediaRouteProvider",
+ "android/support/v4/app/LoaderManagerImpl": "androidx/app/LoaderManagerImpl",
+ "android/support/media/ExifInterface$IfdType": "androidx/media/ExifInterface$IfdType",
+ "android/support/v4/widget/CompoundButtonCompat$CompoundButtonCompatBaseImpl": "androidx/widget/CompoundButtonCompat$CompoundButtonCompatBaseImpl",
+ "android/support/v4/graphics/drawable/DrawableWrapperApi14": "androidx/graphics/drawable/DrawableWrapperApi14",
+ "android/support/wear/widget/drawer/WearableDrawerLayout$BottomDrawerDraggerCallback": "androidx/wear/widget/drawer/WearableDrawerLayout$BottomDrawerDraggerCallback",
+ "android/support/v4/view/TintableBackgroundView": "androidx/view/TintableBackgroundView",
+ "android/support/v17/leanback/graphics/BoundsRule": "androidx/leanback/graphics/BoundsRule",
+ "android/support/v17/leanback/widget/RecyclerViewParallax$ChildPositionProperty": "androidx/leanback/widget/RecyclerViewParallax$ChildPositionProperty",
+ "android/support/v4/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicImpl": "androidx/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicImpl",
+ "android/support/v17/leanback/widget/PlaybackControlsPresenter": "androidx/leanback/widget/PlaybackControlsPresenter",
+ "android/support/v7/app/ActionBarDrawerToggle": "androidx/app/ActionBarDrawerToggle",
+ "android/support/design/internal/BaselineLayout": "androidx/design/internal/BaselineLayout",
+ "android/support/v7/preference/PreferenceScreen": "androidx/preference/PreferenceScreen",
+ "android/support/v4/graphics/drawable/DrawableWrapperApi19": "androidx/graphics/drawable/DrawableWrapperApi19",
+ "android/support/v17/leanback/app/DetailsFragment": "androidx/leanback/app/DetailsFragment",
+ "android/support/annotation/ColorLong": "androidx/annotation/ColorLong",
+ "android/support/annotation/IntRange": "androidx/annotation/IntRange",
+ "android/support/v7/widget/LinearLayoutCompat$DividerMode": "androidx/widget/LinearLayoutCompat$DividerMode",
+ "android/support/annotation/RestrictTo": "androidx/annotation/RestrictTo",
+ "android/support/v4/media/session/PlaybackStateCompat": "androidx/media/session/PlaybackStateCompat",
+ "android/support/v17/leanback/widget/RecyclerViewParallax": "androidx/leanback/widget/RecyclerViewParallax",
+ "android/support/v7/widget/ChildHelper$Callback": "androidx/widget/ChildHelper$Callback",
+ "android/support/v17/leanback/widget/DetailsOverviewLogoPresenter": "androidx/leanback/widget/DetailsOverviewLogoPresenter",
+ "android/support/constraint/Guideline": "androidx/constraint/Guideline",
+ "android/support/design/widget/CircularBorderDrawable": "androidx/design/widget/CircularBorderDrawable",
+ "android/support/text/emoji/widget/EmojiInputConnection": "androidx/text/emoji/widget/EmojiInputConnection",
+ "android/support/v4/widget/ImageViewCompat$ImageViewCompatImpl": "androidx/widget/ImageViewCompat$ImageViewCompatImpl",
+ "android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper": "androidx/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper",
+ "android/support/v7/view/menu/MenuBuilder": "androidx/view/menu/MenuBuilder",
+ "android/support/v7/media/MediaRouteDiscoveryRequest": "androidx/media/MediaRouteDiscoveryRequest",
+ "android/support/design/widget/AppBarLayout$ScrollingViewBehavior": "androidx/design/widget/AppBarLayout$ScrollingViewBehavior",
+ "android/support/v17/leanback/widget/PersistentFocusWrapper$SavedState": "androidx/leanback/widget/PersistentFocusWrapper$SavedState",
+ "android/support/v7/widget/RecyclerView$ItemAnimator$ItemAnimatorListener": "androidx/widget/RecyclerView$ItemAnimator$ItemAnimatorListener",
+ "android/support/v17/leanback/media/PlaybackBannerControlGlue": "androidx/leanback/media/PlaybackBannerControlGlue",
+ "android/support/design/internal/NavigationMenuPresenter$ViewHolder": "androidx/design/internal/NavigationMenuPresenter$ViewHolder",
+ "android/support/v7/widget/AppCompatDrawableManager$VdcInflateDelegate": "androidx/widget/AppCompatDrawableManager$VdcInflateDelegate",
+ "android/support/graphics/drawable/AndroidResources": "androidx/graphics/drawable/AndroidResources",
+ "android/support/v7/widget/RecyclerView$RecyclerViewDataObserver": "androidx/widget/RecyclerView$RecyclerViewDataObserver",
+ "android/support/design/R$integer": "androidx/design/R$integer",
+ "android/support/v4/app/AppLaunchChecker": "androidx/app/AppLaunchChecker",
+ "android/support/design/BuildConfig": "androidx/design/BuildConfig",
+ "android/support/v17/leanback/transition/ParallaxTransition": "androidx/leanback/transition/ParallaxTransition",
+ "android/support/text/emoji/widget/SpannableBuilder": "androidx/text/emoji/widget/SpannableBuilder",
+ "android/support/text/emoji/widget/ExtractButtonCompat": "androidx/text/emoji/widget/ExtractButtonCompat",
+ "android/support/v17/leanback/app/ListRowDataAdapter$QueueBasedDataObserver": "androidx/leanback/app/ListRowDataAdapter$QueueBasedDataObserver",
+ "android/support/content/ContentPager$QueryRunner": "androidx/content/ContentPager$QueryRunner",
+ "android/support/v4/app/FragmentTabHost$SavedState": "androidx/app/FragmentTabHost$SavedState",
+ "android/support/v7/widget/OpReorderer$Callback": "androidx/widget/OpReorderer$Callback",
+ "android/support/multidex/MultiDexExtractor$ExtractedDex": "androidx/multidex/MultiDexExtractor$ExtractedDex",
+ "android/support/design/widget/SwipeDismissBehavior": "androidx/design/widget/SwipeDismissBehavior",
+ "android/support/v4/content/FileProvider": "androidx/content/FileProvider",
+ "android/support/v17/leanback/app/BrowseFragment$BrowseTransitionListener": "androidx/leanback/app/BrowseFragment$BrowseTransitionListener",
+ "android/support/design/widget/ViewOffsetBehavior": "androidx/design/widget/ViewOffsetBehavior",
+ "android/support/v17/leanback/app/ListRowDataAdapter$SimpleDataObserver": "androidx/leanback/app/ListRowDataAdapter$SimpleDataObserver",
+ "android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat": "androidx/accessibilityservice/AccessibilityServiceInfoCompat",
+ "android/support/v7/widget/ScrollbarHelper": "androidx/widget/ScrollbarHelper",
+ "android/support/v17/leanback/widget/BaseCardView$InfoAlphaAnimation": "androidx/leanback/widget/BaseCardView$InfoAlphaAnimation",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$RepeatAction": "androidx/leanback/widget/PlaybackControlsRow$RepeatAction",
+ "android/support/v7/widget/LinearSnapHelper": "androidx/widget/LinearSnapHelper",
+ "android/support/v7/view/menu/BaseWrapper": "androidx/view/menu/BaseWrapper",
+ "android/support/wear/utils/MetadataConstants": "androidx/wear/utils/MetadataConstants",
+ "android/support/v7/widget/RecyclerView$ItemAnimator": "androidx/widget/RecyclerView$ItemAnimator",
+ "android/support/v17/leanback/media/PlaybackGlueHost$HostCallback": "androidx/leanback/media/PlaybackGlueHost$HostCallback",
+ "android/support/v7/widget/ActionMenuPresenter$ActionMenuPopupCallback": "androidx/widget/ActionMenuPresenter$ActionMenuPopupCallback",
+ "android/support/v7/widget/GridLayout$Interval": "androidx/widget/GridLayout$Interval",
+ "android/support/v17/leanback/widget/GuidedActionsStylist$ViewHolder": "androidx/leanback/widget/GuidedActionsStylist$ViewHolder",
+ "android/support/v4/app/Fragment$InstantiationException": "androidx/app/Fragment$InstantiationException",
+ "android/support/v14/preference/EditTextPreferenceDialogFragment": "androidx/preference/EditTextPreferenceDialogFragment",
+ "android/support/text/emoji/EmojiCompat$CompatInternal": "androidx/text/emoji/EmojiCompat$CompatInternal",
+ "android/support/v14/preference/BuildConfig": "androidx/preference/BuildConfig",
+ "android/support/v4/app/FragmentManagerNonConfig": "androidx/app/FragmentManagerNonConfig",
+ "android/support/v7/media/MediaRouter$GlobalMediaRouter": "androidx/media/MediaRouter$GlobalMediaRouter",
+ "android/support/transition/Styleable$TransitionManager": "androidx/transition/Styleable$TransitionManager",
+ "android/support/v4/content/res/ConfigurationHelper": "androidx/content/res/ConfigurationHelper",
+ "android/support/v7/app/MediaRouteDiscoveryFragment": "androidx/app/MediaRouteDiscoveryFragment",
+ "android/support/v7/media/MediaRouteSelector": "androidx/media/MediaRouteSelector",
+ "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi21": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi21",
+ "android/support/v17/leanback/widget/ControlBar": "androidx/leanback/widget/ControlBar",
+ "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi24": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi24",
+ "android/support/app/recommendation/ContentRecommendation$ContentStatus": "androidx/app/recommendation/ContentRecommendation$ContentStatus",
+ "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi23": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi23",
+ "android/support/v4/media/MediaMetadataCompat": "androidx/media/MediaMetadataCompat",
+ "android/support/v4/util/CircularIntArray": "androidx/util/CircularIntArray",
+ "android/support/transition/Slide$CalculateSlide": "androidx/transition/Slide$CalculateSlide",
+ "android/support/transition/GhostViewUtils": "androidx/transition/GhostViewUtils",
+ "android/support/design/widget/NavigationView$OnNavigationItemSelectedListener": "androidx/design/widget/NavigationView$OnNavigationItemSelectedListener",
+ "android/support/v4/hardware/fingerprint/FingerprintManagerCompat$CryptoObject": "androidx/hardware/fingerprint/FingerprintManagerCompat$CryptoObject",
+ "android/support/media/tv/TvContractCompat$Programs": "androidx/media/tv/TvContractCompat$Programs",
+ "android/support/v4/provider/FontsContractCompat": "androidx/provider/FontsContractCompat",
+ "android/support/v4/content/res/FontResourcesParserCompat$ProviderResourceEntry": "androidx/content/res/FontResourcesParserCompat$ProviderResourceEntry",
+ "android/support/v17/leanback/widget/BaseGridView": "androidx/leanback/widget/BaseGridView",
+ "android/support/design/R": "androidx/design/R",
+ "android/support/annotation/GuardedBy": "androidx/annotation/GuardedBy",
+ "android/support/v17/leanback/widget/ListRowPresenter$ViewHolder": "androidx/leanback/widget/ListRowPresenter$ViewHolder",
+ "android/support/constraint/solver/widgets/ConstraintWidgetContainer": "androidx/constraint/solver/widgets/ConstraintWidgetContainer",
+ "android/support/wear/widget/drawer/WearableDrawerView$DrawerState": "androidx/wear/widget/drawer/WearableDrawerView$DrawerState",
+ "android/support/v7/widget/LinearLayoutManager$SavedState": "androidx/widget/LinearLayoutManager$SavedState",
+ "android/support/v4/util/LongSparseArray": "androidx/util/LongSparseArray",
+ "android/support/media/tv/TvContractCompat$ProgramColumns$ReviewRatingStyle": "androidx/media/tv/TvContractCompat$ProgramColumns$ReviewRatingStyle",
+ "android/support/v7/media/MediaRouter$GlobalMediaRouter$RemoteControlClientRecord": "androidx/media/MediaRouter$GlobalMediaRouter$RemoteControlClientRecord",
+ "android/support/v7/widget/TintResources": "androidx/widget/TintResources",
+ "android/support/v7/util/ThreadUtil$MainThreadCallback": "androidx/util/ThreadUtil$MainThreadCallback",
+ "android/support/animation/DynamicAnimation$MassState": "androidx/animation/DynamicAnimation$MassState",
+ "android/support/v4/widget/PopupWindowCompat": "androidx/widget/PopupWindowCompat",
+ "android/support/design/widget/FloatingActionButton$Behavior": "androidx/design/widget/FloatingActionButton$Behavior",
+ "android/support/v7/preference/PreferenceFragmentCompat$DividerDecoration": "androidx/preference/PreferenceFragmentCompat$DividerDecoration",
+ "android/support/transition/Styleable$PatternPathMotion": "androidx/transition/Styleable$PatternPathMotion",
+ "android/support/v4/media/session/MediaSessionCompat$Callback$CallbackHandler": "androidx/media/session/MediaSessionCompat$Callback$CallbackHandler",
+ "android/support/v4/app/INotificationSideChannel": "androidx/app/INotificationSideChannel",
+ "android/support/media/tv/TvContractCompat$Channels$VideoFormat": "androidx/media/tv/TvContractCompat$Channels$VideoFormat",
+ "android/support/v17/preference/LeanbackSettingsFragment$RootViewOnKeyListener": "androidx/leanback/preference/LeanbackSettingsFragment$RootViewOnKeyListener",
+ "android/support/v7/widget/ActionMenuView$MenuBuilderCallback": "androidx/widget/ActionMenuView$MenuBuilderCallback",
+ "android/support/design/widget/TabLayout$Mode": "androidx/design/widget/TabLayout$Mode",
+ "android/support/transition/ChangeTransform$Transforms": "androidx/transition/ChangeTransform$Transforms",
+ "android/support/v4/media/MediaBrowserServiceCompatApi21$ResultWrapper": "androidx/media/MediaBrowserServiceCompatApi21$ResultWrapper",
+ "android/support/v17/leanback/transition/TranslationAnimationCreator$TransitionPositionListener": "androidx/leanback/transition/TranslationAnimationCreator$TransitionPositionListener",
+ "android/support/text/emoji/widget/EmojiEditText": "androidx/text/emoji/widget/EmojiEditText",
+ "android/support/wear/R$styleable": "androidx/wear/R$styleable",
+ "android/support/v17/leanback/app/BrowseSupportFragment$FragmentHost": "androidx/leanback/app/BrowseSupportFragment$FragmentHost",
+ "android/support/transition/Scene": "androidx/transition/Scene",
+ "android/support/text/emoji/widget/EmojiTransformationMethod": "androidx/text/emoji/widget/EmojiTransformationMethod",
+ "android/support/v4/view/ViewCompat$ResolvedLayoutDirectionMode": "androidx/view/ViewCompat$ResolvedLayoutDirectionMode",
+ "android/support/v7/appcompat/R": "androidx/appcompat/R",
+ "android/support/v4/media/session/MediaSessionCompatApi24$Callback": "androidx/media/session/MediaSessionCompatApi24$Callback",
+ "android/support/v7/widget/RecyclerView": "androidx/widget/RecyclerView",
+ "android/support/v4/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListenerCompat": "androidx/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListenerCompat",
+ "android/support/v17/leanback/widget/FragmentAnimationProvider": "androidx/leanback/widget/FragmentAnimationProvider",
+ "android/support/v7/widget/ActivityChooserModel": "androidx/widget/ActivityChooserModel",
+ "android/support/media/tv/TvContractCompat$PreviewProgramColumns$InteractionType": "androidx/media/tv/TvContractCompat$PreviewProgramColumns$InteractionType",
+ "android/support/transition/Transition$TransitionListener": "androidx/transition/Transition$TransitionListener",
+ "android/support/v17/leanback/widget/PlaybackControlsRowPresenter$ViewHolder": "androidx/leanback/widget/PlaybackControlsRowPresenter$ViewHolder",
+ "android/support/design/widget/CoordinatorLayout": "androidx/widget/CoordinatorLayout",
+ "android/support/content/Query": "androidx/content/Query",
+ "android/support/v17/leanback/app/BackgroundManager$EmptyDrawable": "androidx/leanback/app/BackgroundManager$EmptyDrawable",
+ "android/support/v17/leanback/app/PlaybackSupportFragment$OnFadeCompleteListener": "androidx/leanback/app/PlaybackSupportFragment$OnFadeCompleteListener",
+ "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentAdapter": "androidx/leanback/app/BrowseSupportFragment$MainFragmentAdapter",
+ "android/support/v4/media/MediaBrowserCompat$ItemReceiver": "androidx/media/MediaBrowserCompat$ItemReceiver",
+ "android/support/transition/Styleable$VisibilityTransition": "androidx/transition/Styleable$VisibilityTransition",
+ "android/support/transition/TransitionValues": "androidx/transition/TransitionValues",
+ "android/support/v4/content/res/FontResourcesParserCompat$FamilyResourceEntry": "androidx/content/res/FontResourcesParserCompat$FamilyResourceEntry",
+ "android/support/v17/leanback/app/RowsSupportFragment$MainFragmentAdapter": "androidx/leanback/app/RowsSupportFragment$MainFragmentAdapter",
+ "android/support/v17/leanback/widget/Visibility": "androidx/leanback/widget/Visibility",
+ "android/support/design/widget/AppBarLayout$LayoutParams": "androidx/design/widget/AppBarLayout$LayoutParams",
+ "android/support/v4/media/MediaBrowserCompat$SubscriptionCallback$StubApi26": "androidx/media/MediaBrowserCompat$SubscriptionCallback$StubApi26",
+ "android/support/v4/widget/AutoScrollHelper$ClampedScroller": "androidx/widget/AutoScrollHelper$ClampedScroller",
+ "android/support/v7/preference/PreferenceFragmentCompat$OnPreferenceStartScreenCallback": "androidx/preference/PreferenceFragmentCompat$OnPreferenceStartScreenCallback",
+ "android/support/v7/graphics/Palette$Builder": "androidx/graphics/Palette$Builder",
+ "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$CollectionItemInfoCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat$CollectionItemInfoCompat",
+ "android/support/design/widget/StateListAnimator$Tuple": "androidx/design/widget/StateListAnimator$Tuple",
+ "android/support/v4/view/accessibility/AccessibilityManagerCompat$TouchExplorationStateChangeListener": "androidx/view/accessibility/AccessibilityManagerCompat$TouchExplorationStateChangeListener",
+ "android/support/text/emoji/EmojiCompat$SpanFactory": "androidx/text/emoji/EmojiCompat$SpanFactory",
+ "android/support/media/tv/TvContractCompat$Channels$Type": "androidx/media/tv/TvContractCompat$Channels$Type",
+ "android/support/v7/widget/GridLayout$LayoutParams": "androidx/widget/GridLayout$LayoutParams",
+ "android/support/v4/media/MediaBrowserCompat$SubscriptionCallback$StubApi21": "androidx/media/MediaBrowserCompat$SubscriptionCallback$StubApi21",
+ "android/support/v17/leanback/widget/WindowAlignment$Axis": "androidx/leanback/widget/WindowAlignment$Axis",
+ "android/support/v17/leanback/widget/ControlBarPresenter": "androidx/leanback/widget/ControlBarPresenter",
+ "android/support/constraint/ConstraintSet": "androidx/constraint/ConstraintSet",
+ "android/support/v17/leanback/transition/TransitionHelperKitkat": "androidx/leanback/transition/TransitionHelperKitkat",
+ "android/support/wear/widget/ScrollManager": "androidx/wear/widget/ScrollManager",
+ "android/support/content/ContentPager$QueryRunner$Callback": "androidx/content/ContentPager$QueryRunner$Callback",
+ "android/support/v4/graphics/TypefaceCompat$TypefaceCompatImpl": "androidx/graphics/TypefaceCompat$TypefaceCompatImpl",
+ "android/support/v7/widget/ContentFrameLayout": "androidx/widget/ContentFrameLayout",
+ "android/support/v4/app/ActionBarDrawerToggle$SetIndicatorInfo": "androidx/app/ActionBarDrawerToggle$SetIndicatorInfo",
+ "android/support/v4/util/TimeUtils": "androidx/util/TimeUtils",
+ "android/support/v7/widget/ActionBarBackgroundDrawableV21": "androidx/widget/ActionBarBackgroundDrawableV21",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$SkipNextAction": "androidx/leanback/widget/PlaybackControlsRow$SkipNextAction",
+ "android/support/design/internal/ParcelableSparseArray": "androidx/design/internal/ParcelableSparseArray",
+ "android/support/media/tv/Channel$Builder": "androidx/media/tv/Channel$Builder",
+ "android/support/v7/widget/AppCompatCompoundButtonHelper": "androidx/widget/AppCompatCompoundButtonHelper",
+ "android/support/v4/media/MediaBrowserCompatApi23$ItemCallback": "androidx/media/MediaBrowserCompatApi23$ItemCallback",
+ "android/support/v4/app/ActionBarDrawerToggle$Delegate": "androidx/app/ActionBarDrawerToggle$Delegate",
+ "android/support/graphics/drawable/AnimationUtilsCompat": "androidx/graphics/drawable/AnimationUtilsCompat",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$ShuffleAction": "androidx/leanback/widget/PlaybackControlsRow$ShuffleAction",
+ "android/support/v4/app/JobIntentService$JobServiceEngineImpl$WrapperWorkItem": "androidx/app/JobIntentService$JobServiceEngineImpl$WrapperWorkItem",
+ "android/support/v7/media/SystemMediaRouteProvider$SyncCallback": "androidx/media/SystemMediaRouteProvider$SyncCallback",
+ "android/support/v7/util/AsyncListUtil$ViewCallback": "androidx/util/AsyncListUtil$ViewCallback",
+ "android/support/v4/view/ViewPager$OnAdapterChangeListener": "androidx/view/ViewPager$OnAdapterChangeListener",
+ "android/support/v7/media/RegisteredMediaRouteProviderWatcher": "androidx/media/RegisteredMediaRouteProviderWatcher",
+ "android/support/transition/Fade$FadeAnimatorListener": "androidx/transition/Fade$FadeAnimatorListener",
+ "android/support/v4/content/res/FontResourcesParserCompat$FetchStrategy": "androidx/content/res/FontResourcesParserCompat$FetchStrategy",
+ "android/support/v17/leanback/graphics/FitWidthBitmapDrawable": "androidx/leanback/graphics/FitWidthBitmapDrawable",
+ "android/support/v7/widget/CardViewDelegate": "androidx/widget/CardViewDelegate",
+ "android/support/v4/media/MediaBrowserCompat$ItemCallback": "androidx/media/MediaBrowserCompat$ItemCallback",
+ "android/support/design/widget/BottomSheetDialog": "androidx/design/widget/BottomSheetDialog",
+ "android/support/v17/leanback/system/Settings$Customizations": "androidx/leanback/system/Settings$Customizations",
+ "android/support/design/widget/FloatingActionButtonImpl$InternalVisibilityChangedListener": "androidx/design/widget/FloatingActionButtonImpl$InternalVisibilityChangedListener",
+ "android/support/v7/media/RemotePlaybackClient$SessionActionCallback": "androidx/media/RemotePlaybackClient$SessionActionCallback",
+ "android/support/wear/ambient/AmbientDelegate$AmbientCallback": "androidx/wear/ambient/AmbientDelegate$AmbientCallback",
+ "android/support/v4/widget/FocusStrategy$BoundsAdapter": "androidx/widget/FocusStrategy$BoundsAdapter",
+ "android/support/v17/leanback/widget/DividerPresenter": "androidx/leanback/widget/DividerPresenter",
+ "android/support/text/emoji/EmojiProcessor$GlyphChecker": "androidx/text/emoji/EmojiProcessor$GlyphChecker",
+ "android/support/v7/preference/PreferenceFragmentCompat": "androidx/preference/PreferenceFragmentCompat",
+ "android/support/v7/widget/TooltipPopup": "androidx/widget/TooltipPopup",
+ "android/support/v4/view/accessibility/AccessibilityNodeProviderCompat": "androidx/view/accessibility/AccessibilityNodeProviderCompat",
+ "android/support/v4/media/MediaBrowserCompat$SearchCallback": "androidx/media/MediaBrowserCompat$SearchCallback",
+ "android/support/v4/media/session/IMediaControllerCallback": "androidx/media/session/IMediaControllerCallback",
+ "android/support/compat/R$styleable": "androidx/compat/R$styleable",
+ "android/support/v7/view/menu/MenuBuilder$ItemInvoker": "androidx/view/menu/MenuBuilder$ItemInvoker",
+ "android/support/v17/leanback/widget/MultiActionsProvider$MultiAction": "androidx/leanback/widget/MultiActionsProvider$MultiAction",
+ "android/support/v7/gridlayout/R$dimen": "androidx/gridlayout/R$dimen",
+ "android/support/v4/app/FragmentManagerImpl$FragmentTag": "androidx/app/FragmentManagerImpl$FragmentTag",
+ "android/support/v4/media/MediaDescriptionCompat$Builder": "androidx/media/MediaDescriptionCompat$Builder",
+ "android/support/v17/leanback/widget/PlaybackControlsPresenter$BoundData": "androidx/leanback/widget/PlaybackControlsPresenter$BoundData",
+ "android/support/v7/app/MediaRouteChooserDialog$RouteComparator": "androidx/app/MediaRouteChooserDialog$RouteComparator",
+ "android/support/v7/app/ActionBar": "androidx/app/ActionBar",
+ "android/support/design/widget/HeaderBehavior$FlingRunnable": "androidx/design/widget/HeaderBehavior$FlingRunnable",
+ "android/support/v7/widget/GapWorker$Task": "androidx/widget/GapWorker$Task",
+ "android/support/v4/view/AsyncLayoutInflater$InflateThread": "androidx/view/AsyncLayoutInflater$InflateThread",
+ "android/support/v17/leanback/R$string": "androidx/leanback/R$string",
+ "android/support/v4/content/LocalBroadcastManager$BroadcastRecord": "androidx/content/LocalBroadcastManager$BroadcastRecord",
+ "android/support/wear/widget/drawer/AbsListViewFlingWatcher": "androidx/wear/widget/drawer/AbsListViewFlingWatcher",
+ "android/support/v17/leanback/widget/ActionPresenterSelector$ActionViewHolder": "androidx/leanback/widget/ActionPresenterSelector$ActionViewHolder",
+ "android/support/v17/leanback/widget/ImageCardView": "androidx/leanback/widget/ImageCardView",
+ "android/support/v4/app/AlarmManagerCompat": "androidx/app/AlarmManagerCompat",
+ "android/support/v7/app/MediaRouterThemeHelper$ControllerColorType": "androidx/app/MediaRouterThemeHelper$ControllerColorType",
+ "android/support/v4/widget/SlidingPaneLayout$SlidingPanelLayoutImplBase": "androidx/widget/SlidingPaneLayout$SlidingPanelLayoutImplBase",
+ "android/support/v4/view/WindowCompat": "androidx/view/WindowCompat",
+ "android/support/v7/widget/ThemedSpinnerAdapter$Helper": "androidx/widget/ThemedSpinnerAdapter$Helper",
+ "android/support/v4/media/session/MediaControllerCompat$Callback$StubCompat": "androidx/media/session/MediaControllerCompat$Callback$StubCompat",
+ "android/support/v4/widget/NestedScrollView$AccessibilityDelegate": "androidx/widget/NestedScrollView$AccessibilityDelegate",
+ "android/support/annotation/MainThread": "androidx/annotation/MainThread",
+ "android/support/v17/leanback/app/RowsFragment$RowViewHolderExtra": "androidx/leanback/app/RowsFragment$RowViewHolderExtra",
+ "android/support/v17/leanback/widget/MultiActionsProvider": "androidx/leanback/widget/MultiActionsProvider",
+ "android/support/v7/mediarouter/R$id": "androidx/mediarouter/R$id",
+ "android/support/v4/view/ViewCompat$NestedScrollType": "androidx/view/ViewCompat$NestedScrollType",
+ "android/support/v4/text/TextDirectionHeuristicsCompat$TextDirectionAlgorithm": "androidx/text/TextDirectionHeuristicsCompat$TextDirectionAlgorithm",
+ "android/support/v4/media/session/MediaControllerCompatApi21$CallbackProxy": "androidx/media/session/MediaControllerCompatApi21$CallbackProxy",
+ "android/support/customtabs/TrustedWebUtils": "androidx/browser/customtabs/TrustedWebUtils",
+ "android/support/v4/text/BidiFormatter$Builder": "androidx/text/BidiFormatter$Builder",
+ "android/support/design/widget/TabLayout$TabView": "androidx/design/widget/TabLayout$TabView",
+ "android/support/wear/internal/widget/drawer/SinglePageUi$OnSelectedClickHandler": "androidx/wear/internal/widget/drawer/SinglePageUi$OnSelectedClickHandler",
+ "android/support/v17/leanback/widget/BrowseFrameLayout": "androidx/leanback/widget/BrowseFrameLayout",
+ "android/support/v4/widget/ImageViewCompat$BaseViewCompatImpl": "androidx/widget/ImageViewCompat$BaseViewCompatImpl",
+ "android/support/customtabs/PostMessageService": "androidx/browser/customtabs/PostMessageService",
+ "android/support/annotation/FontRes": "androidx/annotation/FontRes",
+ "android/support/transition/ViewGroupUtilsApi14": "androidx/transition/ViewGroupUtilsApi14",
+ "android/support/v4/view/ViewParentCompat": "androidx/view/ViewParentCompat",
+ "android/support/v17/leanback/widget/SectionRow": "androidx/leanback/widget/SectionRow",
+ "android/support/v7/preference/DropDownPreference": "androidx/preference/DropDownPreference",
+ "android/support/v4/widget/DrawerLayout$SavedState": "androidx/widget/DrawerLayout$SavedState",
+ "android/support/transition/AnimatorUtilsApi14": "androidx/transition/AnimatorUtilsApi14",
+ "android/support/transition/AnimatorUtilsApi19": "androidx/transition/AnimatorUtilsApi19",
+ "android/support/constraint/solver/widgets/ConstraintAnchor$Strength": "androidx/constraint/solver/widgets/ConstraintAnchor$Strength",
+ "android/support/v7/widget/RecyclerView$SmoothScroller": "androidx/widget/RecyclerView$SmoothScroller",
+ "android/support/design/R$drawable": "androidx/design/R$drawable",
+ "android/support/v7/util/BatchingListUpdateCallback": "androidx/util/BatchingListUpdateCallback",
+ "android/support/v17/leanback/app/BrandedSupportFragment": "androidx/leanback/app/BrandedSupportFragment",
+ "android/support/transition/ViewGroupUtilsApi18": "androidx/transition/ViewGroupUtilsApi18",
+ "android/support/v17/leanback/app/BrowseFragment$FragmentHost": "androidx/leanback/app/BrowseFragment$FragmentHost",
+ "android/support/v17/leanback/widget/MediaNowPlayingView": "androidx/leanback/widget/MediaNowPlayingView",
+ "android/support/v4/app/ActivityCompat$PermissionCompatDelegate": "androidx/app/ActivityCompat$PermissionCompatDelegate",
+ "android/support/v7/app/ActionBar$TabListener": "androidx/app/ActionBar$TabListener",
+ "android/support/design/widget/CoordinatorLayout$HierarchyChangeListener": "androidx/design/widget/CoordinatorLayout$HierarchyChangeListener",
+ "android/support/v7/app/AppCompatDelegateImplV9": "androidx/app/AppCompatDelegateImplV9",
+ "android/support/v4/app/LoaderManager$LoaderCallbacks": "androidx/app/LoaderManager$LoaderCallbacks",
+ "android/support/v4/view/MenuItemCompat$MenuItemCompatBaseImpl": "androidx/view/MenuItemCompat$MenuItemCompatBaseImpl",
+ "android/support/design/widget/BaseTransientBottomBar$SnackbarBaseLayout": "androidx/design/widget/BaseTransientBottomBar$SnackbarBaseLayout",
+ "android/support/text/emoji/EmojiCompat$CompatInternal19": "androidx/text/emoji/EmojiCompat$CompatInternal19",
+ "android/support/wear/R$fraction": "androidx/wear/R$fraction",
+ "android/support/v7/widget/DividerItemDecoration": "androidx/widget/DividerItemDecoration",
+ "android/support/v4/view/MenuItemCompat$OnActionExpandListener": "androidx/view/MenuItemCompat$OnActionExpandListener",
+ "android/support/v4/widget/SlidingPaneLayout$SlidingPanelLayoutImpl": "androidx/widget/SlidingPaneLayout$SlidingPanelLayoutImpl",
+ "android/support/v4/graphics/PathParser$ExtractFloatResult": "androidx/graphics/PathParser$ExtractFloatResult",
+ "android/support/graphics/drawable/ArgbEvaluator": "androidx/graphics/drawable/ArgbEvaluator",
+ "android/support/v17/leanback/widget/ShadowHelper": "androidx/leanback/widget/ShadowHelper",
+ "android/support/design/widget/FloatingActionButtonImpl$ElevateToTranslationZAnimation": "androidx/design/widget/FloatingActionButtonImpl$ElevateToTranslationZAnimation",
+ "android/support/v4/app/NotificationManagerCompat$SideChannelManager": "androidx/app/NotificationManagerCompat$SideChannelManager",
+ "android/support/v17/leanback/widget/PlaybackRowPresenter$ViewHolder": "androidx/leanback/widget/PlaybackRowPresenter$ViewHolder",
+ "android/support/v17/leanback/media/PlaybackBaseControlGlue": "androidx/leanback/media/PlaybackBaseControlGlue",
+ "android/support/v7/app/MediaRouteButton": "androidx/app/MediaRouteButton",
+ "android/support/v4/view/PagerTabStrip": "androidx/widget/PagerTabStrip",
+ "android/support/v7/widget/ActivityChooserView$InnerLayout": "androidx/widget/ActivityChooserView$InnerLayout",
+ "android/support/v17/leanback/widget/TitleHelper": "androidx/leanback/widget/TitleHelper",
+ "android/support/v7/media/RegisteredMediaRouteProvider": "androidx/media/RegisteredMediaRouteProvider",
+ "android/support/v4/print/PrintHelper$PrintHelperStub": "androidx/print/PrintHelper$PrintHelperStub",
+ "android/support/v7/media/MediaRouter": "androidx/media/MediaRouter",
+ "android/support/v4/widget/ViewDragHelper": "androidx/widget/ViewDragHelper",
+ "android/support/v4/media/MediaBrowserCompat$MediaItem": "androidx/media/MediaBrowserCompat$MediaItem",
+ "android/support/app/recommendation/ContentRecommendation$ContentMaturity": "androidx/app/recommendation/ContentRecommendation$ContentMaturity",
+ "android/support/v7/widget/SwitchCompat": "androidx/widget/SwitchCompat",
+ "android/support/v7/media/MediaSessionStatus": "androidx/media/MediaSessionStatus",
+ "android/support/v17/leanback/widget/picker/Picker$PickerScrollArrayAdapter": "androidx/leanback/widget/picker/Picker$PickerScrollArrayAdapter",
+ "android/support/v4/util/Pools": "androidx/util/Pools",
+ "android/support/v4/widget/SlidingPaneLayout$SavedState": "androidx/widget/SlidingPaneLayout$SavedState",
+ "android/support/v7/widget/ViewStubCompat$OnInflateListener": "androidx/widget/ViewStubCompat$OnInflateListener",
+ "android/support/design/widget/ViewOffsetHelper": "androidx/design/widget/ViewOffsetHelper",
+ "android/support/design/widget/FloatingActionButton$OnVisibilityChangedListener": "androidx/design/widget/FloatingActionButton$OnVisibilityChangedListener",
+ "android/support/compat/BuildConfig": "androidx/compat/BuildConfig",
+ "android/support/v4/app/FragmentManagerImpl$PopBackStackState": "androidx/app/FragmentManagerImpl$PopBackStackState",
+ "android/support/v7/media/MediaRouterJellybeanMr1$ActiveScanWorkaround": "androidx/media/MediaRouterJellybeanMr1$ActiveScanWorkaround",
+ "android/support/v17/leanback/widget/TitleViewAdapter": "androidx/leanback/widget/TitleViewAdapter",
+ "android/support/design/widget/TabLayout": "androidx/design/widget/TabLayout",
+ "android/support/v4/view/MenuItemCompat$MenuVersionImpl": "androidx/view/MenuItemCompat$MenuVersionImpl",
+ "android/support/v7/app/MediaRouteButton$MediaRouterCallback": "androidx/app/MediaRouteButton$MediaRouterCallback",
+ "android/support/v4/media/MediaDescriptionCompatApi21$Builder": "androidx/media/MediaDescriptionCompatApi21$Builder",
+ "android/support/design/widget/TabLayout$TabGravity": "androidx/design/widget/TabLayout$TabGravity",
+ "android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter": "androidx/leanback/widget/AbstractDetailsDescriptionPresenter",
+ "android/support/v7/widget/RecyclerView$RecycledViewPool$ScrapData": "androidx/widget/RecyclerView$RecycledViewPool$ScrapData",
+ "android/support/v17/leanback/media/MediaControllerAdapter": "androidx/leanback/media/MediaControllerAdapter",
+ "android/support/wear/internal/widget/drawer/MultiPagePresenter$Ui": "androidx/wear/internal/widget/drawer/MultiPagePresenter$Ui",
+ "android/support/v7/app/ToolbarActionBar": "androidx/app/ToolbarActionBar",
+ "android/support/v7/widget/ViewBoundsCheck$Callback": "androidx/widget/ViewBoundsCheck$Callback",
+ "android/support/text/emoji/widget/EmojiExtractEditText": "androidx/text/emoji/widget/EmojiExtractEditText",
+ "android/support/v4/app/FrameMetricsAggregator": "androidx/app/FrameMetricsAggregator",
+ "android/support/constraint/R": "androidx/constraint/R",
+ "android/support/v7/mediarouter/R$string": "androidx/mediarouter/R$string",
+ "android/support/text/emoji/bundled/BundledEmojiCompatConfig$InitRunnable": "androidx/text/emoji/bundled/BundledEmojiCompatConfig$InitRunnable",
+ "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperApi21Impl": "androidx/leanback/transition/TransitionHelper$TransitionHelperApi21Impl",
+ "android/support/v7/widget/LinearLayoutManager": "androidx/widget/LinearLayoutManager",
+ "android/support/graphics/drawable/VectorDrawableCompat$VGroup": "androidx/graphics/drawable/VectorDrawableCompat$VGroup",
+ "android/support/v17/leanback/app/BackgroundManager": "androidx/leanback/app/BackgroundManager",
+ "android/support/v17/leanback/app/VideoFragmentGlueHost": "androidx/leanback/app/VideoFragmentGlueHost",
+ "android/support/v4/net/ConnectivityManagerCompat": "androidx/net/ConnectivityManagerCompat",
+ "android/support/annotation/NonNull": "androidx/annotation/NonNull",
+ "android/support/transition/ImageViewUtilsApi21": "androidx/transition/ImageViewUtilsApi21",
+ "android/support/v7/widget/Toolbar$SavedState": "androidx/widget/Toolbar$SavedState",
+ "android/support/v7/util/ThreadUtil$BackgroundCallback": "androidx/util/ThreadUtil$BackgroundCallback",
+ "android/support/v17/leanback/app/BaseFragment": "androidx/leanback/app/BaseFragment",
+ "android/support/v4/view/AccessibilityDelegateCompat$AccessibilityDelegateApi16Impl": "androidx/view/AccessibilityDelegateCompat$AccessibilityDelegateApi16Impl",
+ "android/support/v7/media/MediaRouterJellybeanMr2$UserRouteInfo": "androidx/media/MediaRouterJellybeanMr2$UserRouteInfo",
+ "android/support/v7/widget/DefaultItemAnimator$ChangeInfo": "androidx/widget/DefaultItemAnimator$ChangeInfo",
+ "android/support/v4/hardware/display/DisplayManagerCompat$DisplayManagerCompatApi14Impl": "androidx/hardware/display/DisplayManagerCompat$DisplayManagerCompatApi14Impl",
+ "android/support/v7/cardview/R": "androidx/cardview/R",
+ "android/support/v4/app/NotificationCompat": "androidx/app/NotificationCompat",
+ "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperKitkatImpl": "androidx/leanback/transition/TransitionHelper$TransitionHelperKitkatImpl",
+ "android/support/v4/widget/CircularProgressDrawable$Ring": "androidx/widget/CircularProgressDrawable$Ring",
+ "android/support/v17/leanback/app/BrowseSupportFragment$ListRowFragmentFactory": "androidx/leanback/app/BrowseSupportFragment$ListRowFragmentFactory",
+ "android/support/v7/widget/LinearLayoutManager$AnchorInfo": "androidx/widget/LinearLayoutManager$AnchorInfo",
+ "android/support/v4/media/MediaBrowserCompatApi26$SubscriptionCallbackProxy": "androidx/media/MediaBrowserCompatApi26$SubscriptionCallbackProxy",
+ "android/support/v4/view/ViewCompat$ViewCompatApi19Impl": "androidx/view/ViewCompat$ViewCompatApi19Impl",
+ "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat",
+ "android/support/v4/os/IResultReceiver$Stub$Proxy": "androidx/os/IResultReceiver$Stub$Proxy",
+ "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$BoundData": "androidx/leanback/widget/PlaybackTransportRowPresenter$BoundData",
+ "android/support/transition/TransitionSet": "androidx/transition/TransitionSet",
+ "android/support/v7/graphics/drawable/DrawableWrapper": "androidx/graphics/drawable/DrawableWrapper",
+ "android/support/v7/media/MediaRouterJellybean$UserRouteInfo": "androidx/media/MediaRouterJellybean$UserRouteInfo",
+ "android/support/v7/app/MediaRouteActionProvider": "androidx/app/MediaRouteActionProvider",
+ "android/support/compat/R$layout": "androidx/compat/R$layout",
+ "android/support/v17/leanback/widget/ViewHolderTask": "androidx/leanback/widget/ViewHolderTask",
+ "android/support/v7/graphics/ColorCutQuantizer$Vbox": "androidx/graphics/ColorCutQuantizer$Vbox",
+ "android/support/text/emoji/EmojiProcessor$CodepointIndexFinder": "androidx/text/emoji/EmojiProcessor$CodepointIndexFinder",
+ "android/support/v4/content/CursorLoader": "androidx/content/CursorLoader",
+ "android/support/text/emoji/widget/EditTextAttributeHelper": "androidx/text/emoji/widget/EditTextAttributeHelper",
+ "android/support/wear/internal/widget/ResourcesUtil": "androidx/wear/internal/widget/ResourcesUtil",
+ "android/support/wear/R$array": "androidx/wear/R$array",
+ "android/support/v7/widget/RecyclerView$RecycledViewPool": "androidx/widget/RecyclerView$RecycledViewPool",
+ "android/support/transition/ImageViewUtilsApi14": "androidx/transition/ImageViewUtilsApi14",
+ "android/support/v7/gridlayout/R": "androidx/gridlayout/R",
+ "android/support/text/emoji/FontRequestEmojiCompatConfig": "androidx/text/emoji/FontRequestEmojiCompatConfig",
+ "android/support/text/emoji/EmojiMetadata": "androidx/text/emoji/EmojiMetadata",
+ "android/support/v4/widget/SlidingPaneLayout$DisableLayerRunnable": "androidx/widget/SlidingPaneLayout$DisableLayerRunnable",
+ "android/support/v4/util/Pools$SynchronizedPool": "androidx/util/Pools$SynchronizedPool",
+ "android/support/v17/leanback/graphics/BoundsRule$ValueRule": "androidx/leanback/graphics/BoundsRule$ValueRule",
+ "android/support/v7/widget/ActivityChooserView$ActivityChooserViewAdapter": "androidx/widget/ActivityChooserView$ActivityChooserViewAdapter",
+ "android/support/v7/mediarouter/R": "androidx/mediarouter/R",
+ "android/support/text/emoji/FontRequestEmojiCompatConfig$ExponentialBackoffRetryPolicy": "androidx/text/emoji/FontRequestEmojiCompatConfig$ExponentialBackoffRetryPolicy",
+ "android/support/v7/widget/AppCompatImageView": "androidx/widget/AppCompatImageView",
+ "android/support/v17/preference/R$layout": "androidx/leanback/preference/R$layout",
+ "android/support/v4/provider/FontsContractCompat$FontFamilyResult$FontResultStatus": "androidx/provider/FontsContractCompat$FontFamilyResult$FontResultStatus",
+ "android/support/graphics/drawable/VectorDrawableCompat$VPathRenderer": "androidx/graphics/drawable/VectorDrawableCompat$VPathRenderer",
+ "android/support/v4/app/JobIntentService$CompatWorkEnqueuer": "androidx/app/JobIntentService$CompatWorkEnqueuer",
+ "android/support/v17/leanback/app/BrowseSupportFragment$SetSelectionRunnable": "androidx/leanback/app/BrowseSupportFragment$SetSelectionRunnable",
+ "android/support/v4/media/MediaDescriptionCompatApi23$Builder": "androidx/media/MediaDescriptionCompatApi23$Builder",
+ "android/support/v17/leanback/widget/DetailsOverviewRowPresenter": "androidx/leanback/widget/DetailsOverviewRowPresenter",
+ "android/support/text/emoji/FontRequestEmojiCompatConfig$RetryPolicy": "androidx/text/emoji/FontRequestEmojiCompatConfig$RetryPolicy",
+ "android/support/v7/widget/ScrollingTabContainerView$TabView": "androidx/widget/ScrollingTabContainerView$TabView",
+ "android/support/annotation/DrawableRes": "androidx/annotation/DrawableRes",
+ "android/support/v4/view/ViewPager$LayoutParams": "androidx/view/ViewPager$LayoutParams",
+ "android/support/v17/leanback/widget/MediaItemActionPresenter$ViewHolder": "androidx/leanback/widget/MediaItemActionPresenter$ViewHolder",
+ "android/support/v7/app/AlertDialog$Builder": "androidx/app/AlertDialog$Builder",
+ "android/support/v4/util/Preconditions": "androidx/util/Preconditions",
+ "android/support/v4/app/FragmentTabHost": "androidx/app/FragmentTabHost",
+ "android/support/v17/leanback/widget/BaseGridView$OnTouchInterceptListener": "androidx/leanback/widget/BaseGridView$OnTouchInterceptListener",
+ "android/support/text/emoji/EmojiCompat$ListenerDispatcher": "androidx/text/emoji/EmojiCompat$ListenerDispatcher",
+ "android/support/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuListener": "androidx/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuListener",
+ "android/support/v4/app/INotificationSideChannel$Stub$Proxy": "androidx/app/INotificationSideChannel$Stub$Proxy",
+ "android/support/media/tv/TvContractCompat$Programs$Genres$Genre": "androidx/media/tv/TvContractCompat$Programs$Genres$Genre",
+ "android/support/text/emoji/widget/EmojiTextWatcher$InitCallbackImpl": "androidx/text/emoji/widget/EmojiTextWatcher$InitCallbackImpl",
+ "android/support/v17/leanback/widget/ParallaxTarget$DirectPropertyTarget": "androidx/leanback/widget/ParallaxTarget$DirectPropertyTarget",
+ "android/support/v7/app/ToolbarActionBar$ToolbarCallbackWrapper": "androidx/app/ToolbarActionBar$ToolbarCallbackWrapper",
+ "android/support/v4/widget/CompoundButtonCompat": "androidx/widget/CompoundButtonCompat",
+ "android/support/v4/content/ContentResolverCompat": "androidx/content/ContentResolverCompat",
+ "android/support/v17/leanback/widget/NonOverlappingRelativeLayout": "androidx/leanback/widget/NonOverlappingRelativeLayout",
+ "android/support/text/emoji/EmojiCompat$MetadataRepoLoaderCallback": "androidx/text/emoji/EmojiCompat$MetadataRepoLoaderCallback",
+ "android/support/v4/app/FragmentStatePagerAdapter": "androidx/app/FragmentStatePagerAdapter",
+ "android/support/v17/leanback/app/PlaybackSupportFragment": "androidx/leanback/app/PlaybackSupportFragment",
+ "android/support/v7/app/OverlayListView": "androidx/app/OverlayListView",
+ "android/support/v7/mediarouter/R$styleable": "androidx/mediarouter/R$styleable",
+ "android/support/v7/widget/DrawableUtils": "androidx/widget/DrawableUtils",
+ "android/support/v4/content/ModernAsyncTask$AsyncTaskResult": "androidx/content/ModernAsyncTask$AsyncTaskResult",
+ "android/support/constraint/BuildConfig": "androidx/constraint/BuildConfig",
+ "android/support/v4/app/SharedElementCallback": "androidx/app/SharedElementCallback",
+ "android/support/v7/recyclerview/BuildConfig": "androidx/recyclerview/BuildConfig",
+ "android/support/text/emoji/widget/EmojiKeyListener": "androidx/text/emoji/widget/EmojiKeyListener",
+ "android/support/v17/leanback/transition/FadeAndShortSlide$CalculateSlide": "androidx/leanback/transition/FadeAndShortSlide$CalculateSlide",
+ "android/support/v7/widget/ActionMenuPresenter$ActionButtonSubmenu": "androidx/widget/ActionMenuPresenter$ActionButtonSubmenu",
+ "android/support/v4/media/MediaMetadataCompat$Builder": "androidx/media/MediaMetadataCompat$Builder",
+ "android/support/design/widget/BottomSheetBehavior$SavedState": "androidx/design/widget/BottomSheetBehavior$SavedState",
+ "android/support/v4/media/session/MediaControllerCompatApi21$PlaybackInfo": "androidx/media/session/MediaControllerCompatApi21$PlaybackInfo",
+ "android/support/v7/widget/ActionMenuPresenter$PopupPresenterCallback": "androidx/widget/ActionMenuPresenter$PopupPresenterCallback",
+ "android/support/media/ExifInterface$ByteOrderedDataOutputStream": "androidx/media/ExifInterface$ByteOrderedDataOutputStream",
+ "android/support/v17/leanback/widget/Grid$Location": "androidx/leanback/widget/Grid$Location",
+ "android/support/v7/media/MediaRouterJellybeanMr1$CallbackProxy": "androidx/media/MediaRouterJellybeanMr1$CallbackProxy",
+ "android/support/v17/leanback/R$raw": "androidx/leanback/R$raw",
+ "android/support/media/tv/TvContractCompat$PreviewProgramColumns": "androidx/media/tv/TvContractCompat$PreviewProgramColumns",
+ "android/support/v17/leanback/widget/SeekBar$AccessibilitySeekListener": "androidx/leanback/widget/SeekBar$AccessibilitySeekListener",
+ "android/support/v4/print/PrintHelper$PrintHelperVersionImpl": "androidx/print/PrintHelper$PrintHelperVersionImpl",
+ "android/support/v17/leanback/app/ProgressBarManager": "androidx/leanback/app/ProgressBarManager",
+ "android/support/v7/app/MediaRouteChooserDialogFragment": "androidx/app/MediaRouteChooserDialogFragment",
+ "android/support/v4/content/FileProvider$SimplePathStrategy": "androidx/content/FileProvider$SimplePathStrategy",
+ "android/support/v17/leanback/app/BackgroundManager$BackgroundContinuityService": "androidx/leanback/app/BackgroundManager$BackgroundContinuityService",
+ "android/support/v4/media/session/IMediaSession$Stub": "androidx/media/session/IMediaSession$Stub",
+ "android/support/v4/widget/TintableImageSourceView": "androidx/widget/TintableImageSourceView",
+ "android/support/transition/ViewOverlayApi14$OverlayViewGroup": "androidx/transition/ViewOverlayApi14$OverlayViewGroup",
+ "android/support/design/widget/FloatingActionButtonImpl": "androidx/design/widget/FloatingActionButtonImpl",
+ "android/support/text/emoji/widget/EmojiEditableFactory": "androidx/text/emoji/widget/EmojiEditableFactory",
+ "android/support/transition/Visibility$Mode": "androidx/transition/Visibility$Mode",
+ "android/support/v17/leanback/widget/PagingIndicator$Dot": "androidx/leanback/widget/PagingIndicator$Dot",
+ "android/support/design/internal/NavigationSubMenu": "androidx/design/internal/NavigationSubMenu",
+ "android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter$ViewHolder": "androidx/leanback/widget/AbstractDetailsDescriptionPresenter$ViewHolder",
+ "android/support/v4/media/AudioAttributesCompat$AudioManagerHidden": "androidx/media/AudioAttributesCompat$AudioManagerHidden",
+ "android/support/v7/preference/CheckBoxPreference": "androidx/preference/CheckBoxPreference",
+ "android/support/design/widget/FloatingActionButtonLollipop$AlwaysStatefulGradientDrawable": "androidx/design/widget/FloatingActionButtonLollipop$AlwaysStatefulGradientDrawable",
+ "android/support/v4/media/RatingCompat$StarStyle": "androidx/media/RatingCompat$StarStyle",
+ "android/support/v7/preference/PreferenceGroup$PreferencePositionCallback": "androidx/preference/PreferenceGroup$PreferencePositionCallback",
+ "android/support/design/widget/BottomNavigationView": "androidx/design/widget/BottomNavigationView",
+ "android/support/v17/leanback/media/MediaPlayerAdapter": "androidx/leanback/media/MediaPlayerAdapter",
+ "android/support/v7/widget/SuggestionsAdapter$ChildViewCache": "androidx/widget/SuggestionsAdapter$ChildViewCache",
+ "android/support/v4/media/session/MediaSessionCompat$Callback$StubApi21": "androidx/media/session/MediaSessionCompat$Callback$StubApi21",
+ "android/support/v7/widget/ListPopupWindow$PopupScrollListener": "androidx/widget/ListPopupWindow$PopupScrollListener",
+ "android/support/v4/app/NotificationCompat$MessagingStyle": "androidx/app/NotificationCompat$MessagingStyle",
+ "android/support/wear/widget/SwipeDismissLayout$OnSwipeProgressChangedListener": "androidx/wear/widget/SwipeDismissLayout$OnSwipeProgressChangedListener",
+ "android/support/v7/media/RemotePlaybackClient$OnMessageReceivedListener": "androidx/media/RemotePlaybackClient$OnMessageReceivedListener",
+ "android/support/v7/util/MessageThreadUtil$SyncQueueItem": "androidx/util/MessageThreadUtil$SyncQueueItem",
+ "android/support/v4/view/MarginLayoutParamsCompat": "androidx/view/MarginLayoutParamsCompat",
+ "android/support/v4/media/session/MediaSessionCompat$Callback$StubApi24": "androidx/media/session/MediaSessionCompat$Callback$StubApi24",
+ "android/support/v17/leanback/widget/CheckableImageView": "androidx/leanback/widget/CheckableImageView",
+ "android/support/v4/media/session/MediaSessionCompat$Callback$StubApi23": "androidx/media/session/MediaSessionCompat$Callback$StubApi23",
+ "android/support/v7/widget/ThemeUtils": "androidx/widget/ThemeUtils",
+ "android/support/v7/preference/Preference$BaseSavedState": "androidx/preference/Preference$BaseSavedState",
+ "android/support/v4/widget/DrawerLayout$AccessibilityDelegate": "androidx/widget/DrawerLayout$AccessibilityDelegate",
+ "android/support/v4/app/ActivityOptionsCompat": "androidx/app/ActivityOptionsCompat",
+ "android/support/v4/media/session/PlaybackStateCompat$State": "androidx/media/session/PlaybackStateCompat$State",
+ "android/support/v7/widget/RecyclerView$ItemAnimator$ItemHolderInfo": "androidx/widget/RecyclerView$ItemAnimator$ItemHolderInfo",
+ "android/support/constraint/solver/widgets/ConstraintAnchor$Type": "androidx/constraint/solver/widgets/ConstraintAnchor$Type",
+ "android/support/v4/widget/TextViewCompat$TextViewCompatApi17Impl": "androidx/widget/TextViewCompat$TextViewCompatApi17Impl",
+ "android/support/v17/leanback/widget/ImeKeyMonitor": "androidx/leanback/widget/ImeKeyMonitor",
+ "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentRowsAdapter": "androidx/leanback/app/BrowseSupportFragment$MainFragmentRowsAdapter",
+ "android/support/v4/app/ActivityCompat": "androidx/app/ActivityCompat",
+ "android/support/v4/util/ObjectsCompat": "androidx/util/ObjectsCompat",
+ "android/support/v4/app/SupportActivity$ExtraData": "androidx/app/SupportActivity$ExtraData",
+ "android/support/v4/media/MediaBrowserProtocol": "androidx/media/MediaBrowserProtocol",
+ "android/support/design/widget/CollapsingTextHelper": "androidx/design/widget/CollapsingTextHelper",
+ "android/support/v14/preference/SwitchPreference$Listener": "androidx/preference/SwitchPreference$Listener",
+ "android/support/v7/preference/SwitchPreferenceCompat$Listener": "androidx/preference/SwitchPreferenceCompat$Listener",
+ "android/support/wear/internal/widget/drawer/SinglePageUi": "androidx/wear/internal/widget/drawer/SinglePageUi",
+ "android/support/v4/view/NestedScrollingChild2": "androidx/view/NestedScrollingChild2",
+ "android/support/customtabs/ICustomTabsService": "androidx/browser/customtabs/ICustomTabsService",
+ "android/support/recommendation/BuildConfig": "androidx/recommendation/BuildConfig",
+ "android/support/text/emoji/widget/EmojiAppCompatTextView": "androidx/text/emoji/widget/EmojiAppCompatTextView",
+ "android/support/v7/media/MediaRouterJellybean$RouteGroup": "androidx/media/MediaRouterJellybean$RouteGroup",
+ "android/support/v4/widget/DrawerLayout": "androidx/widget/DrawerLayout",
+ "android/support/v4/os/CancellationSignal$OnCancelListener": "androidx/os/CancellationSignal$OnCancelListener",
+ "android/support/v4/view/ViewCompat$ViewCompatApi17Impl": "androidx/view/ViewCompat$ViewCompatApi17Impl",
+ "android/support/v4/app/JobIntentService$CompatJobEngine": "androidx/app/JobIntentService$CompatJobEngine",
+ "android/support/v4/media/MediaBrowserCompat$CustomActionCallback": "androidx/media/MediaBrowserCompat$CustomActionCallback",
+ "android/support/v4/media/app/NotificationCompat$DecoratedMediaCustomViewStyle": "androidx/media/app/NotificationCompat$DecoratedMediaCustomViewStyle",
+ "android/support/v7/app/ActionBarDrawerToggle$Delegate": "androidx/app/ActionBarDrawerToggle$Delegate",
+ "android/support/v17/leanback/R$anim": "androidx/leanback/R$anim",
+ "android/support/v13/app/FragmentCompat$FragmentCompatBaseImpl": "androidx/app/FragmentCompat$FragmentCompatBaseImpl",
+ "android/support/v7/widget/SearchView$OnCloseListener": "androidx/widget/SearchView$OnCloseListener",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$OnPlaybackProgressCallback": "androidx/leanback/widget/PlaybackControlsRow$OnPlaybackProgressCallback",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$MoreActions": "androidx/leanback/widget/PlaybackControlsRow$MoreActions",
+ "android/support/v7/widget/ActivityChooserModel$ActivityResolveInfo": "androidx/widget/ActivityChooserModel$ActivityResolveInfo",
+ "android/support/annotation/AnimRes": "androidx/annotation/AnimRes",
+ "android/support/animation/Force": "androidx/animation/Force",
+ "android/support/v17/leanback/util/StateMachine$Event": "androidx/leanback/util/StateMachine$Event",
+ "android/support/v17/leanback/app/BrowseFragment$MainFragmentRowsAdapter": "androidx/leanback/app/BrowseFragment$MainFragmentRowsAdapter",
+ "android/support/v4/graphics/BitmapCompat": "androidx/graphics/BitmapCompat",
+ "android/support/v4/app/NotificationCompat$NotificationVisibility": "androidx/app/NotificationCompat$NotificationVisibility",
+ "android/support/v17/leanback/app/PlaybackFragment$SetSelectionRunnable": "androidx/leanback/app/PlaybackFragment$SetSelectionRunnable",
+ "android/support/v7/media/RegisteredMediaRouteProviderWatcher$Callback": "androidx/media/RegisteredMediaRouteProviderWatcher$Callback",
+ "android/support/v4/view/ViewCompat$FocusDirection": "androidx/view/ViewCompat$FocusDirection",
+ "android/support/design/widget/BottomSheetBehavior$SettleRunnable": "androidx/design/widget/BottomSheetBehavior$SettleRunnable",
+ "android/support/v17/leanback/widget/RoundedRectHelperApi21$RoundedRectOutlineProvider": "androidx/leanback/widget/RoundedRectHelperApi21$RoundedRectOutlineProvider",
+ "android/support/wear/widget/drawer/FlingWatcherFactory": "androidx/wear/widget/drawer/FlingWatcherFactory",
+ "android/support/v4/app/NotificationManagerCompat$Task": "androidx/app/NotificationManagerCompat$Task",
+ "android/support/animation/FlingAnimation$DragForce": "androidx/animation/FlingAnimation$DragForce",
+ "android/support/v7/widget/GridLayout$MutableInt": "androidx/widget/GridLayout$MutableInt",
+ "android/support/v7/util/DiffUtil": "androidx/util/DiffUtil",
+ "android/support/v4/app/FragmentManagerImpl$OpGenerator": "androidx/app/FragmentManagerImpl$OpGenerator",
+ "android/support/v4/view/ViewPager": "androidx/widget/ViewPager",
+ "android/support/v7/widget/TintTypedArray": "androidx/widget/TintTypedArray",
+ "android/support/text/emoji/widget/EmojiAppCompatEditText": "androidx/text/emoji/widget/EmojiAppCompatEditText",
+ "android/support/v4/view/ViewGroupCompat$ViewGroupCompatApi21Impl": "androidx/view/ViewGroupCompat$ViewGroupCompatApi21Impl",
+ "android/support/v4/media/MediaBrowserServiceCompat$ConnectionRecord": "androidx/media/MediaBrowserServiceCompat$ConnectionRecord",
+ "android/support/v7/view/menu/ActionMenuItemView": "androidx/view/menu/ActionMenuItemView",
+ "android/support/v4/app/NotificationCompatExtras": "androidx/app/NotificationCompatExtras",
+ "android/support/v7/view/menu/ListMenuPresenter": "androidx/view/menu/ListMenuPresenter",
+ "android/support/v14/preference/R": "androidx/preference/R",
+ "android/support/annotation/RequiresPermission": "androidx/annotation/RequiresPermission",
+ "android/support/v4/app/JobIntentService$GenericWorkItem": "androidx/app/JobIntentService$GenericWorkItem",
+ "android/support/v7/widget/RecyclerView$SmoothScroller$Action": "androidx/widget/RecyclerView$SmoothScroller$Action",
+ "android/support/design/R$attr": "androidx/design/R$attr",
+ "android/support/v4/content/SharedPreferencesCompat$EditorCompat$Helper": "androidx/content/SharedPreferencesCompat$EditorCompat$Helper",
+ "android/support/constraint/solver/widgets/ConstraintWidget": "androidx/constraint/solver/widgets/ConstraintWidget",
+ "android/support/fragment/BuildConfig": "androidx/fragment/BuildConfig",
+ "android/support/design/widget/NavigationView": "androidx/design/widget/NavigationView",
+ "android/support/v4/media/session/PlaybackStateCompatApi22": "androidx/media/session/PlaybackStateCompatApi22",
+ "android/support/v4/media/session/PlaybackStateCompatApi21": "androidx/media/session/PlaybackStateCompatApi21",
+ "android/support/media/instantvideo/preload/InstantVideoPreloadManager$InternalVideoPreloaderFactory": "androidx/media/instantvideo/preload/InstantVideoPreloadManager$InternalVideoPreloaderFactory",
+ "android/support/design/widget/BaseTransientBottomBar": "androidx/design/widget/BaseTransientBottomBar",
+ "android/support/wear/internal/widget/drawer/WearableNavigationDrawerPresenter": "androidx/wear/internal/widget/drawer/WearableNavigationDrawerPresenter",
+ "android/support/v4/media/session/MediaControllerCompat$Callback$StubApi21": "androidx/media/session/MediaControllerCompat$Callback$StubApi21",
+ "android/support/wear/widget/drawer/ScrollViewFlingWatcher": "androidx/wear/widget/drawer/ScrollViewFlingWatcher",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$FastForwardAction": "androidx/leanback/widget/PlaybackControlsRow$FastForwardAction",
+ "android/support/v7/widget/ActionBarOverlayLayout": "androidx/widget/ActionBarOverlayLayout",
+ "android/support/v4/app/FragmentTabHost$TabInfo": "androidx/app/FragmentTabHost$TabInfo",
+ "android/support/v7/widget/GridLayout$Bounds": "androidx/widget/GridLayout$Bounds",
+ "android/support/percent/BuildConfig": "androidx/BuildConfig",
+ "android/support/v7/app/ActionBar$OnMenuVisibilityListener": "androidx/app/ActionBar$OnMenuVisibilityListener",
+ "android/support/customtabs/PostMessageServiceConnection": "androidx/browser/customtabs/PostMessageServiceConnection",
+ "android/support/design/widget/TextInputLayout$TextInputAccessibilityDelegate": "androidx/design/widget/TextInputLayout$TextInputAccessibilityDelegate",
+ "android/support/v7/preference/Preference$OnPreferenceClickListener": "androidx/preference/Preference$OnPreferenceClickListener",
+ "android/support/v7/media/MediaRouterJellybean$RouteCategory": "androidx/media/MediaRouterJellybean$RouteCategory",
+ "android/support/v4/text/TextDirectionHeuristicCompat": "androidx/text/TextDirectionHeuristicCompat",
+ "android/support/v4/view/PointerIconCompat": "androidx/view/PointerIconCompat",
+ "android/support/design/internal/NavigationMenuPresenter$NavigationMenuAdapter": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuAdapter",
+ "android/support/v17/leanback/widget/BaseCardView$AnimationBase": "androidx/leanback/widget/BaseCardView$AnimationBase",
+ "android/support/v7/widget/ScrollingTabContainerView": "androidx/widget/ScrollingTabContainerView",
+ "android/support/v4/text/util/LinkifyCompat": "androidx/text/util/LinkifyCompat",
+ "android/support/annotation/RequiresPermission$Read": "androidx/annotation/RequiresPermission$Read",
+ "android/support/customtabs/CustomTabsService$Result": "androidx/browser/customtabs/CustomTabsService$Result",
+ "android/support/v7/app/MediaRouteControllerDialog": "androidx/app/MediaRouteControllerDialog",
+ "android/support/v17/leanback/app/BrowseFragment": "androidx/leanback/app/BrowseFragment",
+ "android/support/v17/leanback/widget/OnChildViewHolderSelectedListener": "androidx/leanback/widget/OnChildViewHolderSelectedListener",
+ "android/support/design/internal/NavigationMenuPresenter$SubheaderViewHolder": "androidx/design/internal/NavigationMenuPresenter$SubheaderViewHolder",
+ "android/support/v7/mediarouter/R$attr": "androidx/mediarouter/R$attr",
+ "android/support/v7/widget/ActivityChooserView$Callbacks": "androidx/widget/ActivityChooserView$Callbacks",
+ "android/support/v4/widget/TextViewCompat$TextViewCompatApi16Impl": "androidx/widget/TextViewCompat$TextViewCompatApi16Impl",
+ "android/support/v4/content/AsyncTaskLoader$LoadTask": "androidx/content/AsyncTaskLoader$LoadTask",
+ "android/support/v17/leanback/widget/GuidedActionAdapter$ActionOnFocusListener": "androidx/leanback/widget/GuidedActionAdapter$ActionOnFocusListener",
+ "android/support/v7/media/SystemMediaRouteProvider$LegacyImpl": "androidx/media/SystemMediaRouteProvider$LegacyImpl",
+ "android/support/transition/ViewUtils": "androidx/transition/ViewUtils",
+ "android/support/v17/leanback/app/RowsSupportFragment$RowViewHolderExtra": "androidx/leanback/app/RowsSupportFragment$RowViewHolderExtra",
+ "android/support/v17/leanback/widget/ActionPresenterSelector$TwoLineActionPresenter": "androidx/leanback/widget/ActionPresenterSelector$TwoLineActionPresenter",
+ "android/support/v7/recyclerview/R$dimen": "androidx/recyclerview/R$dimen",
+ "android/support/v7/app/TwilightCalculator": "androidx/app/TwilightCalculator",
+ "android/support/v17/leanback/widget/ResizingTextView": "androidx/leanback/widget/ResizingTextView",
+ "android/support/design/widget/ViewUtilsLollipop": "androidx/design/widget/ViewUtilsLollipop",
+ "android/support/media/tv/TvContractCompat$PreviewProgramColumns$Availability": "androidx/media/tv/TvContractCompat$PreviewProgramColumns$Availability",
+ "android/support/v7/media/RemotePlaybackClient$ActionCallback": "androidx/media/RemotePlaybackClient$ActionCallback",
+ "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$Listener": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$Listener",
+ "android/support/v4/app/FragmentManagerImpl$AnimatorOnHWLayerIfNeededListener": "androidx/app/FragmentManagerImpl$AnimatorOnHWLayerIfNeededListener",
+ "android/support/v17/leanback/transition/TransitionHelper": "androidx/leanback/transition/TransitionHelper",
+ "android/support/v7/view/SupportActionModeWrapper$CallbackWrapper": "androidx/view/SupportActionModeWrapper$CallbackWrapper",
+ "android/support/v13/app/FragmentStatePagerAdapter": "androidx/app/FragmentStatePagerAdapter",
+ "android/support/v7/graphics/Palette$PaletteAsyncListener": "androidx/graphics/Palette$PaletteAsyncListener",
+ "android/support/v4/media/MediaBrowserServiceCompat": "androidx/media/MediaBrowserServiceCompat",
+ "android/support/v4/widget/NestedScrollView": "androidx/widget/NestedScrollView",
+ "android/support/v4/media/MediaBrowserCompat$ItemCallback$StubApi23": "androidx/media/MediaBrowserCompat$ItemCallback$StubApi23",
+ "android/support/v4/text/BidiFormatter$DirectionalityEstimator": "androidx/text/BidiFormatter$DirectionalityEstimator",
+ "android/support/text/emoji/FontRequestEmojiCompatConfig$FontRequestMetadataLoader": "androidx/text/emoji/FontRequestEmojiCompatConfig$FontRequestMetadataLoader",
+ "android/support/transition/ChangeClipBounds": "androidx/transition/ChangeClipBounds",
+ "android/support/v7/widget/PositionMap": "androidx/widget/PositionMap",
+ "android/support/v17/leanback/widget/ItemBridgeAdapter$ViewHolder": "androidx/leanback/widget/ItemBridgeAdapter$ViewHolder",
+ "android/support/v7/widget/TintContextWrapper": "androidx/widget/TintContextWrapper",
+ "android/support/v7/widget/MenuItemHoverListener": "androidx/widget/MenuItemHoverListener",
+ "android/support/v4/app/RemoteInputCompatBase": "androidx/app/RemoteInputCompatBase",
+ "android/support/v17/leanback/media/SurfaceHolderGlueHost": "androidx/leanback/media/SurfaceHolderGlueHost",
+ "android/support/v7/widget/LinearLayoutManager$LayoutChunkResult": "androidx/widget/LinearLayoutManager$LayoutChunkResult",
+ "android/support/v7/view/menu/MenuPresenter": "androidx/view/menu/MenuPresenter",
+ "android/support/v7/media/MediaRouterJellybean": "androidx/media/MediaRouterJellybean",
+ "android/support/annotation/ArrayRes": "androidx/annotation/ArrayRes",
+ "android/support/v4/media/session/MediaSessionCompat$ResultReceiverWrapper": "androidx/media/session/MediaSessionCompat$ResultReceiverWrapper",
+ "android/support/v17/leanback/widget/FocusHighlightHelper": "androidx/leanback/widget/FocusHighlightHelper",
+ "android/support/v4/media/session/MediaControllerCompatApi21$TransportControls": "androidx/media/session/MediaControllerCompatApi21$TransportControls",
+ "android/support/v4/media/MediaBrowserCompatApi21$SubscriptionCallbackProxy": "androidx/media/MediaBrowserCompatApi21$SubscriptionCallbackProxy",
+ "android/support/v7/mediarouter/R$dimen": "androidx/mediarouter/R$dimen",
+ "android/support/v4/app/NotificationManagerCompat$CancelTask": "androidx/app/NotificationManagerCompat$CancelTask",
+ "android/support/design/widget/BottomSheetBehavior$BottomSheetCallback": "androidx/design/widget/BottomSheetBehavior$BottomSheetCallback",
+ "android/support/v4/os/LocaleListCompat": "androidx/os/LocaleListCompat",
+ "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase$MediaServiceConnection": "androidx/media/MediaBrowserCompat$MediaBrowserImplBase$MediaServiceConnection",
+ "android/support/design/internal/BottomNavigationPresenter": "androidx/design/internal/BottomNavigationPresenter",
+ "android/support/v7/view/SupportMenuInflater": "androidx/view/SupportMenuInflater",
+ "android/support/v4/app/ActivityOptionsCompat$ActivityOptionsCompatApi16Impl": "androidx/app/ActivityOptionsCompat$ActivityOptionsCompatApi16Impl",
+ "android/support/transition/AutoTransition": "androidx/transition/AutoTransition",
+ "android/support/v7/widget/RoundRectDrawable": "androidx/widget/RoundRectDrawable",
+ "android/support/graphics/drawable/VectorDrawableCompat$VFullPath": "androidx/graphics/drawable/VectorDrawableCompat$VFullPath",
+ "android/support/v4/widget/ListViewAutoScrollHelper": "androidx/widget/ListViewAutoScrollHelper",
+ "android/support/v4/media/MediaBrowserCompatApi21$MediaItem": "androidx/media/MediaBrowserCompatApi21$MediaItem",
+ "android/support/transition/FloatArrayEvaluator": "androidx/transition/FloatArrayEvaluator",
+ "android/support/design/widget/CollapsingToolbarLayout$OffsetUpdateListener": "androidx/design/widget/CollapsingToolbarLayout$OffsetUpdateListener",
+ "android/support/v7/preference/PreferenceManager$OnPreferenceTreeClickListener": "androidx/preference/PreferenceManager$OnPreferenceTreeClickListener",
+ "android/support/v17/leanback/widget/Parallax": "androidx/leanback/widget/Parallax",
+ "android/support/v4/media/MediaBrowserCompat$ConnectionCallback$StubApi21": "androidx/media/MediaBrowserCompat$ConnectionCallback$StubApi21",
+ "android/support/v4/os/CancellationSignal": "androidx/os/CancellationSignal",
+ "android/support/v17/leanback/media/PlaybackGlue$PlayerCallback": "androidx/leanback/media/PlaybackGlue$PlayerCallback",
+ "android/support/v4/widget/CompoundButtonCompat$CompoundButtonCompatApi21Impl": "androidx/widget/CompoundButtonCompat$CompoundButtonCompatApi21Impl",
+ "android/support/design/internal/BottomNavigationItemView": "androidx/design/internal/BottomNavigationItemView",
+ "android/support/v4/view/ViewGroupCompat$ViewGroupCompatApi18Impl": "androidx/view/ViewGroupCompat$ViewGroupCompatApi18Impl",
+ "android/support/text/emoji/flatbuffer/Struct": "androidx/text/emoji/flatbuffer/Struct",
+ "android/support/v17/leanback/widget/VerticalGridPresenter$VerticalGridItemBridgeAdapter": "androidx/leanback/widget/VerticalGridPresenter$VerticalGridItemBridgeAdapter",
+ "android/support/v4/view/ViewCompat$ViewCompatApi21Impl": "androidx/view/ViewCompat$ViewCompatApi21Impl",
+ "android/support/v17/leanback/widget/SearchEditText$OnKeyboardDismissListener": "androidx/leanback/widget/SearchEditText$OnKeyboardDismissListener",
+ "android/support/annotation/AttrRes": "androidx/annotation/AttrRes",
+ "android/support/v17/leanback/app/BrowseFragment$FragmentHostImpl": "androidx/leanback/app/BrowseFragment$FragmentHostImpl",
+ "android/support/v4/graphics/PathParser": "androidx/graphics/PathParser",
+ "android/support/v17/leanback/app/BackgroundManager$BitmapDrawable": "androidx/leanback/app/BackgroundManager$BitmapDrawable",
+ "android/support/v4/util/MapCollections$ArrayIterator": "androidx/util/MapCollections$ArrayIterator",
+ "android/support/v4/view/AsyncLayoutInflater": "androidx/view/AsyncLayoutInflater",
+ "android/support/v4/media/MediaBrowserServiceCompat$Result": "androidx/media/MediaBrowserServiceCompat$Result",
+ "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImpl": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImpl",
+ "android/support/v17/leanback/app/RowsFragment$MainFragmentAdapter": "androidx/leanback/app/RowsFragment$MainFragmentAdapter",
+ "android/support/v17/internal/widget/OutlineOnlyWithChildrenFrameLayout": "androidx/internal/widget/OutlineOnlyWithChildrenFrameLayout",
+ "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi21$ExtraSession": "androidx/media/session/MediaSessionCompat$MediaSessionImplApi21$ExtraSession",
+ "android/support/v17/leanback/util/MathUtil": "androidx/leanback/util/MathUtil",
+ "android/support/v4/app/RemoteInputCompatBase$RemoteInput$Factory": "androidx/app/RemoteInputCompatBase$RemoteInput$Factory",
+ "android/support/animation/DynamicAnimation": "androidx/animation/DynamicAnimation",
+ "android/support/transition/Visibility": "androidx/transition/Visibility",
+ "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatApi21Impl": "androidx/widget/PopupWindowCompat$PopupWindowCompatApi21Impl",
+ "android/support/v7/app/AppCompatViewInflater": "androidx/app/AppCompatViewInflater",
+ "android/support/v7/widget/ListPopupWindow$PopupTouchInterceptor": "androidx/widget/ListPopupWindow$PopupTouchInterceptor",
+ "android/support/v4/app/ServiceCompat$StopForegroundFlags": "androidx/app/ServiceCompat$StopForegroundFlags",
+ "android/support/graphics/drawable/VectorDrawableCompat$VClipPath": "androidx/graphics/drawable/VectorDrawableCompat$VClipPath",
+ "android/support/v7/app/MediaRouteControllerDialog$VolumeGroupAdapter": "androidx/app/MediaRouteControllerDialog$VolumeGroupAdapter",
+ "android/support/design/R$style": "androidx/design/R$style",
+ "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi26": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi26",
+ "android/support/constraint/R$styleable": "androidx/constraint/R$styleable",
+ "android/support/v7/media/MediaRouterJellybeanMr1$RouteInfo": "androidx/media/MediaRouterJellybeanMr1$RouteInfo",
+ "android/support/v4/widget/CircleImageView$OvalShadow": "androidx/widget/CircleImageView$OvalShadow",
+ "android/support/v7/preference/ListPreferenceDialogFragmentCompat": "androidx/preference/ListPreferenceDialogFragmentCompat",
+ "android/support/v7/preference/PreferenceFragmentCompat$OnPreferenceStartFragmentCallback": "androidx/preference/PreferenceFragmentCompat$OnPreferenceStartFragmentCallback",
+ "android/support/v4/view/PagerTitleStrip$PageListener": "androidx/view/PagerTitleStrip$PageListener",
+ "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi21": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi21",
+ "android/support/v7/app/AppCompatDelegate$ApplyableNightMode": "androidx/app/AppCompatDelegate$ApplyableNightMode",
+ "android/support/customtabs/ICustomTabsCallback": "androidx/browser/customtabs/ICustomTabsCallback",
+ "android/support/v17/preference/LeanbackListPreferenceDialogFragment": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment",
+ "android/support/v17/leanback/widget/PresenterSwitcher": "androidx/leanback/widget/PresenterSwitcher",
+ "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi23": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi23",
+ "android/support/v17/leanback/widget/ShadowOverlayHelper$Options": "androidx/leanback/widget/ShadowOverlayHelper$Options",
+ "android/support/v4/text/TextDirectionHeuristicsCompat$FirstStrong": "androidx/text/TextDirectionHeuristicsCompat$FirstStrong",
+ "android/support/v7/widget/AppCompatSeekBar": "androidx/widget/AppCompatSeekBar",
+ "android/support/v17/leanback/widget/Util": "androidx/leanback/widget/Util",
+ "android/support/v4/util/MapCollections": "androidx/util/MapCollections",
+ "android/support/v4/widget/NestedScrollView$SavedState": "androidx/widget/NestedScrollView$SavedState",
+ "android/support/v7/widget/SimpleItemAnimator": "androidx/widget/SimpleItemAnimator",
+ "android/support/v4/media/MediaMetadataCompatApi21$Builder": "androidx/media/MediaMetadataCompatApi21$Builder",
+ "android/support/design/widget/DrawableUtils": "androidx/design/widget/DrawableUtils",
+ "android/support/wear/internal/widget/drawer/SinglePagePresenter": "androidx/wear/internal/widget/drawer/SinglePagePresenter",
+ "android/support/v4/app/FragmentContainer": "androidx/app/FragmentContainer",
+ "android/support/v7/media/MediaRouteProviderDescriptor": "androidx/media/MediaRouteProviderDescriptor",
+ "android/support/v4/media/session/PlaybackStateCompat$Actions": "androidx/media/session/PlaybackStateCompat$Actions",
+ "android/support/v14/preference/ListPreferenceDialogFragment": "androidx/preference/ListPreferenceDialogFragment",
+ "android/support/v4/widget/SwipeRefreshLayout$OnChildScrollUpCallback": "androidx/widget/SwipeRefreshLayout$OnChildScrollUpCallback",
+ "android/support/v4/media/AudioAttributesCompatApi21": "androidx/media/AudioAttributesCompatApi21",
+ "android/support/v7/media/MediaRouter$Callback": "androidx/media/MediaRouter$Callback",
+ "android/support/v4/content/pm/ShortcutInfoCompat$Builder": "androidx/content/pm/ShortcutInfoCompat$Builder",
+ "android/support/v7/util/SortedList$BatchedCallback": "androidx/util/SortedList$BatchedCallback",
+ "android/support/v7/cardview/R$style": "androidx/cardview/R$style",
+ "android/support/v7/media/MediaRouter$GlobalMediaRouter$ProviderCallback": "androidx/media/MediaRouter$GlobalMediaRouter$ProviderCallback",
+ "android/support/v4/widget/SimpleCursorAdapter$ViewBinder": "androidx/widget/SimpleCursorAdapter$ViewBinder",
+ "android/support/v7/util/TileList$Tile": "androidx/util/TileList$Tile",
+ "android/support/v17/leanback/widget/ItemBridgeAdapter$AdapterListener": "androidx/leanback/widget/ItemBridgeAdapter$AdapterListener",
+ "android/support/v4/widget/SlidingPaneLayout$DragHelperCallback": "androidx/widget/SlidingPaneLayout$DragHelperCallback",
+ "android/support/v4/media/MediaBrowserCompat$SearchResultReceiver": "androidx/media/MediaBrowserCompat$SearchResultReceiver",
+ "android/support/v17/leanback/widget/PlaybackRowPresenter": "androidx/leanback/widget/PlaybackRowPresenter",
+ "android/support/v7/media/MediaRouteProvider$ProviderMetadata": "androidx/media/MediaRouteProvider$ProviderMetadata",
+ "android/support/text/emoji/flatbuffer/MetadataList": "androidx/text/emoji/flatbuffer/MetadataList",
+ "android/support/v4/provider/TreeDocumentFile": "androidx/provider/TreeDocumentFile",
+ "android/support/v7/media/MediaSessionStatus$Builder": "androidx/media/MediaSessionStatus$Builder",
+ "android/support/text/emoji/widget/EmojiTextWatcher": "androidx/text/emoji/widget/EmojiTextWatcher",
+ "android/support/v17/leanback/app/GuidedStepSupportFragment": "androidx/leanback/app/GuidedStepSupportFragment",
+ "android/support/v17/leanback/widget/BrowseFrameLayout$OnFocusSearchListener": "androidx/leanback/widget/BrowseFrameLayout$OnFocusSearchListener",
+ "android/support/animation/AnimationHandler": "androidx/animation/AnimationHandler",
+ "android/support/wear/widget/drawer/WearableActionDrawerView": "androidx/wear/widget/drawer/WearableActionDrawerView",
+ "android/support/v4/media/MediaBrowserCompat$CustomActionResultReceiver": "androidx/media/MediaBrowserCompat$CustomActionResultReceiver",
+ "android/support/v7/widget/AppCompatSeekBarHelper": "androidx/widget/AppCompatSeekBarHelper",
+ "android/support/v4/widget/SlidingPaneLayout$AccessibilityDelegate": "androidx/widget/SlidingPaneLayout$AccessibilityDelegate",
+ "android/support/v17/leanback/widget/TitleViewAdapter$Provider": "androidx/leanback/widget/TitleViewAdapter$Provider",
+ "android/support/v7/widget/GridLayoutManager$SpanSizeLookup": "androidx/widget/GridLayoutManager$SpanSizeLookup",
+ "android/support/v4/content/res/ResourcesCompat$FontCallback": "androidx/content/res/ResourcesCompat$FontCallback",
+ "android/support/v4/util/CircularArray": "androidx/util/CircularArray",
+ "android/support/v17/leanback/util/StateMachine$State": "androidx/leanback/util/StateMachine$State",
+ "android/support/text/emoji/widget/EmojiTextView": "androidx/text/emoji/widget/EmojiTextView",
+ "android/support/v4/widget/CursorAdapter$MyDataSetObserver": "androidx/widget/CursorAdapter$MyDataSetObserver",
+ "android/support/v4/os/LocaleListCompat$LocaleListCompatBaseImpl": "androidx/os/LocaleListCompat$LocaleListCompatBaseImpl",
+ "android/support/v4/app/TaskStackBuilder$SupportParentable": "androidx/app/TaskStackBuilder$SupportParentable",
+ "android/support/v17/leanback/media/PlaybackControlGlue": "androidx/leanback/media/PlaybackControlGlue",
+ "android/support/v17/leanback/widget/GuidedActionEditText": "androidx/leanback/widget/GuidedActionEditText",
+ "android/support/v4/util/Pools$SimplePool": "androidx/util/Pools$SimplePool",
+ "android/support/v17/leanback/widget/ControlButtonPresenterSelector$ControlButtonPresenter": "androidx/leanback/widget/ControlButtonPresenterSelector$ControlButtonPresenter",
+ "android/support/v17/leanback/widget/PlaybackControlsPresenter$ViewHolder": "androidx/leanback/widget/PlaybackControlsPresenter$ViewHolder",
+ "android/support/wear/widget/drawer/WearableDrawerLayout": "androidx/wear/widget/drawer/WearableDrawerLayout",
+ "android/support/v7/widget/ActionBarContainer": "androidx/widget/ActionBarContainer",
+ "android/support/v7/widget/ShareActionProvider$ShareActivityChooserModelPolicy": "androidx/widget/ShareActionProvider$ShareActivityChooserModelPolicy",
+ "android/support/transition/ObjectAnimatorUtilsApi21": "androidx/transition/ObjectAnimatorUtilsApi21",
+ "android/support/v17/leanback/widget/BaseOnItemViewSelectedListener": "androidx/leanback/widget/BaseOnItemViewSelectedListener",
+ "android/support/v7/widget/StaggeredGridLayoutManager$LayoutParams": "androidx/widget/StaggeredGridLayoutManager$LayoutParams",
+ "android/support/v7/mediarouter/R$interpolator": "androidx/mediarouter/R$interpolator",
+ "android/support/v4/media/VolumeProviderCompatApi21": "androidx/media/VolumeProviderCompatApi21",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$PictureInPictureAction": "androidx/leanback/widget/PlaybackControlsRow$PictureInPictureAction",
+ "android/support/v7/util/MessageThreadUtil": "androidx/util/MessageThreadUtil",
+ "android/support/v4/util/LogWriter": "androidx/util/LogWriter",
+ "android/support/v7/preference/PreferenceDialogFragmentCompat": "androidx/preference/PreferenceDialogFragmentCompat",
+ "android/support/transition/ViewOverlayApi14": "androidx/transition/ViewOverlayApi14",
+ "android/support/v4/graphics/TypefaceCompatUtil": "androidx/graphics/TypefaceCompatUtil",
+ "android/support/media/tv/BasePreviewProgram": "androidx/media/tv/BasePreviewProgram",
+ "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder$DetailsOverviewRowListener": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder$DetailsOverviewRowListener",
+ "android/support/v7/widget/AlertDialogLayout": "androidx/widget/AlertDialogLayout",
+ "android/support/v7/widget/ActionBarOverlayLayout$LayoutParams": "androidx/widget/ActionBarOverlayLayout$LayoutParams",
+ "android/support/v4/view/NestedScrollingParentHelper": "androidx/view/NestedScrollingParentHelper",
+ "android/support/transition/ObjectAnimatorUtilsApi14": "androidx/transition/ObjectAnimatorUtilsApi14",
+ "android/support/text/emoji/EmojiCompat": "androidx/text/emoji/EmojiCompat",
+ "android/support/v4/media/MediaBrowserServiceCompatApi23$ServiceCompatProxy": "androidx/media/MediaBrowserServiceCompatApi23$ServiceCompatProxy",
+ "android/support/v17/leanback/widget/FocusHighlightHelper$FocusAnimator": "androidx/leanback/widget/FocusHighlightHelper$FocusAnimator",
+ "android/support/v17/leanback/app/PlaybackSupportFragment$SetSelectionRunnable": "androidx/leanback/app/PlaybackSupportFragment$SetSelectionRunnable",
+ "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatApi23Impl": "androidx/widget/PopupWindowCompat$PopupWindowCompatApi23Impl",
+ "android/support/v7/preference/SwitchPreferenceCompat": "androidx/preference/SwitchPreferenceCompat",
+ "android/support/wear/widget/drawer/FlingWatcherFactory$FlingListener": "androidx/wear/widget/drawer/FlingWatcherFactory$FlingListener",
+ "android/support/v7/widget/ShareActionProvider": "androidx/widget/ShareActionProvider",
+ "android/support/v7/content/res/AppCompatResources": "androidx/content/res/AppCompatResources",
+ "android/support/transition/ViewOverlayApi18": "androidx/transition/ViewOverlayApi18",
+ "android/support/v7/widget/ListPopupWindow$ResizePopupRunnable": "androidx/widget/ListPopupWindow$ResizePopupRunnable",
+ "android/support/compat/R$integer": "androidx/compat/R$integer",
+ "android/support/v4/app/ActionBarDrawerToggle$SlideDrawable": "androidx/app/ActionBarDrawerToggle$SlideDrawable",
+ "android/support/transition/ChangeTransform$PathAnimatorMatrix": "androidx/transition/ChangeTransform$PathAnimatorMatrix",
+ "android/support/v17/leanback/graphics/ColorFilterDimmer": "androidx/leanback/graphics/ColorFilterDimmer",
+ "android/support/v7/media/MediaRouteDescriptor": "androidx/media/MediaRouteDescriptor",
+ "android/support/v7/preference/R$id": "androidx/preference/R$id",
+ "android/support/v14/preference/PreferenceFragment$ScrollToPreferenceObserver": "androidx/preference/PreferenceFragment$ScrollToPreferenceObserver",
+ "android/support/v4/internal/package-info": "androidx/internal/package-info",
+ "android/support/v4/media/MediaBrowserCompatApi21$SubscriptionCallback": "androidx/media/MediaBrowserCompatApi21$SubscriptionCallback",
+ "android/support/v7/view/menu/MenuHelper": "androidx/view/menu/MenuHelper",
+ "android/support/v17/leanback/widget/SpeechOrbView": "androidx/leanback/widget/SpeechOrbView",
+ "android/support/v7/media/SystemMediaRouteProvider$JellybeanImpl$SystemRouteController": "androidx/media/SystemMediaRouteProvider$JellybeanImpl$SystemRouteController",
+ "android/support/v7/widget/FitWindowsFrameLayout": "androidx/widget/FitWindowsFrameLayout",
+ "android/support/v7/preference/TwoStatePreference$SavedState": "androidx/preference/TwoStatePreference$SavedState",
+ "android/support/v17/leanback/widget/ShadowOverlayHelper$Builder": "androidx/leanback/widget/ShadowOverlayHelper$Builder",
+ "android/support/v17/leanback/widget/InvisibleRowPresenter": "androidx/leanback/widget/InvisibleRowPresenter",
+ "android/support/design/internal/NavigationMenuPresenter$SeparatorViewHolder": "androidx/design/internal/NavigationMenuPresenter$SeparatorViewHolder",
+ "android/support/design/widget/BaseTransientBottomBar$Duration": "androidx/design/widget/BaseTransientBottomBar$Duration",
+ "android/support/v7/widget/helper/ItemTouchUIUtilImpl": "androidx/widget/helper/ItemTouchUIUtilImpl",
+ "android/support/v17/leanback/widget/GuidedActionsRelativeLayout$InterceptKeyEventListener": "androidx/leanback/widget/GuidedActionsRelativeLayout$InterceptKeyEventListener",
+ "android/support/v4/os/IResultReceiver": "androidx/os/IResultReceiver",
+ "android/support/v17/leanback/widget/ShadowHelperApi21": "androidx/leanback/widget/ShadowHelperApi21",
+ "android/support/v17/leanback/widget/RowPresenter": "androidx/leanback/widget/RowPresenter",
+ "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase": "androidx/media/MediaBrowserCompat$MediaBrowserImplBase",
+ "android/support/v4/app/BackStackRecord": "androidx/app/BackStackRecord",
+ "android/support/v4/view/WindowInsetsCompat": "androidx/view/WindowInsetsCompat",
+ "android/support/graphics/drawable/AnimatedVectorDrawableCompat": "androidx/graphics/drawable/AnimatedVectorDrawableCompat",
+ "android/support/v17/leanback/widget/PlaybackControlsRowPresenter": "androidx/leanback/widget/PlaybackControlsRowPresenter",
+ "android/support/transition/VisibilityPropagation": "androidx/transition/VisibilityPropagation",
+ "android/support/v17/leanback/media/PlaybackTransportControlGlue": "androidx/leanback/media/PlaybackTransportControlGlue",
+ "android/support/wear/widget/BoxInsetLayout$LayoutParams$BoxedEdges": "androidx/wear/widget/BoxInsetLayout$LayoutParams$BoxedEdges",
+ "android/support/annotation/LayoutRes": "androidx/annotation/LayoutRes",
+ "android/support/v4/widget/CursorAdapter": "androidx/widget/CursorAdapter",
+ "android/support/wear/ambient/AmbientMode$AmbientCallback": "androidx/wear/ambient/AmbientMode$AmbientCallback",
+ "android/support/v4/media/MediaBrowserServiceCompatApi21$BrowserRoot": "androidx/media/MediaBrowserServiceCompatApi21$BrowserRoot",
+ "android/support/v7/view/menu/MenuItemWrapperJB": "androidx/view/menu/MenuItemWrapperJB",
+ "android/support/text/emoji/widget/EmojiAppCompatButton": "androidx/text/emoji/widget/EmojiAppCompatButton",
+ "android/support/v4/view/ActionProvider$SubUiVisibilityListener": "androidx/view/ActionProvider$SubUiVisibilityListener",
+ "android/support/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuItem$MenuItemChangedListener": "androidx/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuItem$MenuItemChangedListener",
+ "android/support/v4/media/MediaBrowserCompat$ServiceBinderWrapper": "androidx/media/MediaBrowserCompat$ServiceBinderWrapper",
+ "android/support/v13/app/ActivityCompat": "androidx/app/ActivityCompat",
+ "android/support/v4/widget/ImageViewCompat$LollipopViewCompatImpl": "androidx/widget/ImageViewCompat$LollipopViewCompatImpl",
+ "android/support/annotation/UiThread": "androidx/annotation/UiThread",
+ "android/support/v4/media/session/MediaControllerCompatApi24": "androidx/media/session/MediaControllerCompatApi24",
+ "android/support/v7/media/RemoteControlClientCompat$JellybeanImpl$VolumeCallbackWrapper": "androidx/media/RemoteControlClientCompat$JellybeanImpl$VolumeCallbackWrapper",
+ "android/support/v4/media/session/MediaControllerCompatApi23": "androidx/media/session/MediaControllerCompatApi23",
+ "android/support/v4/media/session/MediaControllerCompatApi21": "androidx/media/session/MediaControllerCompatApi21",
+ "android/support/v4/print/PrintHelper$ScaleMode": "androidx/print/PrintHelper$ScaleMode",
+ "android/support/v7/widget/SearchView$SavedState": "androidx/widget/SearchView$SavedState",
+ "android/support/v7/widget/AppCompatDrawableManager$AvdcInflateDelegate": "androidx/widget/AppCompatDrawableManager$AvdcInflateDelegate",
+ "android/support/v7/preference/TwoStatePreference": "androidx/preference/TwoStatePreference",
+ "android/support/text/emoji/EmojiCompat$LoadState": "androidx/text/emoji/EmojiCompat$LoadState",
+ "android/support/v17/leanback/widget/HorizontalGridView": "androidx/leanback/widget/HorizontalGridView",
+ "android/support/v7/view/menu/ListMenuItemView": "androidx/view/menu/ListMenuItemView",
+ "android/support/transition/Styleable$TransitionSet": "androidx/transition/Styleable$TransitionSet",
+ "android/support/v17/leanback/app/PlaybackFragment$OnFadeCompleteListener": "androidx/leanback/app/PlaybackFragment$OnFadeCompleteListener",
+ "android/support/v7/widget/ActivityChooserModel$PersistHistoryAsyncTask": "androidx/widget/ActivityChooserModel$PersistHistoryAsyncTask",
+ "android/support/v4/util/ArraySet": "androidx/util/ArraySet",
+ "android/support/v7/widget/FastScroller$AnimationState": "androidx/widget/FastScroller$AnimationState",
+ "android/support/v7/widget/RecyclerView$ChildDrawingOrderCallback": "androidx/widget/RecyclerView$ChildDrawingOrderCallback",
+ "android/support/text/emoji/flatbuffer/Constants": "androidx/text/emoji/flatbuffer/Constants",
+ "android/support/v4/widget/DrawerLayout$LayoutParams": "androidx/widget/DrawerLayout$LayoutParams",
+ "android/support/v4/app/TaskStackBuilder": "androidx/app/TaskStackBuilder",
+ "android/support/v7/widget/ListPopupWindow$PopupDataSetObserver": "androidx/widget/ListPopupWindow$PopupDataSetObserver",
+ "android/support/v4/media/session/MediaSessionCompatApi24$CallbackProxy": "androidx/media/session/MediaSessionCompatApi24$CallbackProxy",
+ "android/support/v17/leanback/app/RowsSupportFragment$MainFragmentRowsAdapter": "androidx/leanback/app/RowsSupportFragment$MainFragmentRowsAdapter",
+ "android/support/v17/leanback/widget/picker/DatePicker": "androidx/leanback/widget/picker/DatePicker",
+ "android/support/v17/leanback/widget/SearchBar$SearchBarPermissionListener": "androidx/leanback/widget/SearchBar$SearchBarPermissionListener",
+ "android/support/v7/media/MediaItemMetadata": "androidx/media/MediaItemMetadata",
+ "android/support/v17/leanback/widget/ListRowPresenter": "androidx/leanback/widget/ListRowPresenter",
+ "android/support/v17/leanback/media/PlaybackBannerControlGlue$ACTION_": "androidx/leanback/media/PlaybackBannerControlGlue$ACTION_",
+ "android/support/v4/app/RemoteInput": "androidx/app/RemoteInput",
+ "android/support/text/emoji/MetadataListReader$ByteBufferReader": "androidx/text/emoji/MetadataListReader$ByteBufferReader",
+ "android/support/v17/leanback/widget/SearchEditText": "androidx/leanback/widget/SearchEditText",
+ "android/support/v4/app/NotificationCompat$CarExtender$UnreadConversation$Builder": "androidx/app/NotificationCompat$CarExtender$UnreadConversation$Builder",
+ "android/support/v7/preference/SeekBarPreference": "androidx/preference/SeekBarPreference",
+ "android/support/v17/leanback/R$transition": "androidx/leanback/R$transition",
+ "android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory": "androidx/graphics/drawable/RoundedBitmapDrawableFactory",
+ "android/support/v7/widget/PositionMap$ContainerHelpers": "androidx/widget/PositionMap$ContainerHelpers",
+ "android/support/v4/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListenerWrapper": "androidx/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListenerWrapper",
+ "android/support/design/widget/ViewUtils": "androidx/design/widget/ViewUtils",
+ "android/support/v4/widget/CompoundButtonCompat$CompoundButtonCompatApi23Impl": "androidx/widget/CompoundButtonCompat$CompoundButtonCompatApi23Impl",
+ "android/support/v7/widget/StaggeredGridLayoutManager$SavedState": "androidx/widget/StaggeredGridLayoutManager$SavedState",
+ "android/support/transition/PathMotion": "androidx/transition/PathMotion",
+ "android/support/wear/widget/drawer/WearableDrawerView": "androidx/wear/widget/drawer/WearableDrawerView",
+ "android/support/v4/media/VolumeProviderCompat$ControlType": "androidx/media/VolumeProviderCompat$ControlType",
+ "android/support/v4/view/animation/PathInterpolatorApi14": "androidx/view/animation/PathInterpolatorApi14",
+ "android/support/animation/AnimationHandler$FrameCallbackProvider16": "androidx/animation/AnimationHandler$FrameCallbackProvider16",
+ "android/support/v4/view/animation/FastOutSlowInInterpolator": "androidx/view/animation/FastOutSlowInInterpolator",
+ "android/support/animation/AnimationHandler$FrameCallbackProvider14": "androidx/animation/AnimationHandler$FrameCallbackProvider14",
+ "android/support/customtabs/CustomTabsServiceConnection": "androidx/browser/customtabs/CustomTabsServiceConnection",
+ "android/support/v17/leanback/app/BackgroundFragment": "androidx/leanback/app/BackgroundFragment",
+ "android/support/v17/leanback/widget/FocusHighlightHelper$BrowseItemFocusHighlight": "androidx/leanback/widget/FocusHighlightHelper$BrowseItemFocusHighlight",
+ "android/support/v17/leanback/app/HeadersFragment$OnHeaderClickedListener": "androidx/leanback/app/HeadersFragment$OnHeaderClickedListener",
+ "android/support/v7/media/MediaRouter$RouteInfo": "androidx/media/MediaRouter$RouteInfo",
+ "android/support/v14/preference/PreferenceFragment": "androidx/preference/PreferenceFragment",
+ "android/support/v4/media/session/PlaybackStateCompat$MediaKeyAction": "androidx/media/session/PlaybackStateCompat$MediaKeyAction",
+ "android/support/v17/leanback/widget/TitleView": "androidx/leanback/widget/TitleView",
+ "android/support/graphics/drawable/VectorDrawableCompat$VPath": "androidx/graphics/drawable/VectorDrawableCompat$VPath",
+ "android/support/v17/leanback/widget/AbstractMediaItemPresenter$ViewHolder": "androidx/leanback/widget/AbstractMediaItemPresenter$ViewHolder",
+ "android/support/v17/leanback/widget/BrowseRowsFrameLayout": "androidx/leanback/widget/BrowseRowsFrameLayout",
+ "android/support/v7/content/res/AppCompatResources$ColorStateListCacheEntry": "androidx/content/res/AppCompatResources$ColorStateListCacheEntry",
+ "android/support/design/R$dimen": "androidx/design/R$dimen",
+ "android/support/v7/preference/PreferenceInflater": "androidx/preference/PreferenceInflater",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$PlayPauseAction": "androidx/leanback/widget/PlaybackControlsRow$PlayPauseAction",
+ "android/support/v17/leanback/widget/PlaybackTransportRowPresenter": "androidx/leanback/widget/PlaybackTransportRowPresenter",
+ "android/support/wear/BuildConfig": "androidx/wear/BuildConfig",
+ "android/support/wear/widget/CircledImageView": "androidx/wear/widget/CircledImageView",
+ "android/support/v7/media/MediaRouterJellybean$SelectRouteWorkaround": "androidx/media/MediaRouterJellybean$SelectRouteWorkaround",
+ "android/support/v17/leanback/widget/ListRowHoverCardView": "androidx/leanback/widget/ListRowHoverCardView",
+ "android/support/v7/media/MediaRouterJellybean$GetDefaultRouteWorkaround": "androidx/media/MediaRouterJellybean$GetDefaultRouteWorkaround",
+ "android/support/text/emoji/widget/SpannableBuilder$WatcherWrapper": "androidx/text/emoji/widget/SpannableBuilder$WatcherWrapper",
+ "android/support/v17/preference/LeanbackListPreferenceDialogFragment$AdapterSingle": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment$AdapterSingle",
+ "android/support/v17/leanback/app/OnboardingFragment": "androidx/leanback/app/OnboardingFragment",
+ "android/support/v7/view/menu/MenuPresenter$Callback": "androidx/view/menu/MenuPresenter$Callback",
+ "android/support/v4/graphics/drawable/DrawableWrapperApi14$DrawableWrapperStateBase": "androidx/graphics/drawable/DrawableWrapperApi14$DrawableWrapperStateBase",
+ "android/support/v17/leanback/graphics/CompositeDrawable$ChildDrawable": "androidx/leanback/graphics/CompositeDrawable$ChildDrawable",
+ "android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter$ViewHolder": "androidx/leanback/widget/AbstractMediaListHeaderPresenter$ViewHolder",
+ "android/support/v7/view/menu/MenuItemWrapperICS$OnMenuItemClickListenerWrapper": "androidx/view/menu/MenuItemWrapperICS$OnMenuItemClickListenerWrapper",
+ "android/support/v7/widget/ContentFrameLayout$OnAttachListener": "androidx/widget/ContentFrameLayout$OnAttachListener",
+ "android/support/v17/leanback/widget/StaticShadowHelper": "androidx/leanback/widget/StaticShadowHelper",
+ "android/support/v7/widget/RecyclerView$OnScrollListener": "androidx/widget/RecyclerView$OnScrollListener",
+ "android/support/v17/leanback/graphics/FitWidthBitmapDrawable$BitmapState": "androidx/leanback/graphics/FitWidthBitmapDrawable$BitmapState",
+ "android/support/v17/leanback/widget/SeekBar": "androidx/leanback/widget/SeekBar",
+ "android/support/v4/widget/SlidingPaneLayout$SimplePanelSlideListener": "androidx/widget/SlidingPaneLayout$SimplePanelSlideListener",
+ "android/support/v17/leanback/widget/RowContainerView": "androidx/leanback/widget/RowContainerView",
+ "android/support/v7/widget/ForwardingListener$DisallowIntercept": "androidx/widget/ForwardingListener$DisallowIntercept",
+ "android/support/v7/app/AppCompatDelegateImplBase": "androidx/app/AppCompatDelegateImplBase",
+ "android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost": "androidx/leanback/app/PlaybackSupportFragmentGlueHost",
+ "android/support/transition/Styleable$Transition": "androidx/transition/Styleable$Transition",
+ "android/support/v7/widget/ActionMenuPresenter": "androidx/widget/ActionMenuPresenter",
+ "android/support/v7/app/ActionBar$DisplayOptions": "androidx/app/ActionBar$DisplayOptions",
+ "android/support/v4/app/ShareCompat$IntentBuilder": "androidx/app/ShareCompat$IntentBuilder",
+ "android/support/v4/media/MediaMetadataCompat$LongKey": "androidx/media/MediaMetadataCompat$LongKey",
+ "android/support/v4/media/AudioAttributesCompatApi21$Wrapper": "androidx/media/AudioAttributesCompatApi21$Wrapper",
+ "android/support/exifinterface/BuildConfig": "androidx/exifinterface/BuildConfig",
+ "android/support/v17/leanback/widget/DetailsOverviewRow": "androidx/leanback/widget/DetailsOverviewRow",
+ "android/support/annotation/IdRes": "androidx/annotation/IdRes",
+ "android/support/v7/widget/ActivityChooserModel$HistoricalRecord": "androidx/widget/ActivityChooserModel$HistoricalRecord",
+ "android/support/v17/leanback/widget/SearchOrbView$Colors": "androidx/leanback/widget/SearchOrbView$Colors",
+ "android/support/v7/content/res/GrowingArrayUtils": "androidx/content/res/GrowingArrayUtils",
+ "android/support/text/emoji/MetadataRepo$Node": "androidx/text/emoji/MetadataRepo$Node",
+ "android/support/v17/leanback/app/BrowseFragment$MainFragmentItemViewSelectedListener": "androidx/leanback/app/BrowseFragment$MainFragmentItemViewSelectedListener",
+ "android/support/v17/leanback/app/SearchSupportFragment$ExternalQuery": "androidx/leanback/app/SearchSupportFragment$ExternalQuery",
+ "android/support/v17/leanback/widget/ShadowHelperJbmr2$ShadowImpl": "androidx/leanback/widget/ShadowHelperJbmr2$ShadowImpl",
+ "android/support/wear/widget/drawer/PageIndicatorView": "androidx/wear/widget/drawer/PageIndicatorView",
+ "android/support/v17/leanback/app/VerticalGridSupportFragment": "androidx/leanback/app/VerticalGridSupportFragment",
+ "android/support/v7/preference/PreferenceGroupAdapter$PreferenceLayout": "androidx/preference/PreferenceGroupAdapter$PreferenceLayout",
+ "android/support/v7/preference/internal/AbstractMultiSelectListPreference": "androidx/preference/internal/AbstractMultiSelectListPreference",
+ "android/support/v7/media/MediaRouteProviderDescriptor$Builder": "androidx/media/MediaRouteProviderDescriptor$Builder",
+ "android/support/v4/app/NotificationCompatSideChannelService": "androidx/app/NotificationCompatSideChannelService",
+ "android/support/v7/widget/GridLayoutManager": "androidx/widget/GridLayoutManager",
+ "android/support/v4/media/AudioAttributesCompat$AttributeUsage": "androidx/media/AudioAttributesCompat$AttributeUsage",
+ "android/support/v4/util/Pools$Pool": "androidx/util/Pools$Pool",
+ "android/support/transition/SidePropagation": "androidx/transition/SidePropagation",
+ "android/support/v17/leanback/widget/PlaybackSeekUi$Client": "androidx/leanback/widget/PlaybackSeekUi$Client",
+ "android/support/media/tv/TvContractCompat$Channels": "androidx/media/tv/TvContractCompat$Channels",
+ "android/support/v7/appcompat/R$style": "androidx/appcompat/R$style",
+ "android/support/v4/app/INotificationSideChannel$Stub": "androidx/app/INotificationSideChannel$Stub",
+ "android/support/compat/R$string": "androidx/compat/R$string",
+ "android/support/v4/os/EnvironmentCompat": "androidx/os/EnvironmentCompat",
+ "android/support/wear/ambient/SharedLibraryVersion": "androidx/wear/ambient/SharedLibraryVersion",
+ "android/support/v7/view/menu/MenuBuilder$Callback": "androidx/view/menu/MenuBuilder$Callback",
+ "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentRowsAdapterProvider": "androidx/leanback/app/BrowseSupportFragment$MainFragmentRowsAdapterProvider",
+ "android/support/v17/leanback/R": "androidx/leanback/R",
+ "android/support/transition/Slide": "androidx/transition/Slide",
+ "android/support/v4/os/ParcelableCompat$ParcelableCompatCreatorHoneycombMR2": "androidx/os/ParcelableCompat$ParcelableCompatCreatorHoneycombMR2",
+ "android/support/v17/leanback/widget/PlaybackSeekUi": "androidx/leanback/widget/PlaybackSeekUi",
+ "android/support/v4/view/ViewPropertyAnimatorUpdateListener": "androidx/view/ViewPropertyAnimatorUpdateListener",
+ "android/support/v4/widget/EdgeEffectCompat$EdgeEffectBaseImpl": "androidx/widget/EdgeEffectCompat$EdgeEffectBaseImpl",
+ "android/support/v7/widget/ForwardingListener$TriggerLongPress": "androidx/widget/ForwardingListener$TriggerLongPress",
+ "android/support/text/emoji/bundled/BuildConfig": "androidx/text/emoji/bundled/BuildConfig",
+ "android/support/v4/app/ActivityCompat$SharedElementCallback23Impl": "androidx/app/ActivityCompat$SharedElementCallback23Impl",
+ "android/support/v4/media/MediaBrowserCompatApi21$ConnectionCallback": "androidx/media/MediaBrowserCompatApi21$ConnectionCallback",
+ "android/support/v4/content/Loader$ForceLoadContentObserver": "androidx/content/Loader$ForceLoadContentObserver",
+ "android/support/v7/widget/ScrollingTabContainerView$TabClickListener": "androidx/widget/ScrollingTabContainerView$TabClickListener",
+ "android/support/v4/widget/TextViewCompat$TextViewCompatApi27Impl": "androidx/widget/TextViewCompat$TextViewCompatApi27Impl",
+ "android/support/v17/leanback/widget/GridLayoutManager$OnLayoutCompleteListener": "androidx/leanback/widget/GridLayoutManager$OnLayoutCompleteListener",
+ "android/support/v4/provider/SelfDestructiveThread$ReplyCallback": "androidx/provider/SelfDestructiveThread$ReplyCallback",
+ "android/support/v4/media/VolumeProviderCompat$Callback": "androidx/media/VolumeProviderCompat$Callback",
+ "android/support/v4/app/NotificationCompat$CarExtender$UnreadConversation": "androidx/app/NotificationCompat$CarExtender$UnreadConversation",
+ "android/support/graphics/drawable/AnimatorInflaterCompat": "androidx/graphics/drawable/AnimatorInflaterCompat",
+ "android/support/compat/R$id": "androidx/compat/R$id",
+ "android/support/v17/leanback/app/DetailsFragment$WaitEnterTransitionTimeout": "androidx/leanback/app/DetailsFragment$WaitEnterTransitionTimeout",
+ "android/support/media/tv/TvContractCompat$Channels$ServiceType": "androidx/media/tv/TvContractCompat$Channels$ServiceType",
+ "android/support/v17/leanback/widget/Presenter$ViewHolder": "androidx/leanback/widget/Presenter$ViewHolder",
+ "android/support/text/emoji/EmojiCompat$Config": "androidx/text/emoji/EmojiCompat$Config",
+ "android/support/v17/leanback/app/BackgroundManager$ChangeBackgroundRunnable": "androidx/leanback/app/BackgroundManager$ChangeBackgroundRunnable",
+ "android/support/v17/leanback/util/StateMachine$Transition": "androidx/leanback/util/StateMachine$Transition",
+ "android/support/v17/leanback/widget/picker/TimePicker": "androidx/leanback/widget/picker/TimePicker",
+ "android/support/v7/media/RegisteredMediaRouteProvider$Controller": "androidx/media/RegisteredMediaRouteProvider$Controller",
+ "android/support/text/emoji/TypefaceEmojiSpan": "androidx/text/emoji/TypefaceEmojiSpan",
+ "android/support/wear/widget/SwipeDismissFrameLayout": "androidx/wear/widget/SwipeDismissFrameLayout",
+ "android/support/v4/media/MediaBrowserCompatUtils": "androidx/media/MediaBrowserCompatUtils",
+ "android/support/v17/leanback/app/HeadersSupportFragment": "androidx/leanback/app/HeadersSupportFragment",
+ "android/support/v7/widget/SearchView$OnQueryTextListener": "androidx/widget/SearchView$OnQueryTextListener",
+ "android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter": "androidx/leanback/widget/AbstractMediaListHeaderPresenter",
+ "android/support/design/widget/BaseTransientBottomBar$OnLayoutChangeListener": "androidx/design/widget/BaseTransientBottomBar$OnLayoutChangeListener",
+ "android/support/v14/preference/R$styleable": "androidx/preference/R$styleable",
+ "android/support/v17/leanback/transition/SlideKitkat": "androidx/leanback/transition/SlideKitkat",
+ "android/support/animation/AnimationHandler$AnimationFrameCallbackProvider": "androidx/animation/AnimationHandler$AnimationFrameCallbackProvider",
+ "android/support/v7/view/menu/ActionMenuItem": "androidx/view/menu/ActionMenuItem",
+ "android/support/v4/view/animation/PathInterpolatorCompat": "androidx/view/animation/PathInterpolatorCompat",
+ "android/support/v7/util/AsyncListUtil$DataCallback": "androidx/util/AsyncListUtil$DataCallback",
+ "android/support/v17/leanback/widget/ListRowPresenter$ListRowPresenterItemBridgeAdapter": "androidx/leanback/widget/ListRowPresenter$ListRowPresenterItemBridgeAdapter",
+ "android/support/v7/mediarouter/R$style": "androidx/mediarouter/R$style",
+ "android/support/customtabs/IPostMessageService$Stub": "androidx/browser/customtabs/IPostMessageService$Stub",
+ "android/support/v17/preference/BuildConfig": "androidx/leanback/preference/BuildConfig",
+ "android/support/wear/widget/CircularProgressLayout$OnTimerFinishedListener": "androidx/wear/widget/CircularProgressLayout$OnTimerFinishedListener",
+ "android/support/v7/widget/ActivityChooserModel$OnChooseActivityListener": "androidx/widget/ActivityChooserModel$OnChooseActivityListener",
+ "android/support/v4/graphics/drawable/DrawableWrapperApi21": "androidx/graphics/drawable/DrawableWrapperApi21",
+ "android/support/design/widget/FloatingActionButton$Size": "androidx/design/widget/FloatingActionButton$Size",
+ "android/support/v4/provider/DocumentFile": "androidx/provider/DocumentFile",
+ "android/support/v7/app/AppCompatDelegateImplBase$AppCompatWindowCallbackBase": "androidx/app/AppCompatDelegateImplBase$AppCompatWindowCallbackBase",
+ "android/support/annotation/AnyThread": "androidx/annotation/AnyThread",
+ "android/support/v13/app/FragmentCompat$FragmentCompatApi24Impl": "androidx/app/FragmentCompat$FragmentCompatApi24Impl",
+ "android/support/wear/ambient/SharedLibraryVersion$VersionHolder": "androidx/wear/ambient/SharedLibraryVersion$VersionHolder",
+ "android/support/v7/app/WindowDecorActionBar$ActionModeImpl": "androidx/app/WindowDecorActionBar$ActionModeImpl",
+ "android/support/constraint/solver/widgets/Guideline": "androidx/constraint/solver/widgets/Guideline",
+ "android/support/v17/leanback/widget/NonOverlappingView": "androidx/leanback/widget/NonOverlappingView",
+ "android/support/v7/preference/ListPreference": "androidx/preference/ListPreference",
+ "android/support/v17/leanback/widget/ShadowOverlayContainer": "androidx/leanback/widget/ShadowOverlayContainer",
+ "android/support/design/internal/NavigationMenuItemView": "androidx/design/internal/NavigationMenuItemView",
+ "android/support/v17/leanback/widget/ArrayObjectAdapter": "androidx/leanback/widget/ArrayObjectAdapter",
+ "android/support/v17/leanback/widget/CursorObjectAdapter": "androidx/leanback/widget/CursorObjectAdapter",
+ "android/support/v17/leanback/R$style": "androidx/leanback/R$style",
+ "android/support/v4/media/MediaBrowserCompatApi21": "androidx/media/MediaBrowserCompatApi21",
+ "android/support/v4/media/MediaBrowserCompatApi23": "androidx/media/MediaBrowserCompatApi23",
+ "android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper": "androidx/leanback/widget/FullWidthDetailsOverviewSharedElementHelper",
+ "android/support/v7/widget/ShareActionProvider$ShareMenuItemOnMenuItemClickListener": "androidx/widget/ShareActionProvider$ShareMenuItemOnMenuItemClickListener",
+ "android/support/v4/media/MediaBrowserCompatApi26": "androidx/media/MediaBrowserCompatApi26",
+ "android/support/v4/print/PrintHelper$Orientation": "androidx/print/PrintHelper$Orientation",
+ "android/support/v4/view/ViewPager$PageTransformer": "androidx/view/ViewPager$PageTransformer",
+ "android/support/transition/ViewGroupOverlayImpl": "androidx/transition/ViewGroupOverlayImpl",
+ "android/support/v4/app/ActivityOptionsCompat$ActivityOptionsCompatApi23Impl": "androidx/app/ActivityOptionsCompat$ActivityOptionsCompatApi23Impl",
+ "android/support/v4/view/ViewPropertyAnimatorListener": "androidx/view/ViewPropertyAnimatorListener",
+ "android/support/transition/Styleable$ChangeBounds": "androidx/transition/Styleable$ChangeBounds",
+ "android/support/annotation/Keep": "androidx/annotation/Keep",
+ "android/support/v4/app/NotificationCompat$DecoratedCustomViewStyle": "androidx/app/NotificationCompat$DecoratedCustomViewStyle",
+ "android/support/v4/app/ShareCompat$IntentReader": "androidx/app/ShareCompat$IntentReader",
+ "android/support/v17/leanback/widget/ActionPresenterSelector$ActionPresenter": "androidx/leanback/widget/ActionPresenterSelector$ActionPresenter",
+ "android/support/v7/util/MessageThreadUtil$MessageQueue": "androidx/util/MessageThreadUtil$MessageQueue",
+ "android/support/annotation/Px": "androidx/annotation/Px",
+ "android/support/v17/leanback/app/SearchFragment$SearchResultProvider": "androidx/leanback/app/SearchFragment$SearchResultProvider",
+ "android/support/v7/app/AppCompatDelegateImplV9$ListMenuDecorView": "androidx/app/AppCompatDelegateImplV9$ListMenuDecorView",
+ "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperStubImpl$TransitionStub": "androidx/leanback/transition/TransitionHelper$TransitionHelperStubImpl$TransitionStub",
+ "android/support/v7/app/AppCompatDelegate": "androidx/app/AppCompatDelegate",
+ "android/support/v17/leanback/app/BrowseFragment$MainFragmentAdapter": "androidx/leanback/app/BrowseFragment$MainFragmentAdapter",
+ "android/support/v17/leanback/widget/ParallaxEffect$IntEffect": "androidx/leanback/widget/ParallaxEffect$IntEffect",
+ "android/support/v7/widget/GridLayout$Alignment": "androidx/widget/GridLayout$Alignment",
+ "android/support/v7/widget/helper/ItemTouchHelper$RecoverAnimation": "androidx/widget/helper/ItemTouchHelper$RecoverAnimation",
+ "android/support/v17/leanback/widget/picker/Picker": "androidx/leanback/widget/picker/Picker",
+ "android/support/v7/gridlayout/R$styleable": "androidx/gridlayout/R$styleable",
+ "android/support/v4/app/FragmentPagerAdapter": "androidx/app/FragmentPagerAdapter",
+ "android/support/v4/graphics/TypefaceCompatBaseImpl$StyleExtractor": "androidx/graphics/TypefaceCompatBaseImpl$StyleExtractor",
+ "android/support/v17/leanback/widget/SearchBar": "androidx/leanback/widget/SearchBar",
+ "android/support/wear/widget/drawer/WearableDrawerController": "androidx/wear/widget/drawer/WearableDrawerController",
+ "android/support/design/widget/FloatingActionButtonImpl$DisabledElevationAnimation": "androidx/design/widget/FloatingActionButtonImpl$DisabledElevationAnimation",
+ "android/support/annotation/FloatRange": "androidx/annotation/FloatRange",
+ "android/support/media/ExifInterface$ByteOrderedDataInputStream": "androidx/media/ExifInterface$ByteOrderedDataInputStream",
+ "android/support/v7/widget/TooltipCompat$Api26ViewCompatImpl": "androidx/widget/TooltipCompat$Api26ViewCompatImpl",
+ "android/support/v7/widget/RecyclerViewAccessibilityDelegate": "androidx/widget/RecyclerViewAccessibilityDelegate",
+ "android/support/v7/widget/AppCompatTextView": "androidx/widget/AppCompatTextView",
+ "android/support/transition/ChangeImageTransform": "androidx/transition/ChangeImageTransform",
+ "android/support/v4/app/SuperNotCalledException": "androidx/app/SuperNotCalledException",
+ "android/support/text/emoji/widget/EmojiTextViewHelper$HelperInternal19": "androidx/text/emoji/widget/EmojiTextViewHelper$HelperInternal19",
+ "android/support/v7/widget/GapWorker$LayoutPrefetchRegistryImpl": "androidx/widget/GapWorker$LayoutPrefetchRegistryImpl",
+ "android/support/v7/app/AppCompatDelegateImplV14$AppCompatWindowCallbackV14": "androidx/app/AppCompatDelegateImplV14$AppCompatWindowCallbackV14",
+ "android/support/v4/widget/TextViewCompat$TextViewCompatApi23Impl": "androidx/widget/TextViewCompat$TextViewCompatApi23Impl",
+ "android/support/v17/leanback/widget/ParallaxEffect$FloatEffect": "androidx/leanback/widget/ParallaxEffect$FloatEffect",
+ "android/support/v4/media/session/MediaSessionCompat": "androidx/media/session/MediaSessionCompat",
+ "android/support/v17/leanback/app/BrowseSupportFragment$FragmentHostImpl": "androidx/leanback/app/BrowseSupportFragment$FragmentHostImpl",
+ "android/support/design/widget/ShadowDrawableWrapper": "androidx/design/widget/ShadowDrawableWrapper",
+ "android/support/design/internal/NavigationMenuPresenter$HeaderViewHolder": "androidx/design/internal/NavigationMenuPresenter$HeaderViewHolder",
+ "android/support/v7/widget/PopupMenu": "androidx/widget/PopupMenu",
+ "android/support/v17/preference/LeanbackListPreferenceDialogFragment$ViewHolder": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment$ViewHolder",
+ "android/support/annotation/BoolRes": "androidx/annotation/BoolRes",
+ "android/support/v7/media/RemotePlaybackClient": "androidx/media/RemotePlaybackClient",
+ "android/support/v4/view/LayoutInflaterCompat$LayoutInflaterCompatApi21Impl": "androidx/view/LayoutInflaterCompat$LayoutInflaterCompatApi21Impl",
+ "android/support/v7/preference/AndroidResources": "androidx/preference/AndroidResources",
+ "android/support/v7/app/AlertController$AlertParams$OnPrepareListViewListener": "androidx/app/AlertController$AlertParams$OnPrepareListViewListener",
+ "android/support/wear/widget/drawer/WearableNavigationDrawerView": "androidx/wear/widget/drawer/WearableNavigationDrawerView",
+ "android/support/v4/media/session/PlaybackStateCompat$ErrorCode": "androidx/media/session/PlaybackStateCompat$ErrorCode",
+ "android/support/v7/widget/ActionMenuView$ActionMenuPresenterCallback": "androidx/widget/ActionMenuView$ActionMenuPresenterCallback",
+ "android/support/v7/app/AlertController": "androidx/app/AlertController",
+ "android/support/v7/widget/FitWindowsViewGroup$OnFitSystemWindowsListener": "androidx/widget/FitWindowsViewGroup$OnFitSystemWindowsListener",
+ "android/support/v4/app/NotificationBuilderWithBuilderAccessor": "androidx/app/NotificationBuilderWithBuilderAccessor",
+ "android/support/v4/view/AbsSavedState": "androidx/view/AbsSavedState",
+ "android/support/v7/media/MediaRouteProvider$ProviderHandler": "androidx/media/MediaRouteProvider$ProviderHandler",
+ "android/support/v7/widget/AbsActionBarView$VisibilityAnimListener": "androidx/widget/AbsActionBarView$VisibilityAnimListener",
+ "android/support/design/internal/TextScale": "androidx/design/internal/TextScale",
+ "android/support/v7/widget/RecyclerViewAccessibilityDelegate$ItemDelegate": "androidx/widget/RecyclerViewAccessibilityDelegate$ItemDelegate",
+ "android/support/v4/widget/SlidingPaneLayout": "androidx/widget/SlidingPaneLayout",
+ "android/support/v17/leanback/widget/ScaleFrameLayout": "androidx/leanback/widget/ScaleFrameLayout",
+ "android/support/v4/app/FragmentTransaction": "androidx/app/FragmentTransaction",
+ "android/support/graphics/drawable/AnimatorInflaterCompat$PathDataEvaluator": "androidx/graphics/drawable/AnimatorInflaterCompat$PathDataEvaluator",
+ "android/support/wear/widget/drawer/WearableActionDrawerView$ActionItemViewHolder": "androidx/wear/widget/drawer/WearableActionDrawerView$ActionItemViewHolder",
+ "android/support/wear/ambient/AmbientDelegate": "androidx/wear/ambient/AmbientDelegate",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$ThumbsUpAction": "androidx/leanback/widget/PlaybackControlsRow$ThumbsUpAction",
+ "android/support/v7/widget/AppCompatSpinner": "androidx/widget/AppCompatSpinner",
+ "android/support/design/widget/NavigationView$SavedState": "androidx/design/widget/NavigationView$SavedState",
+ "android/support/v17/leanback/animation/LogDecelerateInterpolator": "androidx/leanback/animation/LogDecelerateInterpolator",
+ "android/support/v4/media/session/MediaControllerCompatApi21$Callback": "androidx/media/session/MediaControllerCompatApi21$Callback",
+ "android/support/v7/widget/helper/ItemTouchHelper": "androidx/widget/helper/ItemTouchHelper",
+ "android/support/graphics/drawable/AnimatedVectorDrawableCompat$AnimatedVectorDrawableCompatState": "androidx/graphics/drawable/AnimatedVectorDrawableCompat$AnimatedVectorDrawableCompatState",
+ "android/support/v4/graphics/drawable/DrawableWrapperApi14$DrawableWrapperState": "androidx/graphics/drawable/DrawableWrapperApi14$DrawableWrapperState",
+ "android/support/v4/util/DebugUtils": "androidx/util/DebugUtils",
+ "android/support/customtabs/CustomTabsCallback": "androidx/browser/customtabs/CustomTabsCallback",
+ "android/support/v13/app/FragmentCompat": "androidx/app/FragmentCompat",
+ "android/support/v7/widget/RecyclerView$ViewFlinger": "androidx/widget/RecyclerView$ViewFlinger",
+ "android/support/v17/leanback/app/BrowseFragment$SetSelectionRunnable": "androidx/leanback/app/BrowseFragment$SetSelectionRunnable",
+ "android/support/mediacompat/BuildConfig": "androidx/mediacompat/BuildConfig",
+ "android/support/customtabs/CustomTabsIntent$Builder": "androidx/browser/customtabs/CustomTabsIntent$Builder",
+ "android/support/v4/util/MapCollections$ValuesCollection": "androidx/util/MapCollections$ValuesCollection",
+ "android/support/v17/leanback/widget/StaggeredGrid": "androidx/leanback/widget/StaggeredGrid",
+ "android/support/v13/app/FragmentTabHost$SavedState": "androidx/app/FragmentTabHost$SavedState",
+ "android/support/v4/media/MediaBrowserServiceCompatApi23": "androidx/media/MediaBrowserServiceCompatApi23",
+ "android/support/v4/media/session/MediaButtonReceiver": "androidx/media/session/MediaButtonReceiver",
+ "android/support/v17/leanback/graphics/CompositeDrawable$CompositeState": "androidx/leanback/graphics/CompositeDrawable$CompositeState",
+ "android/support/transition/WindowIdApi14": "androidx/transition/WindowIdApi14",
+ "android/support/v4/media/MediaBrowserServiceCompatApi26": "androidx/media/MediaBrowserServiceCompatApi26",
+ "android/support/v4/media/MediaBrowserServiceCompatApi21": "androidx/media/MediaBrowserServiceCompatApi21",
+ "android/support/transition/WindowIdApi18": "androidx/transition/WindowIdApi18",
+ "android/support/v7/graphics/ColorCutQuantizer": "androidx/graphics/palette/ColorCutQuantizer",
+ "android/support/v4/media/session/MediaSessionCompatApi23$Callback": "androidx/media/session/MediaSessionCompatApi23$Callback",
+ "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$ActionsItemBridgeAdapter": "androidx/leanback/widget/DetailsOverviewRowPresenter$ActionsItemBridgeAdapter",
+ "android/support/v7/app/MediaRouteButton$RemoteIndicatorLoader": "androidx/app/MediaRouteButton$RemoteIndicatorLoader",
+ "android/support/v7/preference/ListPreference$SavedState": "androidx/preference/ListPreference$SavedState",
+ "android/support/v7/media/RegisteredMediaRouteProvider$ReceiveHandler": "androidx/media/RegisteredMediaRouteProvider$ReceiveHandler",
+ "android/support/v17/leanback/widget/MediaRowFocusView": "androidx/leanback/widget/MediaRowFocusView",
+ "android/support/v14/preference/PreferenceFragment$OnPreferenceDisplayDialogCallback": "androidx/preference/PreferenceFragment$OnPreferenceDisplayDialogCallback",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$HighQualityAction": "androidx/leanback/widget/PlaybackControlsRow$HighQualityAction",
+ "android/support/v17/leanback/app/BaseRowSupportFragment": "androidx/leanback/app/BaseRowSupportFragment",
+ "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentItemViewSelectedListener": "androidx/leanback/app/BrowseSupportFragment$MainFragmentItemViewSelectedListener",
+ "android/support/v17/leanback/widget/StreamingTextView": "androidx/leanback/widget/StreamingTextView",
+ "android/support/transition/GhostViewImpl$Creator": "androidx/transition/GhostViewImpl$Creator",
+ "android/support/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuItem": "androidx/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuItem",
+ "android/support/v4/media/MediaBrowserCompat$Subscription": "androidx/media/MediaBrowserCompat$Subscription",
+ "android/support/v4/view/PagerTitleStrip$SingleLineAllCapsTransform": "androidx/view/PagerTitleStrip$SingleLineAllCapsTransform",
+ "android/support/v4/media/session/MediaControllerCompatApi24$TransportControls": "androidx/media/session/MediaControllerCompatApi24$TransportControls",
+ "android/support/v7/app/ActionBarDrawerToggleHoneycomb": "androidx/app/ActionBarDrawerToggleHoneycomb",
+ "android/support/v4/graphics/TypefaceCompatBaseImpl": "androidx/graphics/TypefaceCompatBaseImpl",
+ "android/support/transition/TranslationAnimationCreator": "androidx/transition/TranslationAnimationCreator",
+ "android/support/v7/app/MediaRouteChooserDialog": "androidx/app/MediaRouteChooserDialog",
+ "android/support/v17/leanback/widget/Parallax$FloatPropertyMarkerValue": "androidx/leanback/widget/Parallax$FloatPropertyMarkerValue",
+ "android/support/v4/widget/FocusStrategy$SequentialComparator": "androidx/widget/FocusStrategy$SequentialComparator",
+ "android/support/v4/media/MediaMetadataCompat$TextKey": "androidx/media/MediaMetadataCompat$TextKey",
+ "android/support/v17/leanback/app/BrowseSupportFragment": "androidx/leanback/app/BrowseSupportFragment",
+ "android/support/v7/widget/ListViewCompat$GateKeeperDrawable": "androidx/widget/ListViewCompat$GateKeeperDrawable",
+ "android/support/v4/media/session/MediaControllerCompatApi23$TransportControls": "androidx/media/session/MediaControllerCompatApi23$TransportControls",
+ "android/support/v13/view/inputmethod/InputConnectionCompat$InputContentInfoCompatApi25Impl": "androidx/view/inputmethod/InputConnectionCompat$InputContentInfoCompatApi25Impl",
+ "android/support/v7/preference/PreferenceManager$OnDisplayPreferenceDialogListener": "androidx/preference/PreferenceManager$OnDisplayPreferenceDialogListener",
+ "android/support/v7/media/MediaRouterJellybeanMr1$IsConnectingWorkaround": "androidx/media/MediaRouterJellybeanMr1$IsConnectingWorkaround",
+ "android/support/v4/view/accessibility/AccessibilityManagerCompat$TouchExplorationStateChangeListenerWrapper": "androidx/view/accessibility/AccessibilityManagerCompat$TouchExplorationStateChangeListenerWrapper",
+ "android/support/v7/widget/RecyclerView$ItemDecoration": "androidx/widget/RecyclerView$ItemDecoration",
+ "android/support/v4/widget/Space": "androidx/widget/Space",
+ "android/support/v17/leanback/app/BrowseSupportFragment$ExpandPreLayout": "androidx/leanback/app/BrowseSupportFragment$ExpandPreLayout",
+ "android/support/media/tv/TvContractCompat$ProgramColumns": "androidx/media/tv/TvContractCompat$ProgramColumns",
+ "android/support/v7/widget/DecorToolbar": "androidx/widget/DecorToolbar",
+ "android/support/design/widget/CheckableImageButton": "androidx/design/widget/CheckableImageButton",
+ "android/support/v4/widget/ImageViewCompat": "androidx/widget/ImageViewCompat",
+ "android/support/v7/preference/UnPressableLinearLayout": "androidx/preference/UnPressableLinearLayout",
+ "android/support/wear/widget/SwipeDismissFrameLayout$MyOnPreSwipeListener": "androidx/wear/widget/SwipeDismissFrameLayout$MyOnPreSwipeListener",
+ "android/support/v4/widget/CircularProgressDrawable": "androidx/widget/CircularProgressDrawable",
+ "android/support/design/R$string": "androidx/design/R$string",
+ "android/support/design/R$color": "androidx/design/R$color",
+ "android/support/v7/widget/TintInfo": "androidx/widget/TintInfo",
+ "android/support/v17/leanback/widget/HeaderItem": "androidx/leanback/widget/HeaderItem",
+ "android/support/v7/media/MediaRouter$RouteInfo$ConnectionState": "androidx/media/MediaRouter$RouteInfo$ConnectionState",
+ "android/support/v7/widget/DialogTitle": "androidx/widget/DialogTitle",
+ "android/support/v17/leanback/media/PlaybackTransportControlGlue$UpdatePlaybackStateHandler": "androidx/leanback/media/PlaybackTransportControlGlue$UpdatePlaybackStateHandler",
+ "android/support/v7/widget/RecyclerView$LayoutParams": "androidx/widget/RecyclerView$LayoutParams",
+ "android/support/v4/media/session/PlaybackStateCompatApi21$CustomAction": "androidx/media/session/PlaybackStateCompatApi21$CustomAction",
+ "android/support/customtabs/CustomTabsService": "androidx/browser/customtabs/CustomTabsService",
+ "android/support/v17/leanback/widget/GuidanceStylist$Guidance": "androidx/leanback/widget/GuidanceStylist$Guidance",
+ "android/support/v4/view/ViewCompat$ViewCompatApi23Impl": "androidx/view/ViewCompat$ViewCompatApi23Impl",
+ "android/support/wear/widget/WearableLinearLayoutManager": "androidx/wear/widget/WearableLinearLayoutManager",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$MultiAction": "androidx/leanback/widget/PlaybackControlsRow$MultiAction",
+ "android/support/v17/leanback/R$integer": "androidx/leanback/R$integer",
+ "android/support/v4/content/ModernAsyncTask$WorkerRunnable": "androidx/content/ModernAsyncTask$WorkerRunnable",
+ "android/support/v4/app/FragmentTabHost$DummyTabFactory": "androidx/app/FragmentTabHost$DummyTabFactory",
+ "android/support/v7/widget/AppCompatSpinner$DropDownAdapter": "androidx/widget/AppCompatSpinner$DropDownAdapter",
+ "android/support/v7/app/ToolbarActionBar$MenuBuilderCallback": "androidx/app/ToolbarActionBar$MenuBuilderCallback",
+ "android/support/v4/content/Loader": "androidx/content/Loader",
+ "android/support/v7/widget/MenuPopupWindow": "androidx/widget/MenuPopupWindow",
+ "android/support/v4/graphics/BitmapCompat$BitmapCompatApi19Impl": "androidx/graphics/BitmapCompat$BitmapCompatApi19Impl",
+ "android/support/v4/app/FrameMetricsAggregator$MetricType": "androidx/app/FrameMetricsAggregator$MetricType",
+ "android/support/v17/leanback/widget/picker/PickerUtility$TimeConstant": "androidx/leanback/widget/picker/PickerUtility$TimeConstant",
+ "android/support/v4/view/NestedScrollingParent2": "androidx/view/NestedScrollingParent2",
+ "android/support/design/widget/Snackbar$SnackbarLayout": "androidx/design/widget/Snackbar$SnackbarLayout",
+ "android/support/v4/app/LoaderManager": "androidx/app/LoaderManager",
+ "android/support/v17/leanback/app/BaseSupportFragment": "androidx/leanback/app/BaseSupportFragment",
+ "android/support/design/internal/NavigationMenuPresenter$NavigationMenuItem": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuItem",
+ "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$RangeInfoCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat$RangeInfoCompat",
+ "android/support/text/emoji/MetadataRepo": "androidx/text/emoji/MetadataRepo",
+ "android/support/v17/leanback/widget/ItemAlignment": "androidx/leanback/widget/ItemAlignment",
+ "android/support/design/widget/TextInputEditText": "androidx/design/widget/TextInputEditText",
+ "android/support/v4/app/FragmentTransitionImpl": "androidx/app/FragmentTransitionImpl",
+ "android/support/animation/SpringAnimation": "androidx/animation/SpringAnimation",
+ "android/support/annotation/CheckResult": "androidx/annotation/CheckResult",
+ "android/support/v7/widget/AppCompatSpinner$DropdownPopup": "androidx/widget/AppCompatSpinner$DropdownPopup",
+ "android/support/v7/widget/ActivityChooserModel$ActivitySorter": "androidx/widget/ActivityChooserModel$ActivitySorter",
+ "android/support/wear/widget/drawer/WearableDrawerLayout$ClosePeekRunnable": "androidx/wear/widget/drawer/WearableDrawerLayout$ClosePeekRunnable",
+ "android/support/design/widget/TextInputLayout$SavedState": "androidx/design/widget/TextInputLayout$SavedState",
+ "android/support/v17/leanback/widget/picker/PickerUtility$DateConstant": "androidx/leanback/widget/picker/PickerUtility$DateConstant",
+ "android/support/v13/app/FragmentTabHost": "androidx/app/FragmentTabHost",
+ "android/support/v7/widget/ScrollingTabContainerView$TabAdapter": "androidx/widget/ScrollingTabContainerView$TabAdapter",
+ "android/support/v7/widget/ActionBarContextView": "androidx/widget/ActionBarContextView",
+ "android/support/design/internal/NavigationMenuPresenter$NavigationMenuHeaderItem": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuHeaderItem",
+ "android/support/v17/leanback/graphics/CompositeDrawable": "androidx/leanback/graphics/CompositeDrawable",
+ "android/support/v7/preference/Preference$OnPreferenceChangeListener": "androidx/preference/Preference$OnPreferenceChangeListener",
+ "android/support/v4/media/MediaBrowserServiceCompat$BrowserRoot": "androidx/media/MediaBrowserServiceCompat$BrowserRoot",
+ "android/support/text/emoji/MetadataListReader$OpenTypeReader": "androidx/text/emoji/MetadataListReader$OpenTypeReader",
+ "android/support/v7/media/MediaRouterJellybean$VolumeCallbackProxy": "androidx/media/MediaRouterJellybean$VolumeCallbackProxy",
+ "android/support/v4/app/OneShotPreDrawListener": "androidx/app/OneShotPreDrawListener",
+ "android/support/design/widget/BottomNavigationView$OnNavigationItemSelectedListener": "androidx/design/widget/BottomNavigationView$OnNavigationItemSelectedListener",
+ "android/support/v7/widget/ActionMenuView": "androidx/widget/ActionMenuView",
+ "android/support/v4/view/NestedScrollingChildHelper": "androidx/view/NestedScrollingChildHelper",
+ "android/support/percent/PercentFrameLayout": "androidx/PercentFrameLayout",
+ "android/support/annotation/AnyRes": "androidx/annotation/AnyRes",
+ "android/support/wear/widget/CircledImageView$OvalShadowPainter": "androidx/wear/widget/CircledImageView$OvalShadowPainter",
+ "android/support/media/tv/TvContractCompat$Channels$Logo": "androidx/media/tv/TvContractCompat$Channels$Logo",
+ "android/support/v4/view/animation/LookupTableInterpolator": "androidx/view/animation/LookupTableInterpolator",
+ "android/support/v7/app/MediaRouteControllerDialog$MediaControllerCallback": "androidx/app/MediaRouteControllerDialog$MediaControllerCallback",
+ "android/support/v7/widget/FitWindowsViewGroup": "androidx/widget/FitWindowsViewGroup",
+ "android/support/v7/widget/ActionBarOverlayLayout$ActionBarVisibilityCallback": "androidx/widget/ActionBarOverlayLayout$ActionBarVisibilityCallback",
+ "android/support/wear/ambient/AmbientMode": "androidx/wear/ambient/AmbientMode",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$SkipPreviousAction": "androidx/leanback/widget/PlaybackControlsRow$SkipPreviousAction",
+ "android/support/v4/app/NotificationCompat$Builder": "androidx/app/NotificationCompat$Builder",
+ "android/support/design/R$layout": "androidx/design/R$layout",
+ "android/support/transition/FragmentTransitionSupport": "androidx/transition/FragmentTransitionSupport",
+ "android/support/v4/app/Fragment$AnimationInfo": "androidx/app/Fragment$AnimationInfo",
+ "android/support/transition/ChangeTransform": "androidx/transition/ChangeTransform",
+ "android/support/v7/gridlayout/BuildConfig": "androidx/gridlayout/BuildConfig",
+ "android/support/v4/view/ViewCompat$FocusRelativeDirection": "androidx/view/ViewCompat$FocusRelativeDirection",
+ "android/support/customtabs/CustomTabsSessionToken$MockCallback": "androidx/browser/customtabs/CustomTabsSessionToken$MockCallback",
+ "android/support/v4/app/TaskStackBuilder$TaskStackBuilderBaseImpl": "androidx/app/TaskStackBuilder$TaskStackBuilderBaseImpl",
+ "android/support/v4/media/AudioAttributesCompat$Builder": "androidx/media/AudioAttributesCompat$Builder",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$ThumbsAction": "androidx/leanback/widget/PlaybackControlsRow$ThumbsAction",
+ "android/support/v7/media/MediaItemStatus$Builder": "androidx/media/MediaItemStatus$Builder",
+ "android/support/v17/leanback/app/OnboardingSupportFragment": "androidx/leanback/app/OnboardingSupportFragment",
+ "android/support/v7/widget/LinearLayoutCompat$OrientationMode": "androidx/widget/LinearLayoutCompat$OrientationMode",
+ "android/support/v7/widget/AppCompatImageButton": "androidx/widget/AppCompatImageButton",
+ "android/support/v7/app/AppCompatViewInflater$DeclaredOnClickListener": "androidx/app/AppCompatViewInflater$DeclaredOnClickListener",
+ "android/support/v7/view/SupportMenuInflater$InflatedOnMenuItemClickListener": "androidx/view/SupportMenuInflater$InflatedOnMenuItemClickListener",
+ "android/support/v4/widget/ContentLoadingProgressBar": "androidx/widget/ContentLoadingProgressBar",
+ "android/support/v4/hardware/display/DisplayManagerCompat$DisplayManagerCompatApi17Impl": "androidx/hardware/display/DisplayManagerCompat$DisplayManagerCompatApi17Impl",
+ "android/support/v17/leanback/app/BrowseFragment$ListRowFragmentFactory": "androidx/leanback/app/BrowseFragment$ListRowFragmentFactory",
+ "android/support/v7/app/MediaRouteChooserDialog$RouteAdapter": "androidx/app/MediaRouteChooserDialog$RouteAdapter",
+ "android/support/v7/view/ContextThemeWrapper": "androidx/view/ContextThemeWrapper",
+ "android/support/design/widget/CoordinatorLayout$OnPreDrawListener": "androidx/design/widget/CoordinatorLayout$OnPreDrawListener",
+ "android/support/v4/util/ContainerHelpers": "androidx/util/ContainerHelpers",
+ "android/support/design/widget/SnackbarManager$Callback": "androidx/design/widget/SnackbarManager$Callback",
+ "android/support/design/internal/ForegroundLinearLayout": "androidx/design/internal/ForegroundLinearLayout",
+ "android/support/v4/app/NotificationCompatJellybean": "androidx/app/NotificationCompatJellybean",
+ "android/support/design/widget/CoordinatorLayout$Behavior": "androidx/design/widget/CoordinatorLayout$Behavior",
+ "android/support/v4/BuildConfig": "androidx/BuildConfig",
+ "android/support/compat/R$dimen": "androidx/compat/R$dimen",
+ "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentAdapterProvider": "androidx/leanback/app/BrowseSupportFragment$MainFragmentAdapterProvider",
+ "android/support/wear/widget/SwipeDismissLayout$OnDismissedListener": "androidx/wear/widget/SwipeDismissLayout$OnDismissedListener",
+ "android/support/v7/recyclerview/R": "androidx/recyclerview/R",
+ "android/support/v4/widget/SlidingPaneLayout$LayoutParams": "androidx/widget/SlidingPaneLayout$LayoutParams",
+ "android/support/v7/app/ToolbarActionBar$ActionMenuPresenterCallback": "androidx/app/ToolbarActionBar$ActionMenuPresenterCallback",
+ "android/support/v4/widget/DrawerLayout$DrawerListener": "androidx/widget/DrawerLayout$DrawerListener",
+ "android/support/v4/net/ConnectivityManagerCompat$RestrictBackgroundStatus": "androidx/net/ConnectivityManagerCompat$RestrictBackgroundStatus",
+ "android/support/v4/media/MediaMetadataCompat$RatingKey": "androidx/media/MediaMetadataCompat$RatingKey",
+ "android/support/v4/view/ActionProvider": "androidx/view/ActionProvider",
+ "android/support/v7/app/MediaRouteControllerDialogFragment": "androidx/app/MediaRouteControllerDialogFragment",
+ "android/support/v7/widget/TooltipCompatHandler": "androidx/widget/TooltipCompatHandler",
+ "android/support/design/widget/TabLayout$TabLayoutOnPageChangeListener": "androidx/design/widget/TabLayout$TabLayoutOnPageChangeListener",
+ "android/support/v7/widget/RecyclerView$ItemAnimatorRestoreListener": "androidx/widget/RecyclerView$ItemAnimatorRestoreListener",
+ "android/support/app/recommendation/ContentRecommendation$ContentType": "androidx/app/recommendation/ContentRecommendation$ContentType",
+ "android/support/v7/app/AlertController$AlertParams": "androidx/app/AlertController$AlertParams",
+ "android/support/v4/widget/DrawerLayout$SimpleDrawerListener": "androidx/widget/DrawerLayout$SimpleDrawerListener",
+ "android/support/v17/leanback/widget/FocusHighlightHelper$HeaderItemFocusHighlight": "androidx/leanback/widget/FocusHighlightHelper$HeaderItemFocusHighlight",
+ "android/support/v7/app/MediaRouteChooserDialog$MediaRouterCallback": "androidx/app/MediaRouteChooserDialog$MediaRouterCallback",
+ "android/support/v4/view/ViewCompat$ImportantForAccessibility": "androidx/view/ViewCompat$ImportantForAccessibility",
+ "android/support/v7/media/MediaRouterJellybean$RouteInfo": "androidx/media/MediaRouterJellybean$RouteInfo",
+ "android/support/v17/leanback/widget/SpeechRecognitionCallback": "androidx/leanback/widget/SpeechRecognitionCallback",
+ "android/support/v4/media/MediaBrowserCompatApi26$SubscriptionCallback": "androidx/media/MediaBrowserCompatApi26$SubscriptionCallback",
+ "android/support/media/tv/Program": "androidx/media/tv/Program",
+ "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$AccessibilityActionCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat$AccessibilityActionCompat",
+ "android/support/v4/app/FragmentTransitionCompat21": "androidx/app/FragmentTransitionCompat21",
+ "android/support/v7/media/MediaRouteSelector$Builder": "androidx/media/MediaRouteSelector$Builder",
+ "android/support/v4/hardware/fingerprint/FingerprintManagerCompat": "androidx/hardware/fingerprint/FingerprintManagerCompat",
+ "android/support/v17/leanback/app/HeadersFragment": "androidx/leanback/app/HeadersFragment",
+ "android/support/v17/leanback/R$dimen": "androidx/leanback/R$dimen",
+ "android/support/v4/content/res/ResourcesCompat": "androidx/content/res/ResourcesCompat",
+ "android/support/v4/view/ViewPager$SavedState": "androidx/view/ViewPager$SavedState",
+ "android/support/v17/leanback/widget/StaticShadowHelper$ShadowHelperJbmr2Impl": "androidx/leanback/widget/StaticShadowHelper$ShadowHelperJbmr2Impl",
+ "android/support/v4/widget/SwipeRefreshLayout": "androidx/widget/SwipeRefreshLayout",
+ "android/support/v17/leanback/widget/StaticShadowHelper$ShadowHelperVersionImpl": "androidx/leanback/widget/StaticShadowHelper$ShadowHelperVersionImpl",
+ "android/support/v4/os/ResultReceiver": "androidx/os/ResultReceiver",
+ "android/support/v17/leanback/widget/BaseCardView$InfoOffsetAnimation": "androidx/leanback/widget/BaseCardView$InfoOffsetAnimation",
+ "android/support/design/widget/SwipeDismissBehavior$SettleRunnable": "androidx/design/widget/SwipeDismissBehavior$SettleRunnable",
+ "android/support/v13/view/inputmethod/InputConnectionCompat$InputContentInfoCompatBaseImpl": "androidx/view/inputmethod/InputConnectionCompat$InputContentInfoCompatBaseImpl",
+ "android/support/v17/leanback/widget/FacetProvider": "androidx/leanback/widget/FacetProvider",
+ "android/support/v7/widget/FitWindowsLinearLayout": "androidx/widget/FitWindowsLinearLayout",
+ "android/support/v4/widget/SwipeProgressBar": "androidx/widget/SwipeProgressBar",
+ "android/support/v7/widget/ActionMenuPresenter$OverflowPopup": "androidx/widget/ActionMenuPresenter$OverflowPopup",
+ "android/support/v7/widget/AppCompatImageHelper": "androidx/widget/AppCompatImageHelper",
+ "android/support/v4/text/TextDirectionHeuristicsCompat": "androidx/text/TextDirectionHeuristicsCompat",
+ "android/support/compat/R$color": "androidx/compat/R$color",
+ "android/support/transition/Transition$EpicenterCallback": "androidx/transition/Transition$EpicenterCallback",
+ "android/support/transition/PropertyValuesHolderUtilsApi14": "androidx/transition/PropertyValuesHolderUtilsApi14",
+ "android/support/v17/leanback/widget/ObjectAdapter$DataObservable": "androidx/leanback/widget/ObjectAdapter$DataObservable",
+ "android/support/multidex/ZipUtil": "androidx/multidex/ZipUtil",
+ "android/support/v7/view/menu/MenuDialogHelper": "androidx/view/menu/MenuDialogHelper",
+ "android/support/v17/preference/R$id": "androidx/leanback/preference/R$id",
+ "android/support/v4/app/BundleCompat": "androidx/app/BundleCompat",
+ "android/support/v4/media/session/IMediaSession$Stub$Proxy": "androidx/media/session/IMediaSession$Stub$Proxy",
+ "android/support/v7/widget/AppCompatTextHelper": "androidx/widget/AppCompatTextHelper",
+ "android/support/v7/view/ActionMode$Callback": "androidx/view/ActionMode$Callback",
+ "android/support/v17/leanback/app/RowsSupportFragment": "androidx/leanback/app/RowsSupportFragment",
+ "android/support/v17/leanback/app/GuidedStepFragment$DummyFragment": "androidx/leanback/app/GuidedStepFragment$DummyFragment",
+ "android/support/v7/widget/util/SortedListAdapterCallback": "androidx/widget/util/SortedListAdapterCallback",
+ "android/support/design/internal/BottomNavigationPresenter$SavedState": "androidx/design/internal/BottomNavigationPresenter$SavedState",
+ "android/support/v7/widget/LinearSmoothScroller": "androidx/widget/LinearSmoothScroller",
+ "android/support/v17/leanback/media/MediaPlayerGlue$VideoPlayerSurfaceHolderCallback": "androidx/leanback/media/MediaPlayerGlue$VideoPlayerSurfaceHolderCallback",
+ "android/support/v7/preference/Preference": "androidx/preference/Preference",
+ "android/support/v4/os/UserManagerCompat": "androidx/os/UserManagerCompat",
+ "android/support/v7/widget/GridLayoutManager$DefaultSpanSizeLookup": "androidx/widget/GridLayoutManager$DefaultSpanSizeLookup",
+ "android/support/v17/leanback/app/PlaybackFragment": "androidx/leanback/app/PlaybackFragment",
+ "android/support/transition/ViewOverlayImpl": "androidx/transition/ViewOverlayImpl",
+ "android/support/transition/ViewOverlayApi14$OverlayViewGroup$TouchInterceptor": "androidx/transition/ViewOverlayApi14$OverlayViewGroup$TouchInterceptor",
+ "android/support/v7/view/menu/MenuAdapter": "androidx/view/menu/MenuAdapter",
+ "android/support/v4/app/NotificationCompat$MessagingStyle$Message": "androidx/app/NotificationCompat$MessagingStyle$Message",
+ "android/support/v4/graphics/drawable/DrawableWrapperApi21$DrawableWrapperStateLollipop": "androidx/graphics/drawable/DrawableWrapperApi21$DrawableWrapperStateLollipop",
+ "android/support/coreutils/BuildConfig": "androidx/coreutils/BuildConfig",
+ "android/support/v17/leanback/widget/ItemAlignmentFacet$ItemAlignmentDef": "androidx/leanback/widget/ItemAlignmentFacet$ItemAlignmentDef",
+ "android/support/v4/content/SharedPreferencesCompat": "androidx/content/SharedPreferencesCompat",
+ "android/support/v4/app/FragmentManager$BackStackEntry": "androidx/app/FragmentManager$BackStackEntry",
+ "android/support/transition/PropertyValuesHolderUtilsApi21": "androidx/transition/PropertyValuesHolderUtilsApi21",
+ "android/support/v17/leanback/R$color": "androidx/leanback/R$color",
+ "android/support/v7/view/menu/MenuView": "androidx/view/menu/MenuView",
+ "android/support/transition/Transition": "androidx/transition/Transition",
+ "android/support/v17/leanback/app/PlaybackFragmentGlueHost": "androidx/leanback/app/PlaybackFragmentGlueHost",
+ "android/support/v7/graphics/Target": "androidx/graphics/palette/Target",
+ "android/support/v7/view/StandaloneActionMode": "androidx/view/StandaloneActionMode",
+ "android/support/v13/view/DragAndDropPermissionsCompat$Api24DragAndDropPermissionsCompatImpl": "androidx/view/DragAndDropPermissionsCompat$Api24DragAndDropPermissionsCompatImpl",
+ "android/support/v7/widget/ViewInfoStore$ProcessCallback": "androidx/widget/ViewInfoStore$ProcessCallback",
+ "android/support/v4/media/session/MediaSessionCompatApi24": "androidx/media/session/MediaSessionCompatApi24",
+ "android/support/v4/widget/CursorFilter": "androidx/widget/CursorFilter",
+ "android/support/v4/media/session/MediaSessionCompatApi23": "androidx/media/session/MediaSessionCompatApi23",
+ "android/support/v4/media/session/MediaSessionCompatApi22": "androidx/media/session/MediaSessionCompatApi22",
+ "android/support/v7/app/ActionBarDrawerToggle$DelegateProvider": "androidx/app/ActionBarDrawerToggle$DelegateProvider",
+ "android/support/v4/media/session/MediaSessionCompatApi21": "androidx/media/session/MediaSessionCompatApi21",
+ "android/support/v7/widget/RecyclerView$OnItemTouchListener": "androidx/widget/RecyclerView$OnItemTouchListener",
+ "android/support/v4/media/MediaBrowserServiceCompat$ServiceHandler": "androidx/media/MediaBrowserServiceCompat$ServiceHandler",
+ "android/support/v4/view/PagerTitleStrip": "androidx/widget/PagerTitleStrip",
+ "android/support/v17/leanback/media/MediaPlayerAdapter$VideoPlayerSurfaceHolderCallback": "androidx/leanback/media/MediaPlayerAdapter$VideoPlayerSurfaceHolderCallback",
+ "android/support/v7/widget/ButtonBarLayout": "androidx/widget/ButtonBarLayout",
+ "android/support/annotation/PluralsRes": "androidx/annotation/PluralsRes",
+ "android/support/v7/appcompat/R$styleable": "androidx/appcompat/R$styleable",
+ "android/support/v7/widget/Toolbar": "androidx/widget/Toolbar",
+ "android/support/v17/leanback/app/DetailsFragmentBackgroundController": "androidx/leanback/app/DetailsFragmentBackgroundController",
+ "android/support/v7/view/menu/CascadingMenuPopup$CascadingMenuInfo": "androidx/view/menu/CascadingMenuPopup$CascadingMenuInfo",
+ "android/support/wear/widget/RoundedDrawable": "androidx/wear/widget/RoundedDrawable",
+ "android/support/v4/math/MathUtils": "androidx/math/MathUtils",
+ "android/support/design/widget/FloatingActionButton": "androidx/design/widget/FloatingActionButton",
+ "android/support/v7/mediarouter/R$drawable": "androidx/mediarouter/R$drawable",
+ "android/support/v4/view/MenuCompat": "androidx/view/MenuCompat",
+ "android/support/v17/leanback/widget/ListRowPresenter$SelectItemViewHolderTask": "androidx/leanback/widget/ListRowPresenter$SelectItemViewHolderTask",
+ "android/support/v7/appcompat/R$color": "androidx/appcompat/R$color",
+ "android/support/media/tv/BaseProgram$Builder": "androidx/media/tv/BaseProgram$Builder",
+ "android/support/v17/leanback/widget/ControlButtonPresenterSelector": "androidx/leanback/widget/ControlButtonPresenterSelector",
+ "android/support/v4/util/MapCollections$KeySet": "androidx/util/MapCollections$KeySet",
+ "android/support/annotation/XmlRes": "androidx/annotation/XmlRes",
+ "android/support/v7/widget/RecyclerView$LayoutManager$Properties": "androidx/widget/RecyclerView$LayoutManager$Properties",
+ "android/support/v4/media/MediaBrowserCompat$ConnectionCallback$ConnectionCallbackInternal": "androidx/media/MediaBrowserCompat$ConnectionCallback$ConnectionCallbackInternal",
+ "android/support/v4/app/RemoteInput$Builder": "androidx/app/RemoteInput$Builder",
+ "android/support/wear/widget/WearableRecyclerView": "androidx/wear/widget/WearableRecyclerView",
+ "android/support/v7/app/AppCompatDialog": "androidx/app/AppCompatDialog",
+ "android/support/v4/app/NotificationManagerCompat$SideChannelManager$ListenerRecord": "androidx/app/NotificationManagerCompat$SideChannelManager$ListenerRecord",
+ "android/support/v4/print/PrintHelper$OnPrintFinishCallback": "androidx/print/PrintHelper$OnPrintFinishCallback",
+ "android/support/v17/leanback/app/FragmentUtil": "androidx/leanback/app/FragmentUtil",
+ "android/support/v17/leanback/widget/RowPresenter$ContainerViewHolder": "androidx/leanback/widget/RowPresenter$ContainerViewHolder",
+ "android/support/v4/media/session/MediaControllerCompat$TransportControlsApi24": "androidx/media/session/MediaControllerCompat$TransportControlsApi24",
+ "android/support/v13/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatImpl": "androidx/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatImpl",
+ "android/support/v17/preference/LeanbackListPreferenceDialogFragment$ViewHolder$OnItemClickListener": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment$ViewHolder$OnItemClickListener",
+ "android/support/v17/leanback/app/BackgroundManager$TranslucentLayerDrawable": "androidx/leanback/app/BackgroundManager$TranslucentLayerDrawable",
+ "android/support/v4/app/FragmentManagerState": "androidx/app/FragmentManagerState",
+ "android/support/v4/media/session/MediaControllerCompat$TransportControlsApi23": "androidx/media/session/MediaControllerCompat$TransportControlsApi23",
+ "android/support/v4/view/AsyncLayoutInflater$BasicInflater": "androidx/view/AsyncLayoutInflater$BasicInflater",
+ "android/support/v7/appcompat/R$dimen": "androidx/appcompat/R$dimen",
+ "android/support/v4/media/session/MediaControllerCompat$TransportControlsApi21": "androidx/media/session/MediaControllerCompat$TransportControlsApi21",
+ "android/support/wear/widget/CircularProgressLayout": "androidx/wear/widget/CircularProgressLayout",
+ "android/support/v7/media/SystemMediaRouteProvider$JellybeanMr1Impl": "androidx/media/SystemMediaRouteProvider$JellybeanMr1Impl",
+ "android/support/customtabs/ICustomTabsCallback$Stub": "androidx/browser/customtabs/ICustomTabsCallback$Stub",
+ "android/support/v17/leanback/widget/RowPresenter$ViewHolder": "androidx/leanback/widget/RowPresenter$ViewHolder",
+ "android/support/v7/widget/RecyclerView$LayoutManager$LayoutPrefetchRegistry": "androidx/widget/RecyclerView$LayoutManager$LayoutPrefetchRegistry",
+ "android/support/v4/media/MediaBrowserServiceCompatApi23$MediaBrowserServiceAdaptor": "androidx/media/MediaBrowserServiceCompatApi23$MediaBrowserServiceAdaptor",
+ "android/support/v17/leanback/app/ListRowDataAdapter": "androidx/leanback/app/ListRowDataAdapter",
+ "android/support/v4/graphics/drawable/DrawableWrapper": "androidx/graphics/drawable/DrawableWrapper",
+ "android/support/media/tv/BuildConfig": "androidx/media/tv/BuildConfig",
+ "android/support/v7/widget/SuggestionsAdapter": "androidx/widget/SuggestionsAdapter",
+ "android/support/v4/widget/TextViewCompat": "androidx/widget/TextViewCompat",
+ "android/support/animation/FlingAnimation": "androidx/animation/FlingAnimation",
+ "android/support/media/tv/PreviewProgram$Builder": "androidx/media/tv/PreviewProgram$Builder",
+ "android/support/v7/widget/RecyclerView$AdapterDataObservable": "androidx/widget/RecyclerView$AdapterDataObservable",
+ "android/support/v17/leanback/app/BaseRowSupportFragment$LateSelectionObserver": "androidx/leanback/app/BaseRowSupportFragment$LateSelectionObserver",
+ "android/support/design/internal/SnackbarContentLayout": "androidx/design/internal/SnackbarContentLayout",
+ "android/support/v17/leanback/widget/BaseGridView$OnMotionInterceptListener": "androidx/leanback/widget/BaseGridView$OnMotionInterceptListener",
+ "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$ViewHolder": "androidx/leanback/widget/PlaybackTransportRowPresenter$ViewHolder",
+ "android/support/v7/widget/CardViewBaseImpl": "androidx/widget/CardViewBaseImpl",
+ "android/support/v4/provider/FontsContractCompat$FontFamilyResult": "androidx/provider/FontsContractCompat$FontFamilyResult",
+ "android/support/v4/os/ResultReceiver$MyRunnable": "androidx/os/ResultReceiver$MyRunnable",
+ "android/support/v7/media/MediaRouteProvider$RouteController": "androidx/media/MediaRouteProvider$RouteController",
+ "android/support/v14/preference/PreferenceFragment$DividerDecoration": "androidx/preference/PreferenceFragment$DividerDecoration",
+ "android/support/text/emoji/flatbuffer/MetadataItem": "androidx/text/emoji/flatbuffer/MetadataItem",
+ "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi18": "androidx/media/session/MediaSessionCompat$MediaSessionImplApi18",
+ "android/support/v7/widget/ToolbarWidgetWrapper": "androidx/widget/ToolbarWidgetWrapper",
+ "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi19": "androidx/media/session/MediaSessionCompat$MediaSessionImplApi19",
+ "android/support/v7/widget/helper/ItemTouchHelper$ItemTouchHelperGestureListener": "androidx/widget/helper/ItemTouchHelper$ItemTouchHelperGestureListener",
+ "android/support/v7/appcompat/R$layout": "androidx/appcompat/R$layout",
+ "android/support/text/emoji/widget/EmojiEditTextHelper$HelperInternal19": "androidx/text/emoji/widget/EmojiEditTextHelper$HelperInternal19",
+ "android/support/v17/leanback/app/BackgroundManager$BitmapDrawable$ConstantState": "androidx/leanback/app/BackgroundManager$BitmapDrawable$ConstantState",
+ "android/support/design/widget/FloatingActionButtonImpl$ShadowAnimatorImpl": "androidx/design/widget/FloatingActionButtonImpl$ShadowAnimatorImpl",
+ "android/support/v7/widget/FastScroller$AnimatorListener": "androidx/widget/FastScroller$AnimatorListener",
+ "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter",
+ "android/support/v4/app/NotificationCompat$WearableExtender": "androidx/app/NotificationCompat$WearableExtender",
+ "android/support/v17/leanback/widget/FocusHighlightHandler": "androidx/leanback/widget/FocusHighlightHandler",
+ "android/support/transition/Slide$GravityFlag": "androidx/transition/Slide$GravityFlag",
+ "android/support/v4/app/FragmentManagerImpl$AnimateOnHWLayerIfNeededListener": "androidx/app/FragmentManagerImpl$AnimateOnHWLayerIfNeededListener",
+ "android/support/v4/widget/ListViewCompat": "androidx/widget/ListViewCompat",
+ "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi21": "androidx/media/session/MediaSessionCompat$MediaSessionImplApi21",
+ "android/support/graphics/drawable/Animatable2Compat$AnimationCallback": "androidx/graphics/drawable/Animatable2Compat$AnimationCallback",
+ "android/support/v17/leanback/widget/ControlButtonPresenterSelector$ActionViewHolder": "androidx/leanback/widget/ControlButtonPresenterSelector$ActionViewHolder",
+ "android/support/transition/GhostViewApi14$Creator": "androidx/transition/GhostViewApi14$Creator",
+ "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatApi19Impl": "androidx/widget/PopupWindowCompat$PopupWindowCompatApi19Impl",
+ "android/support/v17/leanback/widget/GuidedActionsStylist": "androidx/leanback/widget/GuidedActionsStylist",
+ "android/support/v4/app/ActivityCompat$SharedElementCallback21Impl": "androidx/app/ActivityCompat$SharedElementCallback21Impl",
+ "android/support/v17/leanback/app/BrowseFragment$FragmentFactory": "androidx/leanback/app/BrowseFragment$FragmentFactory",
+ "android/support/v7/widget/DefaultItemAnimator$MoveInfo": "androidx/widget/DefaultItemAnimator$MoveInfo",
+ "android/support/media/instantvideo/preload/InstantVideoPreloadManager$VideoPreloader": "androidx/media/instantvideo/preload/InstantVideoPreloadManager$VideoPreloader",
+ "android/support/v4/media/MediaBrowserCompat": "androidx/media/MediaBrowserCompat",
+ "android/support/v7/media/MediaRouter$RouteGroup": "androidx/media/MediaRouter$RouteGroup",
+ "android/support/v4/view/ViewCompat$OverScroll": "androidx/view/ViewCompat$OverScroll",
+ "android/support/v7/media/SystemMediaRouteProvider$LegacyImpl$VolumeChangeReceiver": "androidx/media/SystemMediaRouteProvider$LegacyImpl$VolumeChangeReceiver",
+ "android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21": "androidx/leanback/preference/LeanbackPreferenceFragmentTransitionHelperApi21",
+ "android/support/v17/leanback/widget/BaseGridView$OnUnhandledKeyListener": "androidx/leanback/widget/BaseGridView$OnUnhandledKeyListener",
+ "android/support/v7/view/menu/ActionMenuItemView$ActionMenuItemForwardingListener": "androidx/view/menu/ActionMenuItemView$ActionMenuItemForwardingListener",
+ "android/support/v17/leanback/transition/FadeAndShortSlide": "androidx/leanback/transition/FadeAndShortSlide",
+ "android/support/v7/app/NavItemSelectedListener": "androidx/app/NavItemSelectedListener",
+ "android/support/v4/content/pm/ShortcutManagerCompat": "androidx/content/pm/ShortcutManagerCompat",
+ "android/support/v4/app/FragmentActivity$HostCallbacks": "androidx/app/FragmentActivity$HostCallbacks",
+ "android/support/design/widget/CoordinatorLayout$LayoutParams": "androidx/design/widget/CoordinatorLayout$LayoutParams",
+ "android/support/v4/view/MenuItemCompat$MenuItemCompatApi26Impl": "androidx/view/MenuItemCompat$MenuItemCompatApi26Impl",
+ "android/support/transition/ViewGroupOverlayApi18": "androidx/transition/ViewGroupOverlayApi18",
+ "android/support/v17/preference/LeanbackSettingsFragment": "androidx/leanback/preference/LeanbackSettingsFragment",
+ "android/support/v17/leanback/widget/RowHeaderPresenter$ViewHolder": "androidx/leanback/widget/RowHeaderPresenter$ViewHolder",
+ "android/support/wear/ambient/AmbientMode$AmbientController": "androidx/wear/ambient/AmbientMode$AmbientController",
+ "android/support/v7/cardview/R$color": "androidx/cardview/R$color",
+ "android/support/annotation/MenuRes": "androidx/annotation/MenuRes",
+ "android/support/v7/media/MediaRouterJellybeanMr2": "androidx/media/MediaRouterJellybeanMr2",
+ "android/support/v7/widget/GridLayout$PackedMap": "androidx/widget/GridLayout$PackedMap",
+ "android/support/v7/media/MediaRouterJellybeanMr1": "androidx/media/MediaRouterJellybeanMr1",
+ "android/support/transition/ViewGroupOverlayApi14": "androidx/transition/ViewGroupOverlayApi14",
+ "android/support/v7/app/ActionBarDrawerToggleHoneycomb$SetIndicatorInfo": "androidx/app/ActionBarDrawerToggleHoneycomb$SetIndicatorInfo",
+ "android/support/wear/widget/drawer/FlingWatcherFactory$FlingWatcher": "androidx/wear/widget/drawer/FlingWatcherFactory$FlingWatcher",
+ "android/support/v17/leanback/widget/SparseArrayObjectAdapter": "androidx/leanback/widget/SparseArrayObjectAdapter",
+ "android/support/v4/media/session/MediaSessionCompatApi21$CallbackProxy": "androidx/media/session/MediaSessionCompatApi21$CallbackProxy",
+ "android/support/v4/app/NotificationCompat$CarExtender": "androidx/app/NotificationCompat$CarExtender",
+ "android/support/v17/leanback/widget/PlaybackControlsRowView$OnUnhandledKeyListener": "androidx/leanback/widget/PlaybackControlsRowView$OnUnhandledKeyListener",
+ "android/support/v7/view/menu/MenuPopupHelper": "androidx/view/menu/MenuPopupHelper",
+ "android/support/v17/leanback/app/VideoSupportFragment": "androidx/leanback/app/VideoSupportFragment",
+ "android/support/media/tv/Channel": "androidx/media/tv/Channel",
+ "android/support/v4/media/AudioAttributesCompat$AttributeContentType": "androidx/media/AudioAttributesCompat$AttributeContentType",
+ "android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper$TransitionTimeOutRunnable": "androidx/leanback/widget/DetailsOverviewSharedElementHelper$TransitionTimeOutRunnable",
+ "android/support/v17/leanback/app/BrowseSupportFragment$BrowseTransitionListener": "androidx/leanback/app/BrowseSupportFragment$BrowseTransitionListener",
+ "android/support/v4/view/ViewPager$ViewPositionComparator": "androidx/view/ViewPager$ViewPositionComparator",
+ "android/support/v4/app/NotificationCompat$Action": "androidx/app/NotificationCompat$Action",
+ "android/support/v7/preference/PreferenceManager$SimplePreferenceComparisonCallback": "androidx/preference/PreferenceManager$SimplePreferenceComparisonCallback",
+ "android/support/media/tv/TvContractCompat$BaseTvColumns": "androidx/media/tv/TvContractCompat$BaseTvColumns",
+ "android/support/v4/media/session/PlaybackStateCompat$ShuffleMode": "androidx/media/session/PlaybackStateCompat$ShuffleMode",
+ "android/support/v7/app/WindowDecorActionBar$TabImpl": "androidx/app/WindowDecorActionBar$TabImpl",
+ "android/support/graphics/drawable/VectorDrawableCompat$VectorDrawableDelegateState": "androidx/graphics/drawable/VectorDrawableCompat$VectorDrawableDelegateState",
+ "android/support/v7/media/SystemMediaRouteProvider$JellybeanImpl": "androidx/media/SystemMediaRouteProvider$JellybeanImpl",
+ "android/support/v7/widget/VectorEnabledTintResources": "androidx/widget/VectorEnabledTintResources",
+ "android/support/v7/preference/EditTextPreferenceDialogFragmentCompat": "androidx/preference/EditTextPreferenceDialogFragmentCompat",
+ "android/support/v4/graphics/drawable/DrawableWrapperApi19$DrawableWrapperStateKitKat": "androidx/graphics/drawable/DrawableWrapperApi19$DrawableWrapperStateKitKat",
+ "android/support/v17/leanback/transition/TransitionHelperKitkat$CustomChangeBounds": "androidx/leanback/transition/TransitionHelperKitkat$CustomChangeBounds",
+ "android/support/v4/app/FragmentManagerImpl$StartEnterTransitionListener": "androidx/app/FragmentManagerImpl$StartEnterTransitionListener",
+ "android/support/v4/view/LayoutInflaterCompat$LayoutInflaterCompatBaseImpl": "androidx/view/LayoutInflaterCompat$LayoutInflaterCompatBaseImpl",
+ "android/support/v7/view/SupportMenuInflater$MenuState": "androidx/view/SupportMenuInflater$MenuState",
+ "android/support/v17/leanback/app/GuidedStepFragment": "androidx/leanback/app/GuidedStepFragment",
+ "android/support/v17/leanback/widget/PagingIndicator": "androidx/leanback/widget/PagingIndicator",
+ "android/support/v7/app/MediaRouteControllerDialog$MediaRouterCallback": "androidx/app/MediaRouteControllerDialog$MediaRouterCallback",
+ "android/support/design/widget/CoordinatorLayout$DefaultBehavior": "androidx/design/widget/CoordinatorLayout$DefaultBehavior",
+ "android/support/v4/os/LocaleListInterface": "androidx/os/LocaleListInterface",
+ "android/support/v4/hardware/fingerprint/FingerprintManagerCompat$AuthenticationCallback": "androidx/hardware/fingerprint/FingerprintManagerCompat$AuthenticationCallback",
+ "android/support/v17/leanback/widget/Parallax$FloatProperty": "androidx/leanback/widget/Parallax$FloatProperty",
+ "android/support/v4/app/NotificationCompat$Style": "androidx/app/NotificationCompat$Style",
+ "android/support/v4/app/FrameMetricsAggregator$FrameMetricsApi24Impl": "androidx/app/FrameMetricsAggregator$FrameMetricsApi24Impl",
+ "android/support/v17/leanback/app/HeadersSupportFragment$OnHeaderClickedListener": "androidx/leanback/app/HeadersSupportFragment$OnHeaderClickedListener",
+ "android/support/v7/preference/PreferenceManager$OnNavigateToScreenListener": "androidx/preference/PreferenceManager$OnNavigateToScreenListener",
+ "android/support/v7/widget/AdapterHelper": "androidx/widget/AdapterHelper",
+ "android/support/v17/leanback/transition/SlideKitkat$CalculateSlideHorizontal": "androidx/leanback/transition/SlideKitkat$CalculateSlideHorizontal",
+ "android/support/v4/graphics/ColorUtils": "androidx/graphics/ColorUtils",
+ "android/support/v7/widget/ActionMenuPresenter$OverflowMenuButton": "androidx/widget/ActionMenuPresenter$OverflowMenuButton",
+ "android/support/v7/widget/ListPopupWindow": "androidx/widget/ListPopupWindow",
+ "android/support/v4/media/MediaBrowserServiceCompatApi21$MediaBrowserServiceAdaptor": "androidx/media/MediaBrowserServiceCompatApi21$MediaBrowserServiceAdaptor",
+ "android/support/v17/leanback/widget/Row": "androidx/leanback/widget/Row",
+ "android/support/v17/leanback/widget/ShadowOverlayHelper": "androidx/leanback/widget/ShadowOverlayHelper",
+ "android/support/wear/internal/widget/drawer/MultiPagePresenter": "androidx/wear/internal/widget/drawer/MultiPagePresenter",
+ "android/support/animation/SpringForce": "androidx/animation/SpringForce",
+ "android/support/customtabs/ICustomTabsService$Stub$Proxy": "androidx/browser/customtabs/ICustomTabsService$Stub$Proxy",
+ "android/support/annotation/StringDef": "androidx/annotation/StringDef",
+ "android/support/v4/media/session/MediaControllerCompat$MediaControllerImpl": "androidx/media/session/MediaControllerCompat$MediaControllerImpl",
+ "android/support/design/widget/CircularBorderDrawableLollipop": "androidx/design/widget/CircularBorderDrawableLollipop",
+ "android/support/v17/leanback/widget/ControlBarPresenter$BoundData": "androidx/leanback/widget/ControlBarPresenter$BoundData",
+ "android/support/v7/widget/RecyclerView$Orientation": "androidx/widget/RecyclerView$Orientation",
+ "android/support/v7/media/MediaRouteProviderService$ReceiveHandler": "androidx/media/MediaRouteProviderService$ReceiveHandler",
+ "android/support/v4/view/ViewPropertyAnimatorListenerAdapter": "androidx/view/ViewPropertyAnimatorListenerAdapter",
+ "android/support/v7/graphics/Palette$Swatch": "androidx/graphics/Palette$Swatch",
+ "android/support/v17/leanback/widget/GridLayoutManager": "androidx/leanback/widget/GridLayoutManager",
+ "android/support/v17/leanback/media/PlaybackGlue": "androidx/leanback/media/PlaybackGlue",
+ "android/support/v17/leanback/widget/ShadowHelper$ShadowHelperApi21Impl": "androidx/leanback/widget/ShadowHelper$ShadowHelperApi21Impl",
+ "android/support/v4/view/ViewCompat": "androidx/view/ViewCompat",
+ "android/support/v17/leanback/widget/BackgroundHelper": "androidx/leanback/widget/BackgroundHelper",
+ "android/support/design/widget/AppBarLayout$OnOffsetChangedListener": "androidx/design/widget/AppBarLayout$OnOffsetChangedListener",
+ "android/support/v4/view/GestureDetectorCompat$GestureDetectorCompatImplJellybeanMr2": "androidx/view/GestureDetectorCompat$GestureDetectorCompatImplJellybeanMr2",
+ "android/support/v7/appcompat/R$attr": "androidx/appcompat/R$attr",
+ "android/support/transition/TransitionValuesMaps": "androidx/transition/TransitionValuesMaps",
+ "android/support/v4/view/ViewConfigurationCompat": "androidx/view/ViewConfigurationCompat",
+ "android/support/v4/media/MediaBrowserServiceCompat$ServiceCallbacks": "androidx/media/MediaBrowserServiceCompat$ServiceCallbacks",
+ "android/support/v4/widget/AutoSizeableTextView": "androidx/widget/AutoSizeableTextView",
+ "android/support/v4/view/ViewCompat$LayerType": "androidx/view/ViewCompat$LayerType",
+ "android/support/v17/leanback/widget/DividerRow": "androidx/leanback/widget/DividerRow",
+ "android/support/v7/widget/ActionMenuPresenter$SavedState": "androidx/widget/ActionMenuPresenter$SavedState",
+ "android/support/design/internal/NavigationMenu": "androidx/design/internal/NavigationMenu",
+ "android/support/v7/preference/Preference$OnPreferenceChangeInternalListener": "androidx/preference/Preference$OnPreferenceChangeInternalListener",
+ "android/support/v4/app/JobIntentService": "androidx/app/JobIntentService",
+ "android/support/v4/app/Fragment": "androidx/app/Fragment",
+ "android/support/v17/leanback/app/BrowseSupportFragment$BackStackListener": "androidx/leanback/app/BrowseSupportFragment$BackStackListener",
+ "android/support/v7/widget/RecyclerView$OnChildAttachStateChangeListener": "androidx/widget/RecyclerView$OnChildAttachStateChangeListener",
+ "android/support/v17/leanback/widget/PlaybackSeekDataProvider": "androidx/leanback/widget/PlaybackSeekDataProvider",
+ "android/support/content/ContentPager": "androidx/content/ContentPager",
+ "android/support/v4/util/MapCollections$MapIterator": "androidx/util/MapCollections$MapIterator",
+ "android/support/app/recommendation/ContentRecommendation": "androidx/app/recommendation/ContentRecommendation",
+ "android/support/v7/app/ActionBar$OnNavigationListener": "androidx/app/ActionBar$OnNavigationListener",
+ "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase": "androidx/media/session/MediaSessionCompat$MediaSessionImplBase",
+ "android/support/transition/Styleable$ChangeTransform": "androidx/transition/Styleable$ChangeTransform",
+ "android/support/v7/media/SystemMediaRouteProvider$LegacyImpl$DefaultRouteController": "androidx/media/SystemMediaRouteProvider$LegacyImpl$DefaultRouteController",
+ "android/support/v4/net/DatagramSocketWrapper$DatagramSocketImplWrapper": "androidx/net/DatagramSocketWrapper$DatagramSocketImplWrapper",
+ "android/support/v17/leanback/R$layout": "androidx/leanback/R$layout",
+ "android/support/v4/app/FragmentHostCallback": "androidx/app/FragmentHostCallback",
+ "android/support/v7/widget/StaggeredGridLayoutManager$AnchorInfo": "androidx/widget/StaggeredGridLayoutManager$AnchorInfo",
+ "android/support/v7/widget/RecyclerView$State": "androidx/widget/RecyclerView$State",
+ "android/support/v7/media/MediaRouterJellybean$Callback": "androidx/media/MediaRouterJellybean$Callback",
+ "android/support/v14/preference/MultiSelectListPreferenceDialogFragment": "androidx/preference/MultiSelectListPreferenceDialogFragment",
+ "android/support/v4/media/MediaBrowserServiceCompatApi21$ServiceCompatProxy": "androidx/media/MediaBrowserServiceCompatApi21$ServiceCompatProxy",
+ "android/support/v4/text/util/LinkifyCompat$LinkSpec": "androidx/text/util/LinkifyCompat$LinkSpec",
+ "android/support/v4/app/NotificationManagerCompat$ServiceConnectedEvent": "androidx/app/NotificationManagerCompat$ServiceConnectedEvent",
+ "android/support/v4/graphics/drawable/IconCompat": "androidx/graphics/drawable/IconCompat",
+ "android/support/v17/leanback/graphics/ColorOverlayDimmer": "androidx/leanback/graphics/ColorOverlayDimmer",
+ "android/support/v17/leanback/R$styleable": "androidx/leanback/R$styleable",
+ "android/support/v4/view/AccessibilityDelegateCompat": "androidx/view/AccessibilityDelegateCompat",
+ "android/support/v7/cardview/R$dimen": "androidx/cardview/R$dimen",
+ "android/support/wear/widget/SwipeDismissFrameLayout$Callback": "androidx/wear/widget/SwipeDismissFrameLayout$Callback",
+ "android/support/transition/ArcMotion": "androidx/transition/ArcMotion",
+ "android/support/mediacompat/R$layout": "androidx/mediacompat/R$layout",
+ "android/support/v4/view/ViewPager$ItemInfo": "androidx/view/ViewPager$ItemInfo",
+ "android/support/v4/app/FragmentActivity": "androidx/app/FragmentActivity",
+ "android/support/animation/FloatPropertyCompat": "androidx/animation/FloatPropertyCompat",
+ "android/support/v17/leanback/widget/ObjectAdapter$DataObserver": "androidx/leanback/widget/ObjectAdapter$DataObserver",
+ "android/support/design/widget/AppBarLayout$LayoutParams$ScrollFlags": "androidx/design/widget/AppBarLayout$LayoutParams$ScrollFlags",
+ "android/support/v7/widget/AbsActionBarView": "androidx/widget/AbsActionBarView",
+ "android/support/v4/media/app/NotificationCompat": "androidx/media/app/NotificationCompat",
+ "android/support/v17/leanback/media/PlayerAdapter": "androidx/leanback/media/PlayerAdapter",
+ "android/support/v17/leanback/widget/GridLayoutManager$SavedState": "androidx/leanback/widget/GridLayoutManager$SavedState",
+ "android/support/transition/Fade": "androidx/transition/Fade",
+ "android/support/v17/leanback/R$animator": "androidx/leanback/R$animator",
+ "android/support/v4/view/ViewCompat$ScrollAxis": "androidx/view/ViewCompat$ScrollAxis",
+ "android/support/v17/leanback/widget/GuidedActionEditText$NoPaddingDrawable": "androidx/leanback/widget/GuidedActionEditText$NoPaddingDrawable",
+ "android/support/v7/widget/GridLayout$Axis": "androidx/widget/GridLayout$Axis",
+ "android/support/v4/app/FragmentManagerImpl$AnimationListenerWrapper": "androidx/app/FragmentManagerImpl$AnimationListenerWrapper",
+ "android/support/v4/view/ViewParentCompat$ViewParentCompatBaseImpl": "androidx/view/ViewParentCompat$ViewParentCompatBaseImpl",
+ "android/support/v7/util/DiffUtil$Snake": "androidx/util/DiffUtil$Snake",
+ "android/support/v7/app/AppCompatDelegateImplV9$PanelFeatureState$SavedState": "androidx/app/AppCompatDelegateImplV9$PanelFeatureState$SavedState",
+ "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$ViewHolder": "androidx/leanback/widget/DetailsOverviewRowPresenter$ViewHolder",
+ "android/support/v4/media/RatingCompat$Style": "androidx/media/RatingCompat$Style",
+ "android/support/v7/widget/GridLayout$Spec": "androidx/widget/GridLayout$Spec",
+ "android/support/constraint/solver/widgets/ConstraintAnchor": "androidx/constraint/solver/widgets/ConstraintAnchor",
+ "android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper$TransitionTimeOutRunnable": "androidx/leanback/widget/FullWidthDetailsOverviewSharedElementHelper$TransitionTimeOutRunnable",
+ "android/support/graphics/drawable/animated/BuildConfig": "androidx/graphics/drawable/animated/BuildConfig",
+ "android/support/v4/view/LayoutInflaterFactory": "androidx/view/LayoutInflaterFactory",
+ "android/support/v7/preference/internal/package-info": "androidx/preference/internal/package-info",
+ "android/support/v17/leanback/app/BrowseFragment$MainFragmentAdapterProvider": "androidx/leanback/app/BrowseFragment$MainFragmentAdapterProvider",
+ "android/support/v7/app/OverlayListView$OverlayObject$OnAnimationEndListener": "androidx/app/OverlayListView$OverlayObject$OnAnimationEndListener",
+ "android/support/v7/app/AlertController$RecycleListView": "androidx/app/AlertController$RecycleListView",
+ "android/support/v4/view/ViewCompat$ViewCompatApi18Impl": "androidx/view/ViewCompat$ViewCompatApi18Impl",
+ "android/support/v4/text/TextUtilsCompat": "androidx/text/TextUtilsCompat",
+ "android/support/v17/leanback/widget/Action": "androidx/leanback/widget/Action",
+ "android/support/v7/widget/RecyclerView$ItemAnimator$AdapterChanges": "androidx/widget/RecyclerView$ItemAnimator$AdapterChanges",
+ "android/support/v4/media/session/MediaControllerCompat$MediaControllerExtraData": "androidx/media/session/MediaControllerCompat$MediaControllerExtraData",
+ "android/support/v4/media/session/MediaControllerCompat$TransportControlsBase": "androidx/media/session/MediaControllerCompat$TransportControlsBase",
+ "android/support/v13/view/inputmethod/InputConnectionCompat$InputConnectionCompatImpl": "androidx/view/inputmethod/InputConnectionCompat$InputConnectionCompatImpl",
+ "android/support/v4/media/ParceledListSliceAdapterApi21": "androidx/media/ParceledListSliceAdapterApi21",
+ "android/support/v17/leanback/widget/ItemBridgeAdapter": "androidx/leanback/widget/ItemBridgeAdapter",
+ "android/support/v7/appcompat/BuildConfig": "androidx/appcompat/BuildConfig",
+ "android/support/v13/view/inputmethod/InputConnectionCompat": "androidx/view/inputmethod/InputConnectionCompat",
+ "android/support/v4/widget/ResourceCursorAdapter": "androidx/widget/ResourceCursorAdapter",
+ "android/support/v7/view/WindowCallbackWrapper": "androidx/view/WindowCallbackWrapper",
+ "android/support/v7/widget/AdapterHelper$UpdateOp": "androidx/widget/AdapterHelper$UpdateOp",
+ "android/support/v4/content/res/FontResourcesParserCompat$FontFileResourceEntry": "androidx/content/res/FontResourcesParserCompat$FontFileResourceEntry",
+ "android/support/v4/app/NavUtils": "androidx/app/NavUtils",
+ "android/support/v4/internal/view/SupportMenuItem": "androidx/internal/view/SupportMenuItem",
+ "android/support/v7/widget/FastScroller$DragState": "androidx/widget/FastScroller$DragState",
+ "android/support/annotation/Size": "androidx/annotation/Size",
+ "android/support/wear/widget/drawer/WearableNavigationDrawerView$OnItemSelectedListener": "androidx/wear/widget/drawer/WearableNavigationDrawerView$OnItemSelectedListener",
+ "android/support/transition/WindowIdImpl": "androidx/transition/WindowIdImpl",
+ "android/support/v7/media/RemoteControlClientCompat$LegacyImpl": "androidx/media/RemoteControlClientCompat$LegacyImpl",
+ "android/support/transition/Slide$CalculateSlideVertical": "androidx/transition/Slide$CalculateSlideVertical",
+ "android/support/v17/leanback/app/VideoFragment": "androidx/leanback/app/VideoFragment",
+ "android/support/v4/widget/NestedScrollView$OnScrollChangeListener": "androidx/widget/NestedScrollView$OnScrollChangeListener",
+ "android/support/v7/media/MediaRouter$CallbackFlags": "androidx/media/MediaRouter$CallbackFlags",
+ "android/support/customtabs/IPostMessageService": "androidx/browser/customtabs/IPostMessageService",
+ "android/support/v4/util/AtomicFile": "androidx/util/AtomicFile",
+ "android/support/v4/provider/DocumentsContractApi19": "androidx/provider/DocumentsContractApi19",
+ "android/support/v17/leanback/widget/picker/Picker$ViewHolder": "androidx/leanback/widget/picker/Picker$ViewHolder",
+ "android/support/v4/widget/AutoScrollHelper": "androidx/widget/AutoScrollHelper",
+ "android/support/v4/widget/DrawerLayout$LockMode": "androidx/widget/DrawerLayout$LockMode",
+ "android/support/v17/leanback/transition/SlideKitkat$CalculateSlideVertical": "androidx/leanback/transition/SlideKitkat$CalculateSlideVertical",
+ "android/support/v4/os/BuildCompat": "androidx/os/BuildCompat",
+ "android/support/wear/ambient/SharedLibraryVersion$PresenceHolder": "androidx/wear/ambient/SharedLibraryVersion$PresenceHolder",
+ "android/support/transition/ObjectAnimatorUtilsImpl": "androidx/transition/ObjectAnimatorUtilsImpl",
+ "android/support/v17/leanback/BuildConfig": "androidx/leanback/BuildConfig",
+ "android/support/v7/widget/SearchView$OnSuggestionListener": "androidx/widget/SearchView$OnSuggestionListener",
+ "android/support/design/internal/NavigationMenuPresenter": "androidx/design/internal/NavigationMenuPresenter",
+ "android/support/v17/leanback/widget/ShadowHelper$ShadowHelperVersionImpl": "androidx/leanback/widget/ShadowHelper$ShadowHelperVersionImpl",
+ "android/support/v7/media/RemotePlaybackClient$ItemActionCallback": "androidx/media/RemotePlaybackClient$ItemActionCallback",
+ "android/support/graphics/drawable/BuildConfig": "androidx/graphics/drawable/BuildConfig",
+ "android/support/annotation/Dimension": "androidx/annotation/Dimension",
+ "android/support/v13/view/DragStartHelper$OnDragStartListener": "androidx/view/DragStartHelper$OnDragStartListener",
+ "android/support/text/emoji/R$id": "androidx/text/emoji/R$id",
+ "android/support/wear/widget/CurvingLayoutCallback": "androidx/wear/widget/CurvingLayoutCallback",
+ "android/support/v17/leanback/app/RowsFragment": "androidx/leanback/app/RowsFragment",
+ "android/support/v7/widget/TooltipCompat": "androidx/widget/TooltipCompat",
+ "android/support/v7/widget/SnapHelper": "androidx/widget/SnapHelper",
+ "android/support/v7/mediarouter/R$layout": "androidx/mediarouter/R$layout",
+ "android/support/transition/R$id": "androidx/transition/R$id",
+ "android/support/v4/graphics/BitmapCompat$BitmapCompatBaseImpl": "androidx/graphics/BitmapCompat$BitmapCompatBaseImpl",
+ "android/support/v4/media/VolumeProviderCompatApi21$Delegate": "androidx/media/VolumeProviderCompatApi21$Delegate",
+ "android/support/v17/leanback/widget/SearchBar$SearchBarListener": "androidx/leanback/widget/SearchBar$SearchBarListener",
+ "android/support/v17/leanback/app/SearchFragment": "androidx/leanback/app/SearchFragment",
+ "android/support/v4/view/LayoutInflaterCompat": "androidx/view/LayoutInflaterCompat",
+ "android/support/v7/widget/CardViewApi21Impl": "androidx/widget/CardViewApi21Impl",
+ "android/support/v17/leanback/widget/VideoSurfaceView": "androidx/leanback/widget/VideoSurfaceView",
+ "android/support/transition/GhostViewImpl": "androidx/transition/GhostViewImpl",
+ "android/support/transition/ChangeBounds": "androidx/transition/ChangeBounds",
+ "android/support/v17/leanback/app/HeadersFragment$OnHeaderViewSelectedListener": "androidx/leanback/app/HeadersFragment$OnHeaderViewSelectedListener",
+ "android/support/media/tv/PreviewProgram": "androidx/media/tv/PreviewProgram",
+ "android/support/annotation/RequiresApi": "androidx/annotation/RequiresApi",
+ "android/support/app/recommendation/RecommendationExtender": "androidx/app/recommendation/RecommendationExtender",
+ "android/support/v17/leanback/app/ErrorSupportFragment": "androidx/leanback/app/ErrorSupportFragment",
+ "android/support/v17/leanback/media/MediaPlayerGlue": "androidx/leanback/media/MediaPlayerGlue",
+ "android/support/v4/media/session/MediaSessionCompatApi21$QueueItem": "androidx/media/session/MediaSessionCompatApi21$QueueItem",
+ "android/support/v17/leanback/widget/AbstractMediaItemPresenter": "androidx/leanback/widget/AbstractMediaItemPresenter",
+ "android/support/annotation/StyleableRes": "androidx/annotation/StyleableRes",
+ "android/support/v4/media/session/PlaybackStateCompat$CustomAction": "androidx/media/session/PlaybackStateCompat$CustomAction",
+ "android/support/wear/widget/drawer/WearableDrawerLayout$TopDrawerDraggerCallback": "androidx/wear/widget/drawer/WearableDrawerLayout$TopDrawerDraggerCallback",
+ "android/support/v17/leanback/app/PermissionHelper": "androidx/leanback/app/PermissionHelper",
+ "android/support/transition/R": "androidx/transition/R",
+ "android/support/v17/leanback/transition/SlideKitkat$SlideAnimatorListener": "androidx/leanback/transition/SlideKitkat$SlideAnimatorListener",
+ "android/support/v7/graphics/drawable/DrawerArrowDrawable": "androidx/graphics/drawable/DrawerArrowDrawable",
+ "android/support/v17/leanback/widget/ClassPresenterSelector": "androidx/leanback/widget/ClassPresenterSelector",
+ "android/support/v17/leanback/widget/ControlBarPresenter$OnControlSelectedListener": "androidx/leanback/widget/ControlBarPresenter$OnControlSelectedListener",
+ "android/support/v4/app/NotificationCompat$GroupAlertBehavior": "androidx/app/NotificationCompat$GroupAlertBehavior",
+ "android/support/text/emoji/widget/EmojiInputFilter$InitCallbackImpl": "androidx/text/emoji/widget/EmojiInputFilter$InitCallbackImpl",
+ "android/support/v7/appcompat/R$bool": "androidx/appcompat/R$bool",
+ "android/support/v4/widget/TextViewCompat$AutoSizeTextType": "androidx/widget/TextViewCompat$AutoSizeTextType",
+ "android/support/v4/app/NotificationCompat$BadgeIconType": "androidx/app/NotificationCompat$BadgeIconType",
+ "android/support/v4/app/NotificationCompat$BigTextStyle": "androidx/app/NotificationCompat$BigTextStyle",
+ "android/support/annotation/ColorInt": "androidx/annotation/ColorInt",
+ "android/support/text/emoji/EmojiSpan": "androidx/text/emoji/EmojiSpan",
+ "android/support/wear/widget/SwipeDismissFrameLayout$MyOnDismissedListener": "androidx/wear/widget/SwipeDismissFrameLayout$MyOnDismissedListener",
+ "android/support/percent/PercentRelativeLayout": "androidx/PercentRelativeLayout",
+ "android/support/text/emoji/widget/EmojiInputFilter": "androidx/text/emoji/widget/EmojiInputFilter",
+ "android/support/media/tv/TvContractCompat$PreviewPrograms": "androidx/media/tv/TvContractCompat$PreviewPrograms",
+ "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder",
+ "android/support/v17/leanback/app/BrowseFragment$BackStackListener": "androidx/leanback/app/BrowseFragment$BackStackListener",
+ "android/support/text/emoji/EmojiProcessor$ProcessorSm": "androidx/text/emoji/EmojiProcessor$ProcessorSm",
+ "android/support/v4/view/ViewCompat$ViewCompatBaseImpl": "androidx/view/ViewCompat$ViewCompatBaseImpl",
+ "android/support/design/internal/BottomNavigationMenu": "androidx/design/internal/BottomNavigationMenu",
+ "android/support/v7/view/menu/BaseMenuWrapper": "androidx/view/menu/BaseMenuWrapper",
+ "android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory$DefaultRoundedBitmapDrawable": "androidx/graphics/drawable/RoundedBitmapDrawableFactory$DefaultRoundedBitmapDrawable",
+ "android/support/v17/leanback/widget/OnItemViewClickedListener": "androidx/leanback/widget/OnItemViewClickedListener",
+ "android/support/v4/app/ShareCompat": "androidx/app/ShareCompat",
+ "android/support/v4/app/DialogFragment": "androidx/app/DialogFragment",
+ "android/support/v4/os/ConfigurationCompat": "androidx/os/ConfigurationCompat",
+ "android/support/v4/graphics/drawable/DrawableCompat": "androidx/graphics/drawable/DrawableCompat",
+ "android/support/v17/leanback/widget/PlaybackTransportRowView": "androidx/leanback/widget/PlaybackTransportRowView",
+ "android/support/annotation/ColorRes": "androidx/annotation/ColorRes",
+ "android/support/v4/database/DatabaseUtilsCompat": "androidx/database/DatabaseUtilsCompat",
+ "android/support/v7/app/AppCompatDelegateImplBase$ActionBarDrawableToggleImpl": "androidx/app/AppCompatDelegateImplBase$ActionBarDrawableToggleImpl",
+ "android/support/v7/widget/ForwardingListener": "androidx/widget/ForwardingListener",
+ "android/support/annotation/NavigationRes": "androidx/annotation/NavigationRes",
+ "android/support/v4/widget/TextViewCompat$TextViewCompatApi18Impl": "androidx/widget/TextViewCompat$TextViewCompatApi18Impl",
+ "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase$Command": "androidx/media/session/MediaSessionCompat$MediaSessionImplBase$Command",
+ "android/support/transition/Styleable$ArcMotion": "androidx/transition/Styleable$ArcMotion",
+ "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperStubImpl": "androidx/leanback/transition/TransitionHelper$TransitionHelperStubImpl",
+ "android/support/text/emoji/widget/EmojiEditTextHelper$HelperInternal": "androidx/text/emoji/widget/EmojiEditTextHelper$HelperInternal",
+ "android/support/wear/widget/BezierSCurveInterpolator": "androidx/wear/widget/BezierSCurveInterpolator",
+ "android/support/v4/view/NestedScrollingParent": "androidx/view/NestedScrollingParent",
+ "android/support/v7/widget/ListPopupWindow$ListSelectorHider": "androidx/widget/ListPopupWindow$ListSelectorHider",
+ "android/support/transition/PathProperty": "androidx/transition/PathProperty",
+ "android/support/v4/provider/FontsContractCompat$FontInfo": "androidx/provider/FontsContractCompat$FontInfo",
+ "android/support/v17/leanback/widget/PlaybackControlsRow": "androidx/leanback/widget/PlaybackControlsRow",
+ "android/support/v17/leanback/widget/Presenter": "androidx/leanback/widget/Presenter",
+ "android/support/v17/leanback/app/VerticalGridFragment": "androidx/leanback/app/VerticalGridFragment",
+ "android/support/v4/app/LoaderManagerImpl$LoaderInfo": "androidx/app/LoaderManagerImpl$LoaderInfo",
+ "android/support/v7/widget/RoundRectDrawableWithShadow": "androidx/widget/RoundRectDrawableWithShadow",
+ "android/support/v7/app/AppCompatDelegateImplV9$PanelFeatureState": "androidx/app/AppCompatDelegateImplV9$PanelFeatureState",
+ "android/support/v7/media/SystemMediaRouteProvider$JellybeanImpl$UserRouteRecord": "androidx/media/SystemMediaRouteProvider$JellybeanImpl$UserRouteRecord",
+ "android/support/v4/view/accessibility/AccessibilityManagerCompat": "androidx/view/accessibility/AccessibilityManagerCompat",
+ "android/support/v4/view/ScrollingView": "androidx/view/ScrollingView",
+ "android/support/customtabs/CustomTabsIntent": "androidx/browser/customtabs/CustomTabsIntent",
+ "android/support/v17/leanback/transition/TransitionListener": "androidx/leanback/transition/TransitionListener",
+ "android/support/annotation/DimenRes": "androidx/annotation/DimenRes",
+ "android/support/v17/leanback/widget/Parallax$IntProperty": "androidx/leanback/widget/Parallax$IntProperty",
+ "android/support/v4/app/FragmentManagerImpl$AnimationOrAnimator": "androidx/app/FragmentManagerImpl$AnimationOrAnimator",
+ "android/support/v4/widget/TextViewCompat$TextViewCompatBaseImpl": "androidx/widget/TextViewCompat$TextViewCompatBaseImpl",
+ "android/support/v17/leanback/app/BrowseFragment$ExpandPreLayout": "androidx/leanback/app/BrowseFragment$ExpandPreLayout",
+ "android/support/v13/view/DragAndDropPermissionsCompat$BaseDragAndDropPermissionsCompatImpl": "androidx/view/DragAndDropPermissionsCompat$BaseDragAndDropPermissionsCompatImpl",
+ "android/support/multidex/MultiDexExtractor": "androidx/multidex/MultiDexExtractor",
+ "android/support/v17/leanback/widget/GuidedDatePickerAction$Builder": "androidx/leanback/widget/GuidedDatePickerAction$Builder",
+ "android/support/v7/widget/AppCompatRatingBar": "androidx/widget/AppCompatRatingBar",
+ "android/support/wear/R$string": "androidx/wear/R$string",
+ "android/support/v7/app/AppCompatDelegateImplN": "androidx/app/AppCompatDelegateImplN",
+ "android/support/v17/leanback/widget/GridLayoutManager$PendingMoveSmoothScroller": "androidx/leanback/widget/GridLayoutManager$PendingMoveSmoothScroller",
+ "android/support/v17/leanback/widget/GuidedActionItemContainer": "androidx/leanback/widget/GuidedActionItemContainer",
+ "android/support/transition/ObjectAnimatorUtils": "androidx/transition/ObjectAnimatorUtils",
+ "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$CollectionInfoCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat$CollectionInfoCompat",
+ "android/support/design/widget/CoordinatorLayout$DispatchChangeEvent": "androidx/design/widget/CoordinatorLayout$DispatchChangeEvent",
+ "android/support/annotation/HalfFloat": "androidx/annotation/HalfFloat",
+ "android/support/v4/view/ViewCompat$ViewCompatApi16Impl": "androidx/view/ViewCompat$ViewCompatApi16Impl",
+ "android/support/v7/text/AllCapsTransformationMethod": "androidx/text/AllCapsTransformationMethod",
+ "android/support/v4/app/FragmentController": "androidx/app/FragmentController",
+ "android/support/v17/leanback/app/SearchSupportFragment$SearchResultProvider": "androidx/leanback/app/SearchSupportFragment$SearchResultProvider",
+ "android/support/v17/leanback/widget/RoundedRectHelper$StubImpl": "androidx/leanback/widget/RoundedRectHelper$StubImpl",
+ "android/support/v4/graphics/drawable/RoundedBitmapDrawable": "androidx/graphics/drawable/RoundedBitmapDrawable",
+ "android/support/v4/widget/ScrollerCompat": "androidx/widget/ScrollerCompat",
+ "android/support/v17/leanback/widget/RoundedRectHelper$Api21Impl": "androidx/leanback/widget/RoundedRectHelper$Api21Impl",
+ "android/support/wear/internal/widget/drawer/SinglePagePresenter$Ui": "androidx/wear/internal/widget/drawer/SinglePagePresenter$Ui",
+ "android/support/v7/app/AppCompatDelegateImplV14$AutoNightModeManager": "androidx/app/AppCompatDelegateImplV14$AutoNightModeManager",
+ "android/support/v17/leanback/widget/ImeKeyMonitor$ImeKeyListener": "androidx/leanback/widget/ImeKeyMonitor$ImeKeyListener",
+ "android/support/v4/view/InputDeviceCompat": "androidx/view/InputDeviceCompat",
+ "android/support/wear/widget/CircularProgressLayoutController": "androidx/wear/widget/CircularProgressLayoutController",
+ "android/support/v17/leanback/widget/PlaybackTransportRowView$OnUnhandledKeyListener": "androidx/leanback/widget/PlaybackTransportRowView$OnUnhandledKeyListener",
+ "android/support/v4/view/ViewCompat$AccessibilityLiveRegion": "androidx/view/ViewCompat$AccessibilityLiveRegion",
+ "android/support/v13/app/FragmentCompat$FragmentCompatImpl": "androidx/app/FragmentCompat$FragmentCompatImpl",
+ "android/support/design/widget/Snackbar": "androidx/design/widget/Snackbar",
+ "android/support/v7/preference/PreferenceGroupAdapter": "androidx/preference/PreferenceGroupAdapter",
+ "android/support/v4/view/MenuItemCompat": "androidx/view/MenuItemCompat",
+ "android/support/v7/widget/ChildHelper$Bucket": "androidx/widget/ChildHelper$Bucket",
+ "android/support/v7/util/DiffUtil$DiffResult": "androidx/util/DiffUtil$DiffResult",
+ "android/support/v13/app/FragmentCompat$PermissionCompatDelegate": "androidx/app/FragmentCompat$PermissionCompatDelegate",
+ "android/support/v4/view/MotionEventCompat": "androidx/view/MotionEventCompat",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$ClosedCaptioningAction": "androidx/leanback/widget/PlaybackControlsRow$ClosedCaptioningAction",
+ "android/support/v4/app/FragmentState": "androidx/app/FragmentState",
+ "android/support/v7/widget/CardView": "androidx/widget/CardView",
+ "android/support/v13/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatApi25Impl": "androidx/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatApi25Impl",
+ "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatBaseImpl": "androidx/widget/PopupWindowCompat$PopupWindowCompatBaseImpl",
+ "android/support/media/tv/TvContractCompat$PreviewProgramColumns$Type": "androidx/media/tv/TvContractCompat$PreviewProgramColumns$Type",
+ "android/support/v4/media/session/MediaSessionCompat$OnActiveChangeListener": "androidx/media/session/MediaSessionCompat$OnActiveChangeListener",
+ "android/support/design/widget/BottomSheetBehavior": "androidx/design/widget/BottomSheetBehavior",
+ "android/support/customtabs/CustomTabsSession": "androidx/browser/customtabs/CustomTabsSession",
+ "android/support/v7/media/RemotePlaybackClient$StatusCallback": "androidx/media/RemotePlaybackClient$StatusCallback",
+ "android/support/v17/leanback/app/HeadersSupportFragment$OnHeaderViewSelectedListener": "androidx/leanback/app/HeadersSupportFragment$OnHeaderViewSelectedListener",
+ "android/support/v4/view/ViewPager$OnPageChangeListener": "androidx/view/ViewPager$OnPageChangeListener",
+ "android/support/v4/app/BackStackRecord$Op": "androidx/app/BackStackRecord$Op",
+ "android/support/media/ExifInterface$ExifAttribute": "androidx/media/ExifInterface$ExifAttribute",
+ "android/support/transition/ChangeBounds$ViewBounds": "androidx/transition/ChangeBounds$ViewBounds",
+ "android/support/v17/leanback/widget/NonOverlappingLinearLayoutWithForeground": "androidx/leanback/widget/NonOverlappingLinearLayoutWithForeground",
+ "android/support/v4/app/NotificationCompat$BigPictureStyle": "androidx/app/NotificationCompat$BigPictureStyle",
+ "android/support/design/widget/FloatingActionButton$ShadowDelegateImpl": "androidx/design/widget/FloatingActionButton$ShadowDelegateImpl",
+ "android/support/media/instantvideo/preload/InstantVideoPreloadManager$VideoPreloaderFactory": "androidx/media/instantvideo/preload/InstantVideoPreloadManager$VideoPreloaderFactory",
+ "android/support/v7/app/MediaRouteDialogHelper": "androidx/app/MediaRouteDialogHelper",
+ "android/support/media/ExifInterface$ExifTag": "androidx/media/ExifInterface$ExifTag",
+ "android/support/v17/leanback/widget/BaseCardView$InfoHeightAnimation": "androidx/leanback/widget/BaseCardView$InfoHeightAnimation",
+ "android/support/v13/view/inputmethod/EditorInfoCompat$EditorInfoCompatApi25Impl": "androidx/view/inputmethod/EditorInfoCompat$EditorInfoCompatApi25Impl",
+ "android/support/transition/TransitionSet$TransitionSetListener": "androidx/transition/TransitionSet$TransitionSetListener",
+ "android/support/v17/leanback/transition/SlideKitkat$CalculateSlide": "androidx/leanback/transition/SlideKitkat$CalculateSlide",
+ "android/support/v4/app/ActivityCompat$OnRequestPermissionsResultCallback": "androidx/app/ActivityCompat$OnRequestPermissionsResultCallback",
+ "android/support/v7/widget/AppCompatRadioButton": "androidx/widget/AppCompatRadioButton",
+ "android/support/v4/app/TaskStackBuilder$TaskStackBuilderApi16Impl": "androidx/app/TaskStackBuilder$TaskStackBuilderApi16Impl",
+ "android/support/v7/media/MediaRouter$RouteInfo$PlaybackVolume": "androidx/media/MediaRouter$RouteInfo$PlaybackVolume",
+ "android/support/v17/preference/LeanbackListPreferenceDialogFragment$AdapterMulti": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment$AdapterMulti",
+ "android/support/v4/print/PrintHelper$PrintHelperApi19": "androidx/print/PrintHelper$PrintHelperApi19",
+ "android/support/v7/media/MediaRouter$RouteInfo$DeviceType": "androidx/media/MediaRouter$RouteInfo$DeviceType",
+ "android/support/v4/media/MediaBrowserCompat$SubscriptionCallback": "androidx/media/MediaBrowserCompat$SubscriptionCallback",
+ "android/support/v4/media/MediaBrowserCompat$MediaItem$Flags": "androidx/media/MediaBrowserCompat$MediaItem$Flags",
+ "android/support/v17/leanback/R$attr": "androidx/leanback/R$attr",
+ "android/support/v7/media/MediaRouteDescriptor$Builder": "androidx/media/MediaRouteDescriptor$Builder",
+ "android/support/v7/media/MediaRouteProviderService": "androidx/media/MediaRouteProviderService",
+ "android/support/v4/app/ActivityCompat$RequestPermissionsRequestCodeValidator": "androidx/app/ActivityCompat$RequestPermissionsRequestCodeValidator",
+ "android/support/v17/leanback/widget/ControlBar$OnChildFocusedListener": "androidx/leanback/widget/ControlBar$OnChildFocusedListener",
+ "android/support/v7/media/MediaRouterApi24$RouteInfo": "androidx/media/MediaRouterApi24$RouteInfo",
+ "android/support/v4/app/JobIntentService$WorkEnqueuer": "androidx/app/JobIntentService$WorkEnqueuer",
+ "android/support/v7/preference/DialogPreference$TargetFragment": "androidx/preference/DialogPreference$TargetFragment",
+ "android/support/wear/widget/BoxInsetLayout$LayoutParams": "androidx/wear/widget/BoxInsetLayout$LayoutParams",
+ "android/support/v4/util/SimpleArrayMap": "androidx/util/SimpleArrayMap",
+ "android/support/v4/widget/EdgeEffectCompat": "androidx/widget/EdgeEffectCompat",
+ "android/support/v13/app/FragmentCompat$FragmentCompatApi15Impl": "androidx/app/FragmentCompat$FragmentCompatApi15Impl",
+ "android/support/v4/print/PrintHelper$PrintHelperApi23": "androidx/print/PrintHelper$PrintHelperApi23",
+ "android/support/percent/R$styleable": "androidx/R$styleable",
+ "android/support/v4/print/PrintHelper$PrintHelperApi24": "androidx/print/PrintHelper$PrintHelperApi24",
+ "android/support/v4/content/res/FontResourcesParserCompat": "androidx/content/res/FontResourcesParserCompat",
+ "android/support/design/widget/SnackbarManager$SnackbarRecord": "androidx/design/widget/SnackbarManager$SnackbarRecord",
+ "android/support/v7/util/DiffUtil$Range": "androidx/util/DiffUtil$Range",
+ "android/support/v4/media/MediaBrowserCompat$MediaBrowserImpl": "androidx/media/MediaBrowserCompat$MediaBrowserImpl",
+ "android/support/v4/print/PrintHelper$PrintHelperApi20": "androidx/print/PrintHelper$PrintHelperApi20",
+ "android/support/v4/media/session/PlaybackStateCompat$RepeatMode": "androidx/media/session/PlaybackStateCompat$RepeatMode",
+ "android/support/v7/media/MediaRouteProviderProtocol": "androidx/media/MediaRouteProviderProtocol",
+ "android/support/transition/Transition$ArrayListManager": "androidx/transition/Transition$ArrayListManager",
+ "android/support/text/emoji/widget/EmojiButton": "androidx/text/emoji/widget/EmojiButton",
+ "android/support/v4/view/ActionProvider$VisibilityListener": "androidx/view/ActionProvider$VisibilityListener",
+ "android/support/v7/widget/AppCompatProgressBarHelper": "androidx/widget/AppCompatProgressBarHelper",
+ "android/support/v7/widget/LinearLayoutCompat": "androidx/widget/LinearLayoutCompat",
+ "android/support/v4/app/Fragment$OnStartEnterTransitionListener": "androidx/app/Fragment$OnStartEnterTransitionListener",
+ "android/support/v7/app/AppCompatDialogFragment": "androidx/app/AppCompatDialogFragment",
+ "android/support/graphics/drawable/Animatable2Compat": "androidx/graphics/drawable/Animatable2Compat",
+ "android/support/design/widget/TabLayout$PagerAdapterObserver": "androidx/design/widget/TabLayout$PagerAdapterObserver",
+ "android/support/v7/widget/StaggeredGridLayoutManager$LazySpanLookup$FullSpanItem": "androidx/widget/StaggeredGridLayoutManager$LazySpanLookup$FullSpanItem",
+ "android/support/v4/content/pm/ShortcutInfoCompat": "androidx/content/pm/ShortcutInfoCompat",
+ "android/support/v4/view/ScaleGestureDetectorCompat": "androidx/view/ScaleGestureDetectorCompat",
+ "android/support/v17/leanback/widget/ShadowHelperApi21$ShadowImpl": "androidx/leanback/widget/ShadowHelperApi21$ShadowImpl",
+ "android/support/v7/appcompat/R$id": "androidx/appcompat/R$id",
+ "android/support/v17/leanback/transition/Scale": "androidx/leanback/transition/Scale",
+ "android/support/v7/widget/ViewBoundsCheck": "androidx/widget/ViewBoundsCheck",
+ "android/support/design/widget/BottomSheetBehavior$State": "androidx/design/widget/BottomSheetBehavior$State",
+ "android/support/v7/app/ActionBarDrawerToggle$JellybeanMr2Delegate": "androidx/app/ActionBarDrawerToggle$JellybeanMr2Delegate",
+ "android/support/v7/internal/widget/PreferenceImageView": "androidx/internal/widget/PreferenceImageView",
+ "android/support/content/ContentPager$CursorCache": "androidx/content/ContentPager$CursorCache",
+ "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase$MessageHandler": "androidx/media/session/MediaSessionCompat$MediaSessionImplBase$MessageHandler",
+ "android/support/v4/app/NotificationCompat$Action$Extender": "androidx/app/NotificationCompat$Action$Extender",
+ "android/support/v7/widget/Toolbar$OnMenuItemClickListener": "androidx/widget/Toolbar$OnMenuItemClickListener",
+ "android/support/multidex/MultiDex$V4": "androidx/multidex/MultiDex$V4",
+ "android/support/v4/app/ActionBarDrawerToggle": "androidx/app/ActionBarDrawerToggle",
+ "android/support/v7/media/RemoteControlClientCompat": "androidx/media/RemoteControlClientCompat",
+ "android/support/v4/media/app/NotificationCompat$MediaStyle": "androidx/media/app/NotificationCompat$MediaStyle",
+ "android/support/v17/leanback/transition/TransitionEpicenterCallback": "androidx/leanback/transition/TransitionEpicenterCallback",
+ "android/support/v4/content/LocalBroadcastManager$ReceiverRecord": "androidx/content/LocalBroadcastManager$ReceiverRecord",
+ "android/support/v7/view/menu/BaseMenuPresenter": "androidx/view/menu/BaseMenuPresenter",
+ "android/support/v4/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListener": "androidx/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListener",
+ "android/support/design/widget/TabLayout$AdapterChangeListener": "androidx/design/widget/TabLayout$AdapterChangeListener",
+ "android/support/v7/widget/RecyclerView$RecyclerListener": "androidx/widget/RecyclerView$RecyclerListener",
+ "android/support/media/tv/ChannelLogoUtils": "androidx/media/tv/ChannelLogoUtils",
+ "android/support/v4/media/session/PlaybackStateCompat$CustomAction$Builder": "androidx/media/session/PlaybackStateCompat$CustomAction$Builder",
+ "android/support/v17/leanback/widget/GuidedActionAdapter": "androidx/leanback/widget/GuidedActionAdapter",
+ "android/support/v17/leanback/widget/ItemBridgeAdapter$Wrapper": "androidx/leanback/widget/ItemBridgeAdapter$Wrapper",
+ "android/support/v17/leanback/widget/DetailsOverviewRow$Listener": "androidx/leanback/widget/DetailsOverviewRow$Listener",
+ "android/support/annotation/InterpolatorRes": "androidx/annotation/InterpolatorRes",
+ "android/support/v4/widget/CursorAdapter$ChangeObserver": "androidx/widget/CursorAdapter$ChangeObserver",
+ "android/support/v4/widget/SimpleCursorAdapter$CursorToStringConverter": "androidx/widget/SimpleCursorAdapter$CursorToStringConverter",
+ "android/support/v7/widget/helper/ItemTouchUIUtilImpl$BaseImpl": "androidx/widget/helper/ItemTouchUIUtilImpl$BaseImpl",
+ "android/support/v4/provider/RawDocumentFile": "androidx/provider/RawDocumentFile",
+ "android/support/text/emoji/widget/EmojiExtractTextLayout$ButtonOnclickListener": "androidx/text/emoji/widget/EmojiExtractTextLayout$ButtonOnclickListener",
+ "android/support/v7/view/menu/MenuItemWrapperJB$ActionProviderWrapperJB": "androidx/view/menu/MenuItemWrapperJB$ActionProviderWrapperJB",
+ "android/support/media/tv/TvContractCompat$RecordedPrograms": "androidx/media/tv/TvContractCompat$RecordedPrograms",
+ "android/support/v17/leanback/widget/picker/Picker$PickerValueListener": "androidx/leanback/widget/picker/Picker$PickerValueListener",
+ "android/support/v4/media/session/IMediaControllerCallback$Stub": "androidx/media/session/IMediaControllerCallback$Stub",
+ "android/support/v7/preference/PreferenceManager": "androidx/preference/PreferenceManager",
+ "android/support/transition/GhostViewApi21$Creator": "androidx/transition/GhostViewApi21$Creator",
+ "android/support/v7/widget/ActionMenuView$ActionMenuChildView": "androidx/widget/ActionMenuView$ActionMenuChildView",
+ "android/support/v17/leanback/app/GuidedStepSupportFragment$DummyFragment": "androidx/leanback/app/GuidedStepSupportFragment$DummyFragment",
+ "android/support/v4/app/BaseFragmentActivityApi14": "androidx/app/BaseFragmentActivityApi14",
+ "android/support/v14/preference/SwitchPreference": "androidx/preference/SwitchPreference",
+ "android/support/v4/app/BaseFragmentActivityApi16": "androidx/app/BaseFragmentActivityApi16",
+ "android/support/v7/preference/PreferenceFragmentCompat$ScrollToPreferenceObserver": "androidx/preference/PreferenceFragmentCompat$ScrollToPreferenceObserver",
+ "android/support/v4/graphics/PaintCompat": "androidx/graphics/PaintCompat",
+ "android/support/v4/media/AudioAttributesCompat": "androidx/media/AudioAttributesCompat",
+ "android/support/v4/media/session/MediaSessionCompat$QueueItem": "androidx/media/session/MediaSessionCompat$QueueItem",
+ "android/support/transition/Transition$AnimationInfo": "androidx/transition/Transition$AnimationInfo",
+ "android/support/v7/app/MediaRouteControllerDialog$VolumeChangeListener": "androidx/app/MediaRouteControllerDialog$VolumeChangeListener",
+ "android/support/v4/widget/DrawerLayout$ViewDragCallback": "androidx/widget/DrawerLayout$ViewDragCallback",
+ "android/support/design/widget/FloatingActionButtonImpl$ResetElevationAnimation": "androidx/design/widget/FloatingActionButtonImpl$ResetElevationAnimation",
+ "android/support/design/widget/TabLayout$OnTabSelectedListener": "androidx/design/widget/TabLayout$OnTabSelectedListener",
+ "android/support/annotation/VisibleForTesting": "androidx/annotation/VisibleForTesting",
+ "android/support/v4/app/NotificationCompatSideChannelService$NotificationSideChannelStub": "androidx/app/NotificationCompatSideChannelService$NotificationSideChannelStub",
+ "android/support/annotation/RawRes": "androidx/annotation/RawRes",
+ "android/support/design/R$anim": "androidx/design/R$anim",
+ "android/support/transition/Transition$MatchOrder": "androidx/transition/Transition$MatchOrder",
+ "android/support/v7/widget/RecyclerView$SimpleOnItemTouchListener": "androidx/widget/RecyclerView$SimpleOnItemTouchListener",
+ "android/support/transition/AnimatorUtilsImpl": "androidx/transition/AnimatorUtilsImpl",
+ "android/support/v4/view/OnApplyWindowInsetsListener": "androidx/view/OnApplyWindowInsetsListener",
+ "android/support/wear/widget/SwipeDismissLayout": "androidx/wear/widget/SwipeDismissLayout",
+ "android/support/mediacompat/R$color": "androidx/mediacompat/R$color",
+ "android/support/v7/preference/PreferenceManager$PreferenceComparisonCallback": "androidx/preference/PreferenceManager$PreferenceComparisonCallback",
+ "android/support/v7/widget/ActionMenuView$OnMenuItemClickListener": "androidx/widget/ActionMenuView$OnMenuItemClickListener",
+ "android/support/v7/widget/TooltipCompat$BaseViewCompatImpl": "androidx/widget/TooltipCompat$BaseViewCompatImpl",
+ "android/support/wear/widget/drawer/WearableNavigationDrawerView$NavigationStyle": "androidx/wear/widget/drawer/WearableNavigationDrawerView$NavigationStyle",
+ "android/support/transition/PatternPathMotion": "androidx/transition/PatternPathMotion",
+ "android/support/v7/palette/BuildConfig": "androidx/palette/BuildConfig",
+ "android/support/transition/Styleable$TransitionTarget": "androidx/transition/Styleable$TransitionTarget",
+ "android/support/mediacompat/R": "androidx/mediacompat/R",
+ "android/support/v7/media/MediaRouterJellybeanMr1$Callback": "androidx/media/MediaRouterJellybeanMr1$Callback",
+ "android/support/v17/leanback/widget/ControlBarPresenter$OnControlClickedListener": "androidx/leanback/widget/ControlBarPresenter$OnControlClickedListener",
+ "android/support/v4/view/LayoutInflaterCompat$Factory2Wrapper": "androidx/view/LayoutInflaterCompat$Factory2Wrapper",
+ "android/support/v7/widget/GridLayoutManager$LayoutParams": "androidx/widget/GridLayoutManager$LayoutParams",
+ "android/support/v7/widget/GridLayout": "androidx/widget/GridLayout",
+ "android/support/v4/media/MediaBrowserServiceCompat$ServiceBinderImpl": "androidx/media/MediaBrowserServiceCompat$ServiceBinderImpl",
+ "android/support/v7/widget/AppCompatCheckBox": "androidx/widget/AppCompatCheckBox",
+ "android/support/v4/view/GestureDetectorCompat$GestureDetectorCompatImpl": "androidx/view/GestureDetectorCompat$GestureDetectorCompatImpl",
+ "android/support/v17/preference/BaseLeanbackPreferenceFragment": "androidx/leanback/preference/BaseLeanbackPreferenceFragment",
+ "android/support/v17/leanback/app/GuidedStepRootLayout": "androidx/leanback/app/GuidedStepRootLayout",
+ "android/support/v4/app/FragmentManager$FragmentLifecycleCallbacks": "androidx/app/FragmentManager$FragmentLifecycleCallbacks",
+ "android/support/v4/media/MediaMetadataCompatApi21": "androidx/media/MediaMetadataCompatApi21",
+ "android/support/v7/app/MediaRouterThemeHelper": "androidx/app/MediaRouterThemeHelper",
+ "android/support/v4/util/MapCollections$EntrySet": "androidx/util/MapCollections$EntrySet",
+ "android/support/v7/widget/ViewBoundsCheck$ViewBounds": "androidx/widget/ViewBoundsCheck$ViewBounds",
+ "android/support/design/widget/HeaderScrollingViewBehavior": "androidx/design/widget/HeaderScrollingViewBehavior",
+ "android/support/v7/app/ActionBarDrawerToggle$IcsDelegate": "androidx/app/ActionBarDrawerToggle$IcsDelegate",
+ "android/support/v4/media/session/ParcelableVolumeInfo": "androidx/media/session/ParcelableVolumeInfo",
+ "android/support/v17/leanback/widget/GuidedAction$Builder": "androidx/leanback/widget/GuidedAction$Builder",
+ "android/support/v7/view/menu/CascadingMenuPopup": "androidx/view/menu/CascadingMenuPopup",
+ "android/support/v7/view/menu/MenuPopup": "androidx/view/menu/MenuPopup",
+ "android/support/v7/app/AlertDialog": "androidx/app/AlertDialog",
+ "android/support/v7/widget/RecyclerView$SavedState": "androidx/widget/RecyclerView$SavedState",
+ "android/support/wear/widget/drawer/WearableActionDrawerView$TitleViewHolder": "androidx/wear/widget/drawer/WearableActionDrawerView$TitleViewHolder",
+ "android/support/v13/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatBaseImpl": "androidx/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatBaseImpl",
+ "android/support/v17/leanback/app/VideoSupportFragmentGlueHost": "androidx/leanback/app/VideoSupportFragmentGlueHost",
+ "android/support/text/emoji/EmojiProcessor": "androidx/text/emoji/EmojiProcessor",
+ "android/support/v17/leanback/widget/ActionPresenterSelector": "androidx/leanback/widget/ActionPresenterSelector",
+ "android/support/v13/view/inputmethod/EditorInfoCompat$EditorInfoCompatImpl": "androidx/view/inputmethod/EditorInfoCompat$EditorInfoCompatImpl",
+ "android/support/text/emoji/widget/EmojiExtractTextLayout": "androidx/text/emoji/widget/EmojiExtractTextLayout",
+ "android/support/v17/leanback/widget/GuidedAction": "androidx/leanback/widget/GuidedAction",
+ "android/support/v17/leanback/util/StateMachine$Condition": "androidx/leanback/util/StateMachine$Condition",
+ "android/support/text/emoji/flatbuffer/Table": "androidx/text/emoji/flatbuffer/Table",
+ "android/support/v4/os/OperationCanceledException": "androidx/os/OperationCanceledException",
+ "android/support/v7/media/RegisteredMediaRouteProvider$PrivateHandler": "androidx/media/RegisteredMediaRouteProvider$PrivateHandler",
+ "android/support/v7/widget/RecyclerView$Adapter": "androidx/widget/RecyclerView$Adapter",
+ "android/support/v13/BuildConfig": "androidx/BuildConfig",
+ "android/support/v7/util/ListUpdateCallback": "androidx/util/ListUpdateCallback",
+ "android/support/v4/media/MediaDescriptionCompatApi21": "androidx/media/MediaDescriptionCompatApi21",
+ "android/support/v4/view/ViewCompat$FocusRealDirection": "androidx/view/ViewCompat$FocusRealDirection",
+ "android/support/v4/media/session/MediaControllerCompat$Callback": "androidx/media/session/MediaControllerCompat$Callback",
+ "android/support/v4/media/MediaDescriptionCompatApi23": "androidx/media/MediaDescriptionCompatApi23",
+ "android/support/v4/view/accessibility/AccessibilityEventCompat": "androidx/view/accessibility/AccessibilityEventCompat",
+ "android/support/text/emoji/FontRequestEmojiCompatConfig$FontProviderHelper": "androidx/text/emoji/FontRequestEmojiCompatConfig$FontProviderHelper",
+ "android/support/v4/app/NotificationCompat$Action$Builder": "androidx/app/NotificationCompat$Action$Builder",
+ "android/support/v4/view/accessibility/AccessibilityNodeProviderCompat$AccessibilityNodeProviderApi16": "androidx/view/accessibility/AccessibilityNodeProviderCompat$AccessibilityNodeProviderApi16",
+ "android/support/annotation/AnimatorRes": "androidx/annotation/AnimatorRes",
+ "android/support/v17/leanback/widget/GuidanceStylist": "androidx/leanback/widget/GuidanceStylist",
+ "android/support/v17/leanback/widget/StaticShadowHelper$ShadowHelperStubImpl": "androidx/leanback/widget/StaticShadowHelper$ShadowHelperStubImpl",
+ "android/support/v4/view/accessibility/AccessibilityNodeProviderCompat$AccessibilityNodeProviderApi19": "androidx/view/accessibility/AccessibilityNodeProviderCompat$AccessibilityNodeProviderApi19",
+ "android/support/v7/util/ThreadUtil": "androidx/util/ThreadUtil",
+ "android/support/content/InMemoryCursor$ObserverRelay": "androidx/content/InMemoryCursor$ObserverRelay",
+ "android/support/wear/R$drawable": "androidx/wear/R$drawable",
+ "android/support/constraint/ConstraintLayout$LayoutParams": "androidx/constraint/ConstraintLayout$LayoutParams",
+ "android/support/v7/widget/StaggeredGridLayoutManager$LazySpanLookup": "androidx/widget/StaggeredGridLayoutManager$LazySpanLookup",
+ "android/support/transition/BuildConfig": "androidx/transition/BuildConfig",
+ "android/support/v17/leanback/app/SearchFragment$ExternalQuery": "androidx/leanback/app/SearchFragment$ExternalQuery",
+ "android/support/media/tv/TvContractCompat$Programs$Genres": "androidx/media/tv/TvContractCompat$Programs$Genres",
+ "android/support/v13/view/inputmethod/InputConnectionCompat$OnCommitContentListener": "androidx/view/inputmethod/InputConnectionCompat$OnCommitContentListener",
+ "android/support/content/ContentPager$CursorDisposition": "androidx/content/ContentPager$CursorDisposition",
+ "android/support/v4/view/AsyncLayoutInflater$OnInflateFinishedListener": "androidx/view/AsyncLayoutInflater$OnInflateFinishedListener",
+ "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplBase": "androidx/media/session/MediaControllerCompat$MediaControllerImplBase",
+ "android/support/v4/util/PatternsCompat": "androidx/util/PatternsCompat",
+ "android/support/v4/media/MediaBrowserServiceCompat$ServiceCallbacksCompat": "androidx/media/MediaBrowserServiceCompat$ServiceCallbacksCompat",
+ "android/support/v7/widget/AppCompatCompoundButtonHelper$DirectSetButtonDrawableInterface": "androidx/widget/AppCompatCompoundButtonHelper$DirectSetButtonDrawableInterface",
+ "android/support/v17/leanback/media/PlaybackGlueHost": "androidx/leanback/media/PlaybackGlueHost",
+ "android/support/v4/content/ModernAsyncTask": "androidx/content/ModernAsyncTask",
+ "android/support/v4/view/ViewCompat$ViewCompatApi15Impl": "androidx/view/ViewCompat$ViewCompatApi15Impl",
+ "android/support/v4/os/ResultReceiver$MyResultReceiver": "androidx/os/ResultReceiver$MyResultReceiver",
+ "android/support/v7/widget/helper/ItemTouchHelper$Callback": "androidx/widget/helper/ItemTouchHelper$Callback",
+ "android/support/v17/leanback/app/BrowseFragment$MainFragmentRowsAdapterProvider": "androidx/leanback/app/BrowseFragment$MainFragmentRowsAdapterProvider",
+ "android/support/annotation/Nullable": "androidx/annotation/Nullable",
+ "android/support/v4/os/IResultReceiver$Stub": "androidx/os/IResultReceiver$Stub",
+ "android/support/v7/widget/Toolbar$ExpandedActionViewMenuPresenter": "androidx/widget/Toolbar$ExpandedActionViewMenuPresenter",
+ "android/support/v17/leanback/widget/picker/PickerUtility": "androidx/leanback/widget/picker/PickerUtility",
+ "android/support/v4/view/ViewPager$MyAccessibilityDelegate": "androidx/view/ViewPager$MyAccessibilityDelegate",
+ "android/support/v4/app/FragmentTransaction$Transit": "androidx/app/FragmentTransaction$Transit",
+ "android/support/v7/widget/DefaultItemAnimator": "androidx/widget/DefaultItemAnimator",
+ "android/support/v4/view/PagerAdapter": "androidx/widget/PagerAdapter",
+ "android/support/v7/media/MediaRouteProviderService$PrivateHandler": "androidx/media/MediaRouteProviderService$PrivateHandler",
+ "android/support/v4/media/session/IMediaControllerCallback$Stub$Proxy": "androidx/media/session/IMediaControllerCallback$Stub$Proxy",
+ "android/support/v4/media/RatingCompat": "androidx/media/RatingCompat",
+ "android/support/v7/widget/GridLayout$Assoc": "androidx/widget/GridLayout$Assoc",
+ "android/support/v17/leanback/app/DetailsSupportFragment$SetSelectionRunnable": "androidx/leanback/app/DetailsSupportFragment$SetSelectionRunnable",
+ "android/support/v7/util/DiffUtil$Callback": "androidx/util/DiffUtil$Callback",
+ "android/support/v7/widget/ActivityChooserModel$ActivityChooserModelClient": "androidx/widget/ActivityChooserModel$ActivityChooserModelClient",
+ "android/support/v7/widget/PagerSnapHelper": "androidx/widget/PagerSnapHelper",
+ "android/support/v17/leanback/widget/GridLayoutManager$LayoutParams": "androidx/leanback/widget/GridLayoutManager$LayoutParams",
+ "android/support/percent/R": "androidx/R",
+ "android/support/transition/Styleable$Fade": "androidx/transition/Styleable$Fade",
+ "android/support/design/widget/FloatingActionButtonLollipop": "androidx/design/widget/FloatingActionButtonLollipop",
+ "android/support/v17/leanback/widget/ActionPresenterSelector$OneLineActionPresenter": "androidx/leanback/widget/ActionPresenterSelector$OneLineActionPresenter",
+ "android/support/transition/ViewUtilsApi22": "androidx/transition/ViewUtilsApi22",
+ "android/support/v7/widget/LinearLayoutCompat$LayoutParams": "androidx/widget/LinearLayoutCompat$LayoutParams",
+ "android/support/transition/ViewUtilsApi21": "androidx/transition/ViewUtilsApi21",
+ "android/support/v17/leanback/app/BrandedFragment": "androidx/leanback/app/BrandedFragment",
+ "android/support/text/emoji/bundled/BundledEmojiCompatConfig$BundledMetadataLoader": "androidx/text/emoji/bundled/BundledEmojiCompatConfig$BundledMetadataLoader",
+ "android/support/v17/preference/R": "androidx/leanback/preference/R",
+ "android/support/v4/content/res/TypedArrayUtils": "androidx/content/res/TypedArrayUtils",
+ "android/support/v7/app/ActionBar$LayoutParams": "androidx/app/ActionBar$LayoutParams",
+ "android/support/transition/Visibility$DisappearListener": "androidx/transition/Visibility$DisappearListener",
+ "android/support/v7/view/menu/MenuView$ItemView": "androidx/view/menu/MenuView$ItemView",
+ "android/support/text/emoji/flatbuffer/FlatBufferBuilder": "androidx/text/emoji/flatbuffer/FlatBufferBuilder",
+ "android/support/v17/leanback/app/BaseRowFragment$LateSelectionObserver": "androidx/leanback/app/BaseRowFragment$LateSelectionObserver",
+ "android/support/wear/widget/SwipeDismissFrameLayout$MyOnSwipeProgressChangedListener": "androidx/wear/widget/SwipeDismissFrameLayout$MyOnSwipeProgressChangedListener",
+ "android/support/v4/content/PermissionChecker$PermissionResult": "androidx/content/PermissionChecker$PermissionResult",
+ "android/support/v7/media/MediaRouter$ControlRequestCallback": "androidx/media/MediaRouter$ControlRequestCallback",
+ "android/support/wear/widget/drawer/WearableNavigationDrawerView$WearableNavigationDrawerAdapter": "androidx/wear/widget/drawer/WearableNavigationDrawerView$WearableNavigationDrawerAdapter",
+ "android/support/v13/view/inputmethod/InputContentInfoCompat": "androidx/view/inputmethod/InputContentInfoCompat",
+ "android/support/transition/ViewUtilsApi19": "androidx/transition/ViewUtilsApi19",
+ "android/support/transition/ViewUtilsApi18": "androidx/transition/ViewUtilsApi18",
+ "android/support/v7/widget/AppCompatDrawableManager$InflateDelegate": "androidx/widget/AppCompatDrawableManager$InflateDelegate",
+ "android/support/v7/preference/R$styleable": "androidx/preference/R$styleable",
+ "android/support/v13/view/DragAndDropPermissionsCompat": "androidx/view/DragAndDropPermissionsCompat",
+ "android/support/v4/content/res/FontResourcesParserCompat$FontFamilyFilesResourceEntry": "androidx/content/res/FontResourcesParserCompat$FontFamilyFilesResourceEntry",
+ "android/support/transition/ViewUtilsApi14": "androidx/transition/ViewUtilsApi14",
+ "android/support/v7/view/menu/MenuItemWrapperICS": "androidx/view/menu/MenuItemWrapperICS",
+ "android/support/design/widget/CollapsingToolbarLayout": "androidx/design/widget/CollapsingToolbarLayout",
+ "android/support/dynamicanimation/BuildConfig": "androidx/dynamicanimation/BuildConfig",
+ "android/support/v4/util/ArrayMap": "androidx/util/ArrayMap",
+ "android/support/v17/leanback/widget/ParallaxTarget$PropertyValuesHolderTarget": "androidx/leanback/widget/ParallaxTarget$PropertyValuesHolderTarget",
+ "android/support/wear/widget/drawer/WearableActionDrawerView$ActionListAdapter": "androidx/wear/widget/drawer/WearableActionDrawerView$ActionListAdapter",
+ "android/support/v4/media/MediaBrowserCompat$MediaBrowserServiceCallbackImpl": "androidx/media/MediaBrowserCompat$MediaBrowserServiceCallbackImpl",
+ "android/support/wear/widget/SimpleAnimatorListener": "androidx/wear/widget/SimpleAnimatorListener",
+ "android/support/v17/leanback/widget/FacetProviderAdapter": "androidx/leanback/widget/FacetProviderAdapter",
+ "android/support/v4/widget/SlidingPaneLayout$SlidingPanelLayoutImplJBMR1": "androidx/widget/SlidingPaneLayout$SlidingPanelLayoutImplJBMR1",
+ "android/support/v7/widget/SearchView": "androidx/widget/SearchView",
+ "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase$MediaSessionStub": "androidx/media/session/MediaSessionCompat$MediaSessionImplBase$MediaSessionStub",
+ "android/support/v7/widget/TooltipCompat$ViewCompatImpl": "androidx/widget/TooltipCompat$ViewCompatImpl",
+ "android/support/v13/view/DragAndDropPermissionsCompat$DragAndDropPermissionsCompatImpl": "androidx/view/DragAndDropPermissionsCompat$DragAndDropPermissionsCompatImpl",
+ "android/support/customtabs/IPostMessageService$Stub$Proxy": "androidx/browser/customtabs/IPostMessageService$Stub$Proxy",
+ "android/support/v17/leanback/widget/ItemAlignment$Axis": "androidx/leanback/widget/ItemAlignment$Axis",
+ "android/support/v7/widget/RecyclerView$ViewHolder": "androidx/widget/RecyclerView$ViewHolder",
+ "android/support/v7/widget/GapWorker": "androidx/widget/GapWorker",
+ "android/support/v7/media/MediaItemStatus": "androidx/media/MediaItemStatus",
+ "android/support/transition/Explode": "androidx/transition/Explode",
+ "android/support/v17/leanback/widget/GuidedActionAdapter$ActionEditListener": "androidx/leanback/widget/GuidedActionAdapter$ActionEditListener",
+ "android/support/v4/text/BidiFormatter": "androidx/text/BidiFormatter",
+ "android/support/v7/widget/CardViewApi17Impl": "androidx/widget/CardViewApi17Impl",
+ "android/support/v7/media/MediaRouter$RouteInfo$PlaybackType": "androidx/media/MediaRouter$RouteInfo$PlaybackType",
+ "android/support/v4/view/ViewGroupCompat$ViewGroupCompatBaseImpl": "androidx/view/ViewGroupCompat$ViewGroupCompatBaseImpl",
+ "android/support/v4/view/ViewParentCompat$ViewParentCompatApi21Impl": "androidx/view/ViewParentCompat$ViewParentCompatApi21Impl",
+ "android/support/v7/widget/StaggeredGridLayoutManager": "androidx/widget/StaggeredGridLayoutManager",
+ "android/support/v4/widget/FocusStrategy": "androidx/widget/FocusStrategy",
+ "android/support/customtabs/ICustomTabsCallback$Stub$Proxy": "androidx/browser/customtabs/ICustomTabsCallback$Stub$Proxy",
+ "android/support/v7/media/MediaRouteProvider": "androidx/media/MediaRouteProvider",
+ "android/support/v4/net/DatagramSocketWrapper": "androidx/net/DatagramSocketWrapper",
+ "android/support/design/widget/SnackbarManager": "androidx/design/widget/SnackbarManager",
+ "android/support/v17/leanback/media/MediaControllerGlue": "androidx/leanback/media/MediaControllerGlue",
+ "android/support/v7/widget/PopupMenu$OnMenuItemClickListener": "androidx/widget/PopupMenu$OnMenuItemClickListener",
+ "android/support/v7/widget/helper/ItemTouchUIUtilImpl$Api21Impl": "androidx/widget/helper/ItemTouchUIUtilImpl$Api21Impl",
+ "android/support/text/emoji/widget/EmojiTextViewHelper": "androidx/text/emoji/widget/EmojiTextViewHelper",
+ "android/support/v4/media/session/MediaSessionCompat$Callback": "androidx/media/session/MediaSessionCompat$Callback",
+ "android/support/design/internal/NavigationMenuPresenter$NavigationMenuTextItem": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuTextItem",
+ "android/support/v13/app/FragmentCompat$OnRequestPermissionsResultCallback": "androidx/app/FragmentCompat$OnRequestPermissionsResultCallback",
+ "android/support/design/widget/AppBarLayout$Behavior$DragCallback": "androidx/design/widget/AppBarLayout$Behavior$DragCallback",
+ "android/support/text/emoji/widget/EmojiEditTextHelper": "androidx/text/emoji/widget/EmojiEditTextHelper",
+ "android/support/v7/widget/AppCompatTextHelperV17": "androidx/widget/AppCompatTextHelperV17",
+ "android/support/v4/widget/SimpleCursorAdapter": "androidx/widget/SimpleCursorAdapter",
+ "android/support/mediacompat/R$integer": "androidx/mediacompat/R$integer",
+ "android/support/v17/leanback/widget/Grid$Provider": "androidx/leanback/widget/Grid$Provider",
+ "android/support/v13/view/ViewCompat": "androidx/view/ViewCompat",
+ "android/support/v14/preference/MultiSelectListPreference$SavedState": "androidx/preference/MultiSelectListPreference$SavedState",
+ "android/support/v4/view/NestedScrollingChild": "androidx/view/NestedScrollingChild",
+ "android/support/v7/preference/R$layout": "androidx/preference/R$layout",
+ "android/support/v4/app/FragmentTransition": "androidx/app/FragmentTransition",
+ "android/support/v4/app/NotificationCompat$Action$WearableExtender": "androidx/app/NotificationCompat$Action$WearableExtender",
+ "android/support/v17/preference/LeanbackPreferenceDialogFragment": "androidx/leanback/preference/LeanbackPreferenceDialogFragment",
+ "android/support/annotation/WorkerThread": "androidx/annotation/WorkerThread",
+ "android/support/v7/app/MediaRouteDialogFactory": "androidx/app/MediaRouteDialogFactory",
+ "android/support/v7/view/ActionMode": "androidx/view/ActionMode",
+ "android/support/v4/provider/FontsContractCompat$FontRequestCallback$FontRequestFailReason": "androidx/provider/FontsContractCompat$FontRequestCallback$FontRequestFailReason",
+ "android/support/v17/leanback/R$drawable": "androidx/leanback/R$drawable",
+ "android/support/annotation/StringRes": "androidx/annotation/StringRes",
+ "android/support/v4/app/RemoteInputCompatBase$RemoteInput": "androidx/app/RemoteInputCompatBase$RemoteInput",
+ "android/support/v13/app/FragmentTabHost$TabInfo": "androidx/app/FragmentTabHost$TabInfo",
+ "android/support/v7/app/ActionBarDrawerToggle$ToolbarCompatDelegate": "androidx/app/ActionBarDrawerToggle$ToolbarCompatDelegate",
+ "android/support/v7/widget/PopupMenu$OnDismissListener": "androidx/widget/PopupMenu$OnDismissListener",
+ "android/support/transition/AnimatorUtilsApi14$AnimatorPauseListenerCompat": "androidx/transition/AnimatorUtilsApi14$AnimatorPauseListenerCompat",
+ "android/support/v4/app/JobIntentService$CommandProcessor": "androidx/app/JobIntentService$CommandProcessor",
+ "android/support/v17/leanback/widget/VerticalGridView": "androidx/leanback/widget/VerticalGridView",
+ "android/support/v4/app/FragmentManager": "androidx/app/FragmentManager",
+ "android/support/v4/app/BackStackState": "androidx/app/BackStackState",
+ "android/support/text/emoji/R": "androidx/text/emoji/R",
+ "android/support/v4/media/session/MediaSessionCompatApi21$Callback": "androidx/media/session/MediaSessionCompatApi21$Callback",
+ "android/support/transition/ChangeScroll": "androidx/transition/ChangeScroll",
+ "android/support/v4/view/ViewCompat$LayoutDirectionMode": "androidx/view/ViewCompat$LayoutDirectionMode",
+ "android/support/v7/widget/AdapterHelper$Callback": "androidx/widget/AdapterHelper$Callback",
+ "android/support/wear/R$layout": "androidx/wear/R$layout",
+ "android/support/v17/leanback/widget/GuidedActionAdapter$ClickListener": "androidx/leanback/widget/GuidedActionAdapter$ClickListener",
+ "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi21$ExtraCallback": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi21$ExtraCallback",
+ "android/support/customtabs/ICustomTabsService$Stub": "androidx/browser/customtabs/ICustomTabsService$Stub",
+ "android/support/v17/leanback/widget/ListRowView": "androidx/leanback/widget/ListRowView",
+ "android/support/v7/widget/ActivityChooserView": "androidx/widget/ActivityChooserView",
+ "android/support/v4/os/TraceCompat": "androidx/os/TraceCompat",
+ "android/support/transition/ImageViewUtils": "androidx/transition/ImageViewUtils",
+ "android/support/v4/app/FragmentManager$OnBackStackChangedListener": "androidx/app/FragmentManager$OnBackStackChangedListener",
+ "android/support/v7/app/AppCompatDelegateImplV23$AppCompatWindowCallbackV23": "androidx/app/AppCompatDelegateImplV23$AppCompatWindowCallbackV23",
+ "android/support/transition/GhostViewApi14": "androidx/transition/GhostViewApi14",
+ "android/support/design/widget/SwipeDismissBehavior$SwipeDirection": "androidx/design/widget/SwipeDismissBehavior$SwipeDirection",
+ "android/support/v17/leanback/widget/SearchOrbView": "androidx/leanback/widget/SearchOrbView",
+ "android/support/v4/app/NotificationManagerCompat$NotifyTask": "androidx/app/NotificationManagerCompat$NotifyTask",
+ "android/support/v4/util/LruCache": "androidx/util/LruCache",
+ "android/support/v7/widget/ActionMenuView$LayoutParams": "androidx/widget/ActionMenuView$LayoutParams",
+ "android/support/v7/widget/helper/ItemTouchHelper$ViewDropHandler": "androidx/widget/helper/ItemTouchHelper$ViewDropHandler",
+ "android/support/v7/content/res/AppCompatColorStateListInflater": "androidx/content/res/AppCompatColorStateListInflater",
+ "android/support/v7/widget/ActionMenuPresenter$OpenOverflowRunnable": "androidx/widget/ActionMenuPresenter$OpenOverflowRunnable",
+ "android/support/v7/media/MediaRouter$GlobalMediaRouter$CallbackHandler": "androidx/media/MediaRouter$GlobalMediaRouter$CallbackHandler",
+ "android/support/design/widget/AppBarLayout$Behavior": "androidx/design/widget/AppBarLayout$Behavior",
+ "android/support/v4/widget/ExploreByTouchHelper": "androidx/widget/ExploreByTouchHelper",
+ "android/support/transition/PropertyValuesHolderUtilsImpl": "androidx/transition/PropertyValuesHolderUtilsImpl",
+ "android/support/v14/preference/PreferenceDialogFragment": "androidx/preference/PreferenceDialogFragment",
+ "android/support/transition/GhostViewApi21": "androidx/transition/GhostViewApi21",
+ "android/support/text/emoji/MetadataListReader$InputStreamOpenTypeReader": "androidx/text/emoji/MetadataListReader$InputStreamOpenTypeReader",
+ "android/support/transition/RectEvaluator": "androidx/transition/RectEvaluator",
+ "android/support/v7/preference/BuildConfig": "androidx/preference/BuildConfig",
+ "android/support/v4/view/VelocityTrackerCompat": "androidx/view/VelocityTrackerCompat",
+ "android/support/v7/widget/AppCompatAutoCompleteTextView": "androidx/widget/AppCompatAutoCompleteTextView",
+ "android/support/v7/media/MediaRouterJellybean$VolumeCallback": "androidx/media/MediaRouterJellybean$VolumeCallback",
+ "android/support/media/tv/WatchNextProgram": "androidx/media/tv/WatchNextProgram",
+ "android/support/wear/internal/widget/drawer/MultiPageUi$NavigationPagerAdapter": "androidx/wear/internal/widget/drawer/MultiPageUi$NavigationPagerAdapter",
+ "android/support/v4/widget/ExploreByTouchHelper$MyNodeProvider": "androidx/widget/ExploreByTouchHelper$MyNodeProvider",
+ "android/support/v7/widget/RecyclerView$AdapterDataObserver": "androidx/widget/RecyclerView$AdapterDataObserver",
+ "android/support/v4/media/session/IMediaSession": "androidx/media/session/IMediaSession",
+ "android/support/v17/preference/LeanbackSettingsRootView": "androidx/leanback/preference/LeanbackSettingsRootView",
+ "android/support/v7/widget/AppCompatButton": "androidx/widget/AppCompatButton",
+ "android/support/constraint/solver/widgets/ConstraintWidget$DimensionBehaviour": "androidx/constraint/solver/widgets/ConstraintWidget$DimensionBehaviour",
+ "android/support/graphics/drawable/AnimatedVectorDrawableCompat$AnimatedVectorDrawableDelegateState": "androidx/graphics/drawable/AnimatedVectorDrawableCompat$AnimatedVectorDrawableDelegateState",
+ "android/support/v17/leanback/app/DetailsSupportFragmentBackgroundController": "androidx/leanback/app/DetailsSupportFragmentBackgroundController",
+ "android/support/v17/leanback/widget/ThumbsBar": "androidx/leanback/widget/ThumbsBar",
+ "android/support/v4/media/session/MediaSessionCompat$Token": "androidx/media/session/MediaSessionCompat$Token",
+ "android/support/v7/mediarouter/R$integer": "androidx/mediarouter/R$integer",
+ "android/support/v7/app/WindowDecorActionBar": "androidx/app/WindowDecorActionBar",
+ "android/support/v4/app/Fragment$SavedState": "androidx/app/Fragment$SavedState",
+ "android/support/v17/leanback/widget/StaggeredGrid$Location": "androidx/leanback/widget/StaggeredGrid$Location",
+ "android/support/v17/leanback/widget/DiffCallback": "androidx/leanback/widget/DiffCallback",
+ "android/support/v4/os/ParcelableCompat": "androidx/os/ParcelableCompat",
+ "android/support/transition/ViewGroupUtils": "androidx/transition/ViewGroupUtils",
+ "android/support/v7/media/MediaRouter$GlobalMediaRouter$MediaSessionRecord": "androidx/media/MediaRouter$GlobalMediaRouter$MediaSessionRecord",
+ "android/support/v7/widget/ViewBoundsCheck$BoundFlags": "androidx/widget/ViewBoundsCheck$BoundFlags",
+ "android/support/wear/R": "androidx/wear/R",
+ "android/support/v17/leanback/app/DetailsSupportFragment$WaitEnterTransitionTimeout": "androidx/leanback/app/DetailsSupportFragment$WaitEnterTransitionTimeout",
+ "android/support/v4/widget/ViewDragHelper$Callback": "androidx/widget/ViewDragHelper$Callback",
+ "android/support/v7/widget/DropDownListView": "androidx/widget/DropDownListView",
+ "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperVersionImpl": "androidx/leanback/transition/TransitionHelper$TransitionHelperVersionImpl",
+ "android/support/transition/TransitionUtils$MatrixEvaluator": "androidx/transition/TransitionUtils$MatrixEvaluator",
+ "android/support/v4/hardware/display/DisplayManagerCompat": "androidx/hardware/display/DisplayManagerCompat",
+ "android/support/media/tv/TvContractCompat$Channels$VideoResolution": "androidx/media/tv/TvContractCompat$Channels$VideoResolution",
+ "android/support/v4/app/NotificationCompatBuilder": "androidx/app/NotificationCompatBuilder",
+ "android/support/v4/media/session/MediaControllerCompat$TransportControls": "androidx/media/session/MediaControllerCompat$TransportControls",
+ "android/support/v7/view/menu/SubMenuBuilder": "androidx/view/menu/SubMenuBuilder",
+ "android/support/v4/media/session/MediaSessionCompatApi23$CallbackProxy": "androidx/media/session/MediaSessionCompatApi23$CallbackProxy",
+ "android/support/v7/recyclerview/R$id": "androidx/recyclerview/R$id",
+ "android/support/wear/widget/WearableLinearLayoutManager$LayoutCallback": "androidx/wear/widget/WearableLinearLayoutManager$LayoutCallback",
+ "android/support/v17/leanback/widget/PresenterSelector": "androidx/leanback/widget/PresenterSelector",
+ "android/support/v4/app/JobIntentService$JobServiceEngineImpl": "androidx/app/JobIntentService$JobServiceEngineImpl",
+ "android/support/v4/app/ActionBarDrawerToggle$DelegateProvider": "androidx/app/ActionBarDrawerToggle$DelegateProvider",
+ "android/support/v17/leanback/widget/GuidedActionsRelativeLayout": "androidx/leanback/widget/GuidedActionsRelativeLayout",
+ "android/support/v7/widget/RecyclerView$LayoutManager": "androidx/widget/RecyclerView$LayoutManager",
+ "android/support/v4/print/PrintHelper": "androidx/print/PrintHelper",
+ "android/support/v7/util/AsyncListUtil": "androidx/util/AsyncListUtil",
+ "android/support/transition/TransitionListenerAdapter": "androidx/transition/TransitionListenerAdapter",
+ "android/support/v7/view/menu/MenuItemWrapperICS$ActionProviderWrapper": "androidx/view/menu/MenuItemWrapperICS$ActionProviderWrapper",
+ "android/support/v7/app/TwilightManager": "androidx/app/TwilightManager",
+ "android/support/v17/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperDefault": "androidx/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperDefault",
+ "android/support/v4/app/NotificationCompat$InboxStyle": "androidx/app/NotificationCompat$InboxStyle",
+ "android/support/v14/preference/MultiSelectListPreference": "androidx/preference/MultiSelectListPreference",
+ "android/support/v13/view/inputmethod/EditorInfoCompat$EditorInfoCompatBaseImpl": "androidx/view/inputmethod/EditorInfoCompat$EditorInfoCompatBaseImpl",
+ "android/support/v7/preference/SeekBarPreference$SavedState": "androidx/preference/SeekBarPreference$SavedState",
+ "android/support/v17/leanback/widget/PlaybackControlsRowPresenter$BoundData": "androidx/leanback/widget/PlaybackControlsRowPresenter$BoundData",
+ "android/support/customtabs/CustomTabsSessionToken": "androidx/browser/customtabs/CustomTabsSessionToken",
+ "android/support/v4/media/session/MediaControllerCompat$PlaybackInfo": "androidx/media/session/MediaControllerCompat$PlaybackInfo",
+ "android/support/v17/leanback/app/DetailsBackgroundVideoHelper": "androidx/leanback/app/DetailsBackgroundVideoHelper",
+ "android/support/v17/leanback/app/RowsFragment$MainFragmentRowsAdapter": "androidx/leanback/app/RowsFragment$MainFragmentRowsAdapter",
+ "android/support/v7/app/OverlayListView$OverlayObject": "androidx/app/OverlayListView$OverlayObject",
+ "android/support/v4/provider/SingleDocumentFile": "androidx/provider/SingleDocumentFile",
+ "android/support/v7/app/AppCompatDelegateImplV9$ActionModeCallbackWrapperV9": "androidx/app/AppCompatDelegateImplV9$ActionModeCallbackWrapperV9",
+ "android/support/v4/widget/TintableCompoundButton": "androidx/widget/TintableCompoundButton",
+ "android/support/v7/graphics/Target$Builder": "androidx/graphics/Target$Builder",
+ "android/support/v17/leanback/widget/NonOverlappingFrameLayout": "androidx/leanback/widget/NonOverlappingFrameLayout",
+ "android/support/annotation/IntegerRes": "androidx/annotation/IntegerRes",
+ "android/support/media/tv/CollectionUtils": "androidx/media/tv/CollectionUtils",
+ "android/support/v4/provider/FontsContractCompat$FontRequestCallback": "androidx/provider/FontsContractCompat$FontRequestCallback",
+ "android/support/design/internal/BottomNavigationMenuView": "androidx/design/internal/BottomNavigationMenuView",
+ "android/support/v4/graphics/drawable/RoundedBitmapDrawable21": "androidx/graphics/drawable/RoundedBitmapDrawable21",
+ "android/support/design/widget/CoordinatorLayout$SavedState": "androidx/design/widget/CoordinatorLayout$SavedState",
+ "android/support/text/emoji/BuildConfig": "androidx/text/emoji/BuildConfig",
+ "android/support/media/tv/TvContractCompat": "androidx/media/tv/TvContractCompat",
+ "android/support/v7/media/RemoteControlClientCompat$PlaybackInfo": "androidx/media/RemoteControlClientCompat$PlaybackInfo",
+ "android/support/v7/app/AppCompatDelegateImplV9$ActionMenuPresenterCallback": "androidx/app/AppCompatDelegateImplV9$ActionMenuPresenterCallback",
+ "android/support/v17/leanback/widget/StreamingTextView$DottySpan": "androidx/leanback/widget/StreamingTextView$DottySpan",
+ "android/support/v7/view/menu/ActionMenuItemView$PopupCallback": "androidx/view/menu/ActionMenuItemView$PopupCallback",
+ "android/support/percent/PercentLayoutHelper": "androidx/PercentLayoutHelper",
+ "android/support/v17/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperVersion": "androidx/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperVersion",
+ "android/support/v17/leanback/widget/VerticalGridPresenter$ViewHolder": "androidx/leanback/widget/VerticalGridPresenter$ViewHolder",
+ "android/support/media/tv/BaseProgram": "androidx/media/tv/BaseProgram",
+ "android/support/v4/view/ViewGroupCompat": "androidx/view/ViewGroupCompat",
+ "android/support/media/instantvideo/preload/InstantVideoPreloadManager$AsyncTaskVideoPreloader": "androidx/media/instantvideo/preload/InstantVideoPreloadManager$AsyncTaskVideoPreloader",
+ "android/support/v4/widget/FocusStrategy$CollectionAdapter": "androidx/widget/FocusStrategy$CollectionAdapter",
+ "android/support/v7/util/SortedList$Callback": "androidx/util/SortedList$Callback",
+ "android/support/v17/leanback/widget/Parallax$PropertyMarkerValue": "androidx/leanback/widget/Parallax$PropertyMarkerValue",
+ "android/support/v4/text/TextDirectionHeuristicsCompat$AnyStrong": "androidx/text/TextDirectionHeuristicsCompat$AnyStrong",
+ "android/support/v14/preference/PreferenceFragment$OnPreferenceStartScreenCallback": "androidx/preference/PreferenceFragment$OnPreferenceStartScreenCallback",
+ "android/support/v17/leanback/widget/picker/PickerColumn": "androidx/leanback/widget/picker/PickerColumn",
+ "android/support/transition/TransitionPropagation": "androidx/transition/TransitionPropagation",
+ "android/support/v17/leanback/widget/WindowAlignment": "androidx/leanback/widget/WindowAlignment",
+ "android/support/v17/leanback/transition/TranslationAnimationCreator": "androidx/leanback/transition/TranslationAnimationCreator",
+ "android/support/v7/media/MediaRouterApi24": "androidx/media/MediaRouterApi24",
+ "android/support/transition/Styleable$Slide": "androidx/transition/Styleable$Slide",
+ "android/support/v7/view/menu/StandardMenuPopup": "androidx/view/menu/StandardMenuPopup",
+ "android/support/v4/widget/PopupMenuCompat": "androidx/widget/PopupMenuCompat",
+ "android/support/design/widget/CollapsingToolbarLayout$LayoutParams$CollapseMode": "androidx/design/widget/CollapsingToolbarLayout$LayoutParams$CollapseMode",
+ "android/support/v17/leanback/widget/ObjectAdapter": "androidx/leanback/widget/ObjectAdapter",
+ "android/support/v4/view/GestureDetectorCompat": "androidx/view/GestureDetectorCompat",
+ "android/support/v17/leanback/widget/Parallax$IntPropertyMarkerValue": "androidx/leanback/widget/Parallax$IntPropertyMarkerValue",
+ "android/support/v4/view/ViewCompat$ViewCompatApi26Impl": "androidx/view/ViewCompat$ViewCompatApi26Impl",
+ "android/support/v7/media/RemoteControlClientCompat$VolumeCallback": "androidx/media/RemoteControlClientCompat$VolumeCallback",
+ "android/support/design/widget/AnimationUtils": "androidx/design/widget/AnimationUtils",
+ "android/support/v4/view/ViewCompat$ScrollIndicators": "androidx/view/ViewCompat$ScrollIndicators",
+ "android/support/media/tv/WatchNextProgram$Builder": "androidx/media/tv/WatchNextProgram$Builder",
+ "android/support/v7/graphics/Palette$Filter": "androidx/graphics/Palette$Filter",
+ "android/support/annotation/BinderThread": "androidx/annotation/BinderThread",
+ "android/support/v17/leanback/widget/FocusHighlightHelper$HeaderItemFocusHighlight$HeaderFocusAnimator": "androidx/leanback/widget/FocusHighlightHelper$HeaderItemFocusHighlight$HeaderFocusAnimator",
+ "android/support/media/tv/Program$Builder": "androidx/media/tv/Program$Builder",
+ "android/support/v4/hardware/fingerprint/FingerprintManagerCompat$AuthenticationResult": "androidx/hardware/fingerprint/FingerprintManagerCompat$AuthenticationResult",
+ "android/support/v4/os/LocaleListCompat$LocaleListCompatApi24Impl": "androidx/os/LocaleListCompat$LocaleListCompatApi24Impl",
+ "android/support/v17/leanback/widget/GuidedActionAdapter$FocusListener": "androidx/leanback/widget/GuidedActionAdapter$FocusListener",
+ "android/support/v17/leanback/widget/ControlBarPresenter$ViewHolder": "androidx/leanback/widget/ControlBarPresenter$ViewHolder",
+ "android/support/v7/graphics/drawable/DrawerArrowDrawable$ArrowDirection": "androidx/graphics/drawable/DrawerArrowDrawable$ArrowDirection",
+ "android/support/v4/view/ViewPager$DecorView": "androidx/view/ViewPager$DecorView",
+ "android/support/v4/view/ViewParentCompat$ViewParentCompatApi19Impl": "androidx/view/ViewParentCompat$ViewParentCompatApi19Impl",
+ "android/support/v7/widget/StaggeredGridLayoutManager$Span": "androidx/widget/StaggeredGridLayoutManager$Span",
+ "android/support/wear/widget/ProgressDrawable": "androidx/wear/widget/ProgressDrawable",
+ "android/support/v7/media/MediaRouterJellybeanMr2$RouteInfo": "androidx/media/MediaRouterJellybeanMr2$RouteInfo",
+ "android/support/v4/graphics/PathParser$PathDataNode": "androidx/graphics/PathParser$PathDataNode",
+ "android/support/v17/leanback/graphics/ColorFilterCache": "androidx/leanback/graphics/ColorFilterCache",
+ "android/support/text/emoji/EmojiCompat$InitCallback": "androidx/text/emoji/EmojiCompat$InitCallback",
+ "android/support/v17/leanback/app/BrowseFragment$MainFragmentAdapterRegistry": "androidx/leanback/app/BrowseFragment$MainFragmentAdapterRegistry",
+ "android/support/transition/PropertyValuesHolderUtils": "androidx/transition/PropertyValuesHolderUtils",
+ "android/support/v7/widget/ActivityChooserModel$DefaultSorter": "androidx/widget/ActivityChooserModel$DefaultSorter",
+ "android/support/v7/app/AlertController$CheckedItemAdapter": "androidx/app/AlertController$CheckedItemAdapter",
+ "android/support/design/widget/TabItem": "androidx/design/widget/TabItem",
+ "android/support/v4/media/MediaBrowserCompatApi21$ConnectionCallbackProxy": "androidx/media/MediaBrowserCompatApi21$ConnectionCallbackProxy",
+ "android/support/content/LoaderQueryRunner": "androidx/content/LoaderQueryRunner",
+ "android/support/v17/leanback/app/BrowseSupportFragment$FragmentFactory": "androidx/leanback/app/BrowseSupportFragment$FragmentFactory",
+ "android/support/v7/app/AppCompatDelegateImplN$AppCompatWindowCallbackN": "androidx/app/AppCompatDelegateImplN$AppCompatWindowCallbackN",
+ "android/support/wear/widget/drawer/WearableDrawerLayout$DrawerDraggerCallback": "androidx/wear/widget/drawer/WearableDrawerLayout$DrawerDraggerCallback",
+ "android/support/content/BuildConfig": "androidx/content/BuildConfig",
+ "android/support/v7/widget/OpReorderer": "androidx/widget/OpReorderer",
+ "android/support/media/instantvideo/preload/InstantVideoPreloadManager": "androidx/media/instantvideo/preload/InstantVideoPreloadManager",
+ "android/support/v4/view/ViewPropertyAnimatorCompat": "androidx/view/ViewPropertyAnimatorCompat",
+ "android/support/v13/app/FragmentCompat$FragmentCompatApi23Impl": "androidx/app/FragmentCompat$FragmentCompatApi23Impl",
+ "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi23": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi23",
+ "android/support/v4/internal/view/SupportSubMenu": "androidx/internal/view/SupportSubMenu",
+ "android/support/text/emoji/EmojiProcessor$Action": "androidx/text/emoji/EmojiProcessor$Action",
+ "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi21": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi21",
+ "android/support/v17/leanback/widget/DetailsOverviewLogoPresenter$ViewHolder": "androidx/leanback/widget/DetailsOverviewLogoPresenter$ViewHolder",
+ "android/support/v7/widget/OrientationHelper": "androidx/widget/OrientationHelper",
+ "android/support/v4/app/FragmentTransition$FragmentContainerTransition": "androidx/app/FragmentTransition$FragmentContainerTransition",
+ "android/support/multidex/BuildConfig": "androidx/multidex/BuildConfig",
+ "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi26": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi26",
+ "android/support/v7/preference/PreferenceViewHolder": "androidx/preference/PreferenceViewHolder",
+ "android/support/graphics/drawable/VectorDrawableCommon": "androidx/graphics/drawable/VectorDrawableCommon",
+ "android/support/v4/view/animation/FastOutLinearInInterpolator": "androidx/view/animation/FastOutLinearInInterpolator",
+ "android/support/v4/media/MediaBrowserServiceCompatApi26$MediaBrowserServiceAdaptor": "androidx/media/MediaBrowserServiceCompatApi26$MediaBrowserServiceAdaptor",
+ "android/support/v7/view/SupportActionModeWrapper": "androidx/view/SupportActionModeWrapper",
+ "android/support/v7/app/AppCompatDelegateImplV11": "androidx/app/AppCompatDelegateImplV11",
+ "android/support/v7/app/AppCompatDelegateImplV14": "androidx/app/AppCompatDelegateImplV14",
+ "android/support/v4/graphics/TypefaceCompatApi26Impl": "androidx/graphics/TypefaceCompatApi26Impl",
+ "android/support/v17/leanback/media/PlaybackGlueHost$PlayerCallback": "androidx/leanback/media/PlaybackGlueHost$PlayerCallback",
+ "android/support/design/widget/BottomNavigationView$SavedState": "androidx/design/widget/BottomNavigationView$SavedState",
+ "android/support/v7/preference/R$attr": "androidx/preference/R$attr",
+ "android/support/text/emoji/R$styleable": "androidx/text/emoji/R$styleable",
+ "android/support/v4/view/animation/LinearOutSlowInInterpolator": "androidx/view/animation/LinearOutSlowInInterpolator",
+ "android/support/customtabs/BuildConfig": "androidx/browser/customtabs/BuildConfig",
+ "android/support/v7/widget/LinearLayoutManager$LayoutState": "androidx/widget/LinearLayoutManager$LayoutState",
+ "android/support/wear/widget/BoxInsetLayout": "androidx/wear/widget/BoxInsetLayout",
+ "android/support/media/instantvideo/BuildConfig": "androidx/media/instantvideo/BuildConfig",
+ "android/support/design/widget/HeaderBehavior": "androidx/design/widget/HeaderBehavior",
+ "android/support/v17/leanback/widget/PageRow": "androidx/leanback/widget/PageRow",
+ "android/support/v7/widget/ViewStubCompat": "androidx/widget/ViewStubCompat",
+ "android/support/v7/widget/SearchView$AutoCompleteTextViewReflector": "androidx/widget/SearchView$AutoCompleteTextViewReflector",
+ "android/support/v17/leanback/widget/OnChildLaidOutListener": "androidx/leanback/widget/OnChildLaidOutListener",
+ "android/support/v7/app/TwilightManager$TwilightState": "androidx/app/TwilightManager$TwilightState",
+ "android/support/v7/widget/FastScroller": "androidx/widget/FastScroller",
+ "android/support/design/widget/CoordinatorLayout$ViewElevationComparator": "androidx/design/widget/CoordinatorLayout$ViewElevationComparator",
+ "android/support/transition/TransitionManager": "androidx/transition/TransitionManager",
+ "android/support/v7/widget/AppCompatDrawableManager": "androidx/widget/AppCompatDrawableManager",
+ "android/support/animation/DynamicAnimation$OnAnimationUpdateListener": "androidx/animation/DynamicAnimation$OnAnimationUpdateListener",
+ "android/support/v4/graphics/TypefaceCompat": "androidx/graphics/TypefaceCompat",
+ "android/support/v17/preference/LeanbackPreferenceFragment": "androidx/leanback/preference/LeanbackPreferenceFragment",
+ "android/support/v17/leanback/widget/ParallaxTarget": "androidx/leanback/widget/ParallaxTarget",
+ "android/support/annotation/StyleRes": "androidx/annotation/StyleRes",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$ThumbsDownAction": "androidx/leanback/widget/PlaybackControlsRow$ThumbsDownAction",
+ "android/support/v17/leanback/media/PlaybackTransportControlGlue$SeekUiClient": "androidx/leanback/media/PlaybackTransportControlGlue$SeekUiClient",
+ "android/support/v7/media/SystemMediaRouteProvider$JellybeanImpl$SystemRouteRecord": "androidx/media/SystemMediaRouteProvider$JellybeanImpl$SystemRouteRecord",
+ "android/support/v17/leanback/widget/ShadowHelper$ShadowHelperStubImpl": "androidx/leanback/widget/ShadowHelper$ShadowHelperStubImpl",
+ "android/support/animation/DynamicAnimation$ViewProperty": "androidx/animation/DynamicAnimation$ViewProperty",
+ "android/support/v7/app/AppCompatDelegateImplV23": "androidx/app/AppCompatDelegateImplV23",
+ "android/support/v4/app/NotificationManagerCompat": "androidx/app/NotificationManagerCompat",
+ "android/support/v4/media/session/MediaControllerCompat": "androidx/media/session/MediaControllerCompat",
+ "android/support/v17/leanback/widget/GuidedDatePickerAction": "androidx/leanback/widget/GuidedDatePickerAction",
+ "android/support/v4/widget/CircularProgressDrawable$ProgressDrawableSize": "androidx/widget/CircularProgressDrawable$ProgressDrawableSize",
+ "android/support/v17/leanback/widget/Presenter$ViewHolderTask": "androidx/leanback/widget/Presenter$ViewHolderTask",
+ "android/support/text/emoji/bundled/BundledEmojiCompatConfig": "androidx/text/emoji/bundled/BundledEmojiCompatConfig",
+ "android/support/content/ContentPager$CursorView": "androidx/content/ContentPager$CursorView",
+ "android/support/transition/TranslationAnimationCreator$TransitionPositionListener": "androidx/transition/TranslationAnimationCreator$TransitionPositionListener",
+ "android/support/v7/recyclerview/R$styleable": "androidx/recyclerview/R$styleable",
+ "android/support/v17/leanback/widget/PersistentFocusWrapper": "androidx/leanback/widget/PersistentFocusWrapper",
+ "android/support/v4/view/accessibility/AccessibilityWindowInfoCompat": "androidx/view/accessibility/AccessibilityWindowInfoCompat",
+ "android/support/v17/leanback/widget/PlaybackControlsRow$RewindAction": "androidx/leanback/widget/PlaybackControlsRow$RewindAction",
+ "android/support/v7/widget/AppCompatPopupWindow": "androidx/widget/AppCompatPopupWindow",
+ "android/support/coreui/BuildConfig": "androidx/coreui/BuildConfig",
+ "android/support/mediacompat/R$id": "androidx/mediacompat/R$id",
+ "android/support/v17/leanback/widget/ItemAlignmentFacet": "androidx/leanback/widget/ItemAlignmentFacet",
+ "android/support/v4/view/GestureDetectorCompat$GestureDetectorCompatImplBase$GestureHandler": "androidx/view/GestureDetectorCompat$GestureDetectorCompatImplBase$GestureHandler",
+ "android/support/v17/leanback/widget/GuidedAction$BuilderBase": "androidx/leanback/widget/GuidedAction$BuilderBase",
+ "android/support/v17/leanback/widget/RoundedRectHelper$Impl": "androidx/leanback/widget/RoundedRectHelper$Impl",
+ "android/support/v7/media/MediaRouterJellybean$CallbackProxy": "androidx/media/MediaRouterJellybean$CallbackProxy",
+ "android/support/design/widget/CollapsingToolbarLayout$LayoutParams": "androidx/design/widget/CollapsingToolbarLayout$LayoutParams",
+ "android/support/v7/preference/DialogPreference": "androidx/preference/DialogPreference",
+ "android/support/v7/preference/EditTextPreference": "androidx/preference/EditTextPreference",
+ "android/support/v4/media/MediaBrowserCompatApi23$ItemCallbackProxy": "androidx/media/MediaBrowserCompatApi23$ItemCallbackProxy",
+ "android/support/v4/text/util/LinkifyCompat$LinkifyMask": "androidx/text/util/LinkifyCompat$LinkifyMask",
+ "android/support/v7/widget/helper/ItemTouchHelper$SimpleCallback": "androidx/widget/helper/ItemTouchHelper$SimpleCallback",
+ "android/support/wear/ambient/AmbientMode$AmbientCallbackProvider": "androidx/wear/ambient/AmbientMode$AmbientCallbackProvider",
+ "android/support/v7/widget/CardViewImpl": "androidx/widget/CardViewImpl",
+ "android/support/animation/FloatValueHolder": "androidx/animation/FloatValueHolder",
+ "android/support/transition/MatrixUtils": "androidx/transition/MatrixUtils",
+ "android/support/v14/preference/PreferenceFragment$OnPreferenceStartFragmentCallback": "androidx/preference/PreferenceFragment$OnPreferenceStartFragmentCallback",
+ "android/support/v4/widget/SlidingPaneLayout$PanelSlideListener": "androidx/widget/SlidingPaneLayout$PanelSlideListener",
+ "android/support/v7/util/SortedList": "androidx/util/SortedList",
+ "android/support/v4/view/AccessibilityDelegateCompat$AccessibilityDelegateBaseImpl": "androidx/view/AccessibilityDelegateCompat$AccessibilityDelegateBaseImpl",
+ "android/support/v7/app/MediaRouteControllerDialog$FetchArtTask": "androidx/app/MediaRouteControllerDialog$FetchArtTask",
+ "android/support/compat/R$drawable": "androidx/compat/R$drawable",
+ "android/support/transition/Visibility$VisibilityInfo": "androidx/transition/Visibility$VisibilityInfo",
+ "android/support/v7/widget/ThemedSpinnerAdapter": "androidx/widget/ThemedSpinnerAdapter",
+ "android/support/v17/leanback/widget/GuidanceStylingRelativeLayout": "androidx/leanback/widget/GuidanceStylingRelativeLayout",
+ "android/support/v7/media/MediaRouter$ProviderInfo": "androidx/media/MediaRouter$ProviderInfo",
+ "android/support/v7/media/MediaControlIntent": "androidx/media/MediaControlIntent",
+ "android/support/v17/leanback/widget/ListRow": "androidx/leanback/widget/ListRow",
+ "android/support/v7/view/menu/ListMenuPresenter$MenuAdapter": "androidx/view/menu/ListMenuPresenter$MenuAdapter",
+ "android/support/v4/app/FrameMetricsAggregator$FrameMetricsBaseImpl": "androidx/app/FrameMetricsAggregator$FrameMetricsBaseImpl",
+ "android/support/design/widget/TabLayout$SlidingTabStrip": "androidx/design/widget/TabLayout$SlidingTabStrip",
+ "android/support/content/ContentPager$ContentCallback": "androidx/content/ContentPager$ContentCallback",
+ "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplBase": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplBase",
+ "android/support/v7/util/TileList": "androidx/util/TileList",
+ "android/support/v7/widget/ActionBarBackgroundDrawable": "androidx/widget/ActionBarBackgroundDrawable",
+ "android/support/v4/widget/CursorFilter$CursorFilterClient": "androidx/widget/CursorFilter$CursorFilterClient",
+ "android/support/v17/leanback/database/CursorMapper": "androidx/leanback/database/CursorMapper",
+ "android/support/v17/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperKitKatImpl": "androidx/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperKitKatImpl",
+ "android/support/v7/cardview/R$styleable": "androidx/cardview/R$styleable",
+ "android/support/v17/leanback/transition/TransitionHelperApi21": "androidx/leanback/transition/TransitionHelperApi21",
+ "android/support/v7/widget/ViewInfoStore": "androidx/widget/ViewInfoStore",
+ "android/support/design/widget/BaseTransientBottomBar$BaseCallback$DismissEvent": "androidx/design/widget/BaseTransientBottomBar$BaseCallback$DismissEvent",
+ "android/support/percent/PercentLayoutHelper$PercentLayoutInfo": "androidx/PercentLayoutHelper$PercentLayoutInfo",
+ "android/support/v7/app/AppCompatCallback": "androidx/app/AppCompatCallback",
+ "android/support/wear/R$style": "androidx/wear/R$style",
+ "android/support/v17/leanback/widget/ItemAlignmentFacetHelper": "androidx/leanback/widget/ItemAlignmentFacetHelper",
+ "android/support/v7/view/menu/MenuItemImpl": "androidx/view/menu/MenuItemImpl",
+ "android/support/v4/content/ContextCompat": "androidx/content/ContextCompat",
+ "android/support/percent/PercentLayoutHelper$PercentMarginLayoutParams": "androidx/PercentLayoutHelper$PercentMarginLayoutParams",
+ "android/support/v7/widget/LayoutState": "androidx/widget/LayoutState",
+ "android/support/animation/AnimationHandler$AnimationFrameCallback": "androidx/animation/AnimationHandler$AnimationFrameCallback",
+ "android/support/v17/leanback/widget/SingleRow": "androidx/leanback/widget/SingleRow",
+ "android/support/v4/content/ModernAsyncTask$InternalHandler": "androidx/content/ModernAsyncTask$InternalHandler",
+ "android/support/transition/ImageViewUtilsImpl": "androidx/transition/ImageViewUtilsImpl",
+ "android/support/v7/widget/RtlSpacingHelper": "androidx/widget/RtlSpacingHelper",
+ "android/support/v4/content/PermissionChecker": "androidx/content/PermissionChecker",
+ "android/support/v7/preference/PreferenceCategory": "androidx/preference/PreferenceCategory",
+ "android/support/annotation/IntDef": "androidx/annotation/IntDef",
+ "android/support/v4/app/BundleCompat$BundleCompatBaseImpl": "androidx/app/BundleCompat$BundleCompatBaseImpl",
+ "android/support/v7/app/MediaRouteExpandCollapseButton": "androidx/app/MediaRouteExpandCollapseButton",
+ "android/support/v17/leanback/animation/LogAccelerateInterpolator": "androidx/leanback/animation/LogAccelerateInterpolator",
+ "android/support/v13/app/FragmentPagerAdapter": "androidx/app/FragmentPagerAdapter",
+ "android/support/content/InMemoryCursor": "androidx/content/InMemoryCursor",
+ "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ActionsItemBridgeAdapter": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ActionsItemBridgeAdapter",
+ "android/support/v7/widget/AppCompatTextViewAutoSizeHelper": "androidx/widget/AppCompatTextViewAutoSizeHelper",
+ "android/support/multidex/instrumentation/BuildConfig": "androidx/multidex/instrumentation/BuildConfig",
+ "android/support/v7/preference/PreferenceGroup": "androidx/preference/PreferenceGroup",
+ "android/support/v7/media/RegisteredMediaRouteProvider$Connection": "androidx/media/RegisteredMediaRouteProvider$Connection",
+ "android/support/v4/os/ParcelableCompatCreatorCallbacks": "androidx/os/ParcelableCompatCreatorCallbacks",
+ "android/support/v4/media/MediaMetadataCompat$BitmapKey": "androidx/media/MediaMetadataCompat$BitmapKey",
+ "android/support/v7/app/MediaRouteActionProvider$MediaRouterCallback": "androidx/app/MediaRouteActionProvider$MediaRouterCallback",
+ "android/support/v7/view/ViewPropertyAnimatorCompatSet": "androidx/view/ViewPropertyAnimatorCompatSet",
+ "android/support/v7/widget/AppCompatMultiAutoCompleteTextView": "androidx/widget/AppCompatMultiAutoCompleteTextView",
+ "android/support/v17/leanback/widget/GridLayoutManager$GridLinearSmoothScroller": "androidx/leanback/widget/GridLayoutManager$GridLinearSmoothScroller",
+ "android/support/design/internal/NavigationMenuView": "androidx/design/internal/NavigationMenuView",
+ "android/support/v17/leanback/app/SearchSupportFragment": "androidx/leanback/app/SearchSupportFragment",
+ "android/support/v7/media/SystemMediaRouteProvider$Api24Impl": "androidx/media/SystemMediaRouteProvider$Api24Impl",
+ "android/support/v4/content/FileProvider$PathStrategy": "androidx/content/FileProvider$PathStrategy",
+ "android/support/v17/leanback/util/StateMachine": "androidx/leanback/util/StateMachine",
+ "android/support/v7/widget/AppCompatCheckedTextView": "androidx/widget/AppCompatCheckedTextView",
+ "android/support/v4/media/session/PlaybackStateCompat$Builder": "androidx/media/session/PlaybackStateCompat$Builder",
+ "android/support/v17/leanback/widget/DetailsParallaxDrawable": "androidx/leanback/widget/DetailsParallaxDrawable",
+ "android/support/v17/leanback/widget/GuidedDatePickerAction$BuilderBase": "androidx/leanback/widget/GuidedDatePickerAction$BuilderBase",
+ "android/support/v17/leanback/widget/OnItemViewSelectedListener": "androidx/leanback/widget/OnItemViewSelectedListener",
+ "android/support/v7/widget/ShareActionProvider$OnShareTargetSelectedListener": "androidx/widget/ShareActionProvider$OnShareTargetSelectedListener",
+ "android/support/v4/app/JobIntentService$CompatWorkItem": "androidx/app/JobIntentService$CompatWorkItem",
+ "android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat": "androidx/preference/MultiSelectListPreferenceDialogFragmentCompat",
+ "android/support/v17/leanback/widget/OnActionClickedListener": "androidx/leanback/widget/OnActionClickedListener",
+ "android/support/design/widget/SwipeDismissBehavior$OnDismissListener": "androidx/design/widget/SwipeDismissBehavior$OnDismissListener",
+ "android/support/design/R$id": "androidx/design/R$id",
+ "android/support/content/ContentPager$Stats": "androidx/content/ContentPager$Stats",
+ "android/support/v17/leanback/widget/SinglePresenterSelector": "androidx/leanback/widget/SinglePresenterSelector",
+ "android/support/v7/widget/GridLayout$Arc": "androidx/widget/GridLayout$Arc",
+ "android/support/v17/leanback/widget/BaseGridView$OnKeyInterceptListener": "androidx/leanback/widget/BaseGridView$OnKeyInterceptListener",
+ "android/support/customtabs/CustomTabsService$Relation": "androidx/browser/customtabs/CustomTabsService$Relation",
+ "android/support/v4/content/WakefulBroadcastReceiver": "androidx/content/WakefulBroadcastReceiver",
+ "android/support/v4/os/LocaleHelper": "androidx/os/LocaleHelper",
+ "android/support/v7/app/ActionBar$NavigationMode": "androidx/app/ActionBar$NavigationMode",
+ "android/support/v7/media/RemotePlaybackClient$ActionReceiver": "androidx/media/RemotePlaybackClient$ActionReceiver",
+ "android/support/v7/view/menu/CascadingMenuPopup$HorizPosition": "androidx/view/menu/CascadingMenuPopup$HorizPosition",
+ "android/support/v13/view/inputmethod/EditorInfoCompat": "androidx/view/inputmethod/EditorInfoCompat",
+ "android/support/v17/leanback/widget/Grid": "androidx/leanback/widget/Grid",
+ "android/support/annotation/TransitionRes": "androidx/annotation/TransitionRes",
+ "android/support/v4/media/VolumeProviderCompat": "androidx/media/VolumeProviderCompat",
+ "android/support/multidex/MultiDexApplication": "androidx/multidex/MultiDexApplication",
+ "android/support/text/emoji/EmojiCompat$MetadataRepoLoader": "androidx/text/emoji/EmojiCompat$MetadataRepoLoader",
+ "android/support/design/widget/TextInputLayout": "androidx/design/widget/TextInputLayout",
+ "android/support/v4/view/ViewCompat$ViewCompatApi24Impl": "androidx/view/ViewCompat$ViewCompatApi24Impl",
+ "android/support/v4/provider/FontRequest": "androidx/provider/FontRequest",
+ "android/support/v4/media/session/MediaButtonReceiver$MediaButtonConnectionCallback": "androidx/media/session/MediaButtonReceiver$MediaButtonConnectionCallback",
+ "android/support/v7/widget/RecyclerView$SmoothScroller$ScrollVectorProvider": "androidx/widget/RecyclerView$SmoothScroller$ScrollVectorProvider",
+ "android/support/v4/media/session/MediaSessionCompat$MediaSessionImpl": "androidx/media/session/MediaSessionCompat$MediaSessionImpl",
+ "android/support/v4/content/ModernAsyncTask$Status": "androidx/content/ModernAsyncTask$Status",
+ "android/support/v7/widget/AppCompatDrawableManager$ColorFilterLruCache": "androidx/widget/AppCompatDrawableManager$ColorFilterLruCache",
+ "android/support/multidex/MultiDex": "androidx/multidex/MultiDex",
+ "android/support/wear/ambient/WearableControllerProvider": "androidx/wear/ambient/WearableControllerProvider",
+ "android/support/v17/leanback/widget/ForegroundHelper": "androidx/leanback/widget/ForegroundHelper",
+ "android/support/v4/app/DialogFragment$DialogStyle": "androidx/app/DialogFragment$DialogStyle",
+ "android/support/v4/graphics/TypefaceCompatApi24Impl": "androidx/graphics/TypefaceCompatApi24Impl",
+ "android/support/v7/preference/R": "androidx/preference/R",
+ "android/support/v7/app/ActionBar$Tab": "androidx/app/ActionBar$Tab",
+ "android/support/transition/CircularPropagation": "androidx/transition/CircularPropagation",
+ "android/support/v7/app/ResourcesFlusher": "androidx/app/ResourcesFlusher",
+ "android/support/text/emoji/MetadataListReader$OffsetInfo": "androidx/text/emoji/MetadataListReader$OffsetInfo",
+ "android/support/v4/app/ActivityOptionsCompat$ActivityOptionsCompatApi24Impl": "androidx/app/ActivityOptionsCompat$ActivityOptionsCompatApi24Impl",
+ "android/support/v4/content/SharedPreferencesCompat$EditorCompat": "androidx/content/SharedPreferencesCompat$EditorCompat",
+ "android/support/v7/widget/RecyclerView$OnFlingListener": "androidx/widget/RecyclerView$OnFlingListener",
+ "android/support/animation/AnimationHandler$AnimationCallbackDispatcher": "androidx/animation/AnimationHandler$AnimationCallbackDispatcher",
+ "android/support/v7/widget/ResourcesWrapper": "androidx/widget/ResourcesWrapper",
+ "android/support/v17/leanback/widget/BrowseFrameLayout$OnChildFocusListener": "androidx/leanback/widget/BrowseFrameLayout$OnChildFocusListener",
+ "android/support/v7/widget/AppCompatEditText": "androidx/widget/AppCompatEditText",
+ "android/support/media/tv/TvContractCompat$WatchNextPrograms": "androidx/media/tv/TvContractCompat$WatchNextPrograms",
+ "android/support/v4/widget/ListPopupWindowCompat": "androidx/widget/ListPopupWindowCompat",
+ "android/support/v7/preference/PreferenceFragmentCompat$OnPreferenceDisplayDialogCallback": "androidx/preference/PreferenceFragmentCompat$OnPreferenceDisplayDialogCallback",
+ "android/support/v7/util/DiffUtil$PostponedUpdate": "androidx/util/DiffUtil$PostponedUpdate",
+ "android/support/transition/TransitionManager$MultiListener": "androidx/transition/TransitionManager$MultiListener",
+ "android/support/v4/view/ViewPropertyAnimatorCompat$ViewPropertyAnimatorListenerApi14": "androidx/view/ViewPropertyAnimatorCompat$ViewPropertyAnimatorListenerApi14",
+ "android/support/v17/leanback/widget/ViewsStateBundle": "androidx/leanback/widget/ViewsStateBundle",
+ "android/support/v4/provider/FontsContractCompat$TypefaceResult": "androidx/provider/FontsContractCompat$TypefaceResult",
+ "android/support/v4/widget/DrawerLayout$State": "androidx/widget/DrawerLayout$State",
+ "android/support/v4/widget/SwipeRefreshLayout$OnRefreshListener": "androidx/widget/SwipeRefreshLayout$OnRefreshListener",
+ "android/support/media/ExifInterface$Rational": "androidx/media/ExifInterface$Rational",
+ "android/support/v4/view/ViewPager$PagerObserver": "androidx/view/ViewPager$PagerObserver",
+ "android/support/design/widget/StateListAnimator": "androidx/design/widget/StateListAnimator",
+ "android/support/v4/media/MediaBrowserCompat$CallbackHandler": "androidx/media/MediaBrowserCompat$CallbackHandler",
+ "android/support/customtabs/CustomTabsClient": "androidx/browser/customtabs/CustomTabsClient",
+ "android/support/v4/media/MediaBrowserServiceCompatApi26$ServiceCompatProxy": "androidx/media/MediaBrowserServiceCompatApi26$ServiceCompatProxy",
+ "android/support/transition/Slide$CalculateSlideHorizontal": "androidx/transition/Slide$CalculateSlideHorizontal",
+ "android/support/v17/leanback/media/PlaybackBannerControlGlue$SPEED": "androidx/leanback/media/PlaybackBannerControlGlue$SPEED",
+ "android/support/annotation/CallSuper": "androidx/annotation/CallSuper",
+ "android/support/design/widget/Snackbar$Callback": "androidx/design/widget/Snackbar$Callback",
+ "android/support/v4/app/ActivityManagerCompat": "androidx/app/ActivityManagerCompat",
+ "android/support/v17/leanback/widget/RoundedRectHelperApi21": "androidx/leanback/widget/RoundedRectHelperApi21",
+ "android/support/v7/graphics/Palette": "androidx/graphics/palette/Palette",
+ "android/support/wear/R$color": "androidx/wear/R$color",
+ "android/support/v17/leanback/widget/ItemBridgeAdapter$OnFocusChangeListener": "androidx/leanback/widget/ItemBridgeAdapter$OnFocusChangeListener",
+ "android/support/v7/media/MediaRouteProviderService$ProviderCallback": "androidx/media/MediaRouteProviderService$ProviderCallback",
+ "android/support/media/ExifInterface": "androidx/media/ExifInterface",
+ "android/support/v4/app/FragmentManagerImpl": "androidx/app/FragmentManagerImpl",
+ "android/support/v13/app/FragmentTabHost$DummyTabFactory": "androidx/app/FragmentTabHost$DummyTabFactory",
+ "android/support/app/recommendation/ContentRecommendation$Builder": "androidx/app/recommendation/ContentRecommendation$Builder",
+ "android/support/v17/leanback/widget/RowHeaderView": "androidx/leanback/widget/RowHeaderView",
+ "android/support/v4/widget/DrawerLayout$EdgeGravity": "androidx/widget/DrawerLayout$EdgeGravity",
+ "android/support/v7/view/menu/MenuWrapperICS": "androidx/view/menu/MenuWrapperICS",
+ "android/support/v7/widget/RoundRectDrawableWithShadow$RoundRectHelper": "androidx/widget/RoundRectDrawableWithShadow$RoundRectHelper",
+ "android/support/v4/media/session/MediaControllerCompat$Callback$MessageHandler": "androidx/media/session/MediaControllerCompat$Callback$MessageHandler",
+ "android/support/v4/text/ICUCompat": "androidx/text/ICUCompat",
+ "android/support/v17/leanback/widget/PlaybackSeekDataProvider$ResultCallback": "androidx/leanback/widget/PlaybackSeekDataProvider$ResultCallback",
+ "android/support/v7/widget/ViewUtils": "androidx/widget/ViewUtils",
+ "android/support/v7/appcompat/R$string": "androidx/appcompat/R$string",
+ "android/support/constraint/ConstraintLayout": "androidx/constraint/ConstraintLayout",
+ "android/support/v4/view/ViewPager$SimpleOnPageChangeListener": "androidx/view/ViewPager$SimpleOnPageChangeListener",
+ "android/support/wear/internal/widget/drawer/MultiPageUi": "androidx/wear/internal/widget/drawer/MultiPageUi",
+ "android/support/v17/leanback/media/PlayerAdapter$Callback": "androidx/leanback/media/PlayerAdapter$Callback",
+ "android/support/design/widget/BaseTransientBottomBar$ContentViewCallback": "androidx/design/widget/BaseTransientBottomBar$ContentViewCallback",
+ "android/support/annotation/RestrictTo$Scope": "androidx/annotation/RestrictTo$Scope",
+ "android/support/v4/content/AsyncTaskLoader": "androidx/content/AsyncTaskLoader",
+ "android/support/v17/leanback/widget/ParallaxEffect": "androidx/leanback/widget/ParallaxEffect",
+ "android/support/v17/leanback/app/BackgroundManager$DrawableWrapper": "androidx/leanback/app/BackgroundManager$DrawableWrapper",
+ "android/support/v4/app/ListFragment": "androidx/app/ListFragment",
+ "android/support/design/widget/DirectedAcyclicGraph": "androidx/widget/DirectedAcyclicGraph",
+ "android/support/design/widget/AppBarLayout": "androidx/design/widget/AppBarLayout",
+ "android/support/v7/media/RemoteControlClientCompat$JellybeanImpl": "androidx/media/RemoteControlClientCompat$JellybeanImpl",
+ "android/support/design/widget/ViewGroupUtils": "androidx/widget/ViewGroupUtils",
+ "android/support/design/R$styleable": "androidx/design/R$styleable",
+ "android/support/animation/DynamicAnimation$OnAnimationEndListener": "androidx/animation/DynamicAnimation$OnAnimationEndListener",
+ "android/support/media/tv/TvContractUtils": "androidx/media/tv/TvContractUtils",
+ "android/support/v4/app/JobIntentService$JobWorkEnqueuer": "androidx/app/JobIntentService$JobWorkEnqueuer",
+ "android/support/percent/PercentLayoutHelper$PercentLayoutParams": "androidx/PercentLayoutHelper$PercentLayoutParams",
+ "android/support/v4/util/Pair": "androidx/util/Pair",
+ "android/support/text/emoji/appcompat/BuildConfig": "androidx/text/emoji/appcompat/BuildConfig",
+ "android/support/v17/leanback/transition/LeanbackTransitionHelperKitKat": "androidx/leanback/transition/LeanbackTransitionHelperKitKat",
+ "android/support/v13/view/DragStartHelper": "androidx/view/DragStartHelper",
+ "android/support/v7/widget/ListViewCompat": "androidx/widget/ListViewCompat",
+ "android/support/v7/preference/CheckBoxPreference$Listener": "androidx/preference/CheckBoxPreference$Listener",
+ "android/support/v7/app/AppCompatDelegate$NightMode": "androidx/app/AppCompatDelegate$NightMode",
+ "android/support/v17/leanback/transition/SlideNoPropagation": "androidx/leanback/transition/SlideNoPropagation",
+ "android/support/v7/media/MediaRouteProviderService$ClientRecord": "androidx/media/MediaRouteProviderService$ClientRecord",
+ "android/support/graphics/drawable/VectorDrawableCompat$VectorDrawableCompatState": "androidx/graphics/drawable/VectorDrawableCompat$VectorDrawableCompatState",
+ "android/support/text/emoji/R$layout": "androidx/text/emoji/R$layout",
+ "android/support/v4/media/session/MediaSessionCompat$SessionFlags": "androidx/media/session/MediaSessionCompat$SessionFlags",
+ "android/support/v7/preference/PreferenceRecyclerViewAccessibilityDelegate": "androidx/preference/PreferenceRecyclerViewAccessibilityDelegate",
+ "android/support/transition/AnimatorUtils": "androidx/transition/AnimatorUtils",
+ "android/support/v17/leanback/system/Settings": "androidx/leanback/system/Settings",
+ "android/support/v4/app/FragmentActivity$NonConfigurationInstances": "androidx/app/FragmentActivity$NonConfigurationInstances",
+ "android/support/v17/leanback/widget/GuidedActionAdapter$EditListener": "androidx/leanback/widget/GuidedActionAdapter$EditListener",
+ "android/support/v7/media/MediaRouteProvider$Callback": "androidx/media/MediaRouteProvider$Callback",
+ "android/support/v7/app/AppCompatDelegateImplV9$PanelMenuPresenterCallback": "androidx/app/AppCompatDelegateImplV9$PanelMenuPresenterCallback",
+ "android/support/constraint/ConstraintSet$Constraint": "androidx/constraint/ConstraintSet$Constraint",
+ "android/support/wear/R$dimen": "androidx/wear/R$dimen"
+ },
+ "fields": {
+ "android/support/v4/view/AbsSavedState": {
+ "androidx/view/AbsSavedState": [
+ "CREATOR",
+ "EMPTY_STATE"
+ ]
+ },
+ "android/support/v4/view/PagerTabStrip": {
+ "androidx/widget/PagerTabStrip": [
+ "TAG",
+ "TAB_PADDING",
+ "TAB_SPACING",
+ "FULL_UNDERLINE_HEIGHT",
+ "MIN_PADDING_BOTTOM",
+ "MIN_STRIP_HEIGHT",
+ "MIN_TEXT_SPACING",
+ "INDICATOR_HEIGHT"
+ ]
+ },
+ "android/support/media/tv/TvContractCompat$Channels": {
+ "androidx/media/tv/TvContractCompat$Channels": [
+ "VIDEO_FORMAT_4320P",
+ "VIDEO_RESOLUTION_HD",
+ "VIDEO_RESOLUTION_ED",
+ "VIDEO_FORMAT_720P",
+ "COLUMN_TRANSIENT",
+ "VIDEO_FORMAT_TO_RESOLUTION_MAP",
+ "COLUMN_DISPLAY_NAME",
+ "VIDEO_FORMAT_240P",
+ "COLUMN_VIDEO_FORMAT",
+ "COLUMN_APP_LINK_TEXT",
+ "COLUMN_APP_LINK_POSTER_ART_URI",
+ "VIDEO_FORMAT_360P",
+ "TYPE_OTHER",
+ "COLUMN_NETWORK_AFFILIATION",
+ "TYPE_PAL",
+ "SERVICE_TYPE_OTHER",
+ "VIDEO_FORMAT_480P",
+ "VIDEO_FORMAT_480I",
+ "CONTENT_URI",
+ "TYPE_CMMB",
+ "TYPE_ATSC_C",
+ "TYPE_ATSC_T",
+ "VIDEO_RESOLUTION_FHD",
+ "COLUMN_APP_LINK_INTENT_URI",
+ "VIDEO_FORMAT_2160P",
+ "TYPE_SECAM",
+ "COLUMN_INTERNAL_PROVIDER_FLAG2",
+ "COLUMN_INTERNAL_PROVIDER_FLAG1",
+ "COLUMN_INTERNAL_PROVIDER_FLAG4",
+ "COLUMN_INTERNAL_PROVIDER_FLAG3",
+ "TYPE_T_DMB",
+ "CONTENT_TYPE",
+ "COLUMN_TRANSPORT_STREAM_ID",
+ "VIDEO_FORMAT_576P",
+ "VIDEO_FORMAT_576I",
+ "COLUMN_LOCKED",
+ "COLUMN_SERVICE_TYPE",
+ "TYPE_ISDB_S",
+ "TYPE_ISDB_T",
+ "TYPE_ISDB_C",
+ "COLUMN_DESCRIPTION",
+ "TYPE_DVB_S2",
+ "TYPE_DVB_T2",
+ "TYPE_DVB_SH",
+ "TYPE_DTMB",
+ "COLUMN_INPUT_ID",
+ "VIDEO_RESOLUTION_SD",
+ "COLUMN_VERSION_NUMBER",
+ "COLUMN_SEARCHABLE",
+ "COLUMN_SERVICE_ID",
+ "TYPE_1SEG",
+ "TYPE_DVB_C2",
+ "TYPE_DVB_C",
+ "TYPE_DVB_H",
+ "TYPE_DVB_S",
+ "TYPE_DVB_T",
+ "CONTENT_ITEM_TYPE",
+ "SERVICE_TYPE_AUDIO",
+ "TYPE_ATSC_M_H",
+ "TYPE_NTSC",
+ "COLUMN_BROWSABLE",
+ "TYPE_ISDB_TB",
+ "COLUMN_INTERNAL_PROVIDER_DATA",
+ "COLUMN_DISPLAY_NUMBER",
+ "COLUMN_SYSTEM_APPROVED",
+ "VIDEO_FORMAT_1080I",
+ "VIDEO_FORMAT_1080P",
+ "COLUMN_TYPE",
+ "VIDEO_RESOLUTION_UHD",
+ "COLUMN_APP_LINK_ICON_URI",
+ "TYPE_S_DMB",
+ "COLUMN_APP_LINK_COLOR",
+ "SERVICE_TYPE_AUDIO_VIDEO",
+ "TYPE_PREVIEW",
+ "COLUMN_ORIGINAL_NETWORK_ID",
+ "COLUMN_INTERNAL_PROVIDER_ID"
+ ]
+ },
+ "android/support/v7/widget/ViewBoundsCheck": {
+ "androidx/widget/ViewBoundsCheck": [
+ "FLAG_CVS_EQ_PVE",
+ "FLAG_CVS_EQ_PVS",
+ "GT",
+ "LT",
+ "EQ",
+ "FLAG_CVS_GT_PVS",
+ "FLAG_CVS_GT_PVE",
+ "FLAG_CVE_EQ_PVE",
+ "FLAG_CVE_EQ_PVS",
+ "MASK",
+ "CVS_PVE_POS",
+ "CVE_PVE_POS",
+ "FLAG_CVS_LT_PVE",
+ "FLAG_CVS_LT_PVS",
+ "CVS_PVS_POS",
+ "FLAG_CVE_LT_PVS",
+ "FLAG_CVE_LT_PVE",
+ "CVE_PVS_POS",
+ "FLAG_CVE_GT_PVS",
+ "FLAG_CVE_GT_PVE"
+ ]
+ },
+ "android/support/constraint/ConstraintLayout$LayoutParams": {
+ "androidx/constraint/ConstraintLayout$LayoutParams": [
+ "topToTop",
+ "goneTopMargin",
+ "verticalWeight",
+ "horizontalDimensionFixed",
+ "goneBottomMargin",
+ "matchConstraintMaxHeight",
+ "resolveGoneLeftMargin",
+ "leftMargin",
+ "MATCH_CONSTRAINT",
+ "resolvedRightToLeft",
+ "needsBaseline",
+ "startToEnd",
+ "TOP",
+ "horizontalChainStyle",
+ "guidePercent",
+ "CHAIN_SPREAD",
+ "topMargin",
+ "goneStartMargin",
+ "goneRightMargin",
+ "UNSET",
+ "HORIZONTAL",
+ "dimensionRatioValue",
+ "MATCH_CONSTRAINT_SPREAD",
+ "END",
+ "guideBegin",
+ "matchConstraintMaxWidth",
+ "verticalDimensionFixed",
+ "resolvedRightToRight",
+ "BASELINE",
+ "START",
+ "resolvedHorizontalBias",
+ "bottomToBottom",
+ "MATCH_CONSTRAINT_WRAP",
+ "startToStart",
+ "RIGHT",
+ "orientation",
+ "matchConstraintDefaultHeight",
+ "guideEnd",
+ "bottomToTop",
+ "CHAIN_PACKED",
+ "isGuideline",
+ "dimensionRatioSide",
+ "dimensionRatio",
+ "goneLeftMargin",
+ "matchConstraintMinWidth",
+ "PARENT_ID",
+ "endToStart",
+ "LEFT",
+ "horizontalBias",
+ "leftToLeft",
+ "BOTTOM",
+ "resolveGoneRightMargin",
+ "leftToRight",
+ "verticalBias",
+ "goneEndMargin",
+ "VERTICAL",
+ "rightMargin",
+ "rightToRight",
+ "resolvedLeftToLeft",
+ "topToBottom",
+ "endToEnd",
+ "matchConstraintDefaultWidth",
+ "matchConstraintMinHeight",
+ "height",
+ "CHAIN_SPREAD_INSIDE",
+ "widget",
+ "resolvedLeftToRight",
+ "baselineToBaseline",
+ "rightToLeft",
+ "verticalChainStyle",
+ "editorAbsoluteY",
+ "editorAbsoluteX",
+ "bottomMargin",
+ "width",
+ "horizontalWeight"
+ ]
+ },
+ "android/support/v4/media/session/PlaybackStateCompat": {
+ "androidx/media/session/PlaybackStateCompat": [
+ "STATE_NONE",
+ "ACTION_SET_SHUFFLE_MODE",
+ "ACTION_SKIP_TO_QUEUE_ITEM",
+ "ERROR_CODE_CONTENT_ALREADY_PLAYING",
+ "STATE_ERROR",
+ "SHUFFLE_MODE_NONE",
+ "CREATOR",
+ "STATE_SKIPPING_TO_PREVIOUS",
+ "PLAYBACK_POSITION_UNKNOWN",
+ "REPEAT_MODE_INVALID",
+ "REPEAT_MODE_GROUP",
+ "ACTION_SET_REPEAT_MODE",
+ "ACTION_SKIP_TO_PREVIOUS",
+ "ACTION_PREPARE",
+ "ERROR_CODE_SKIP_LIMIT_REACHED",
+ "REPEAT_MODE_NONE",
+ "ACTION_PREPARE_FROM_URI",
+ "STATE_PLAYING",
+ "STATE_SKIPPING_TO_NEXT",
+ "ACTION_FAST_FORWARD",
+ "ERROR_CODE_END_OF_QUEUE",
+ "ERROR_CODE_PARENTAL_CONTROL_RESTRICTED",
+ "STATE_BUFFERING",
+ "ACTION_REWIND",
+ "KEYCODE_MEDIA_PAUSE",
+ "ACTION_PLAY_FROM_MEDIA_ID",
+ "STATE_FAST_FORWARDING",
+ "ACTION_STOP",
+ "KEYCODE_MEDIA_PLAY",
+ "ACTION_PLAY",
+ "ACTION_SET_CAPTIONING_ENABLED",
+ "ERROR_CODE_NOT_SUPPORTED",
+ "STATE_STOPPED",
+ "ACTION_PLAY_PAUSE",
+ "SHUFFLE_MODE_ALL",
+ "ERROR_CODE_AUTHENTICATION_EXPIRED",
+ "ERROR_CODE_APP_ERROR",
+ "ACTION_SEEK_TO",
+ "ERROR_CODE_CONCURRENT_STREAM_LIMIT",
+ "REPEAT_MODE_ALL",
+ "ERROR_CODE_NOT_AVAILABLE_IN_REGION",
+ "ERROR_CODE_ACTION_ABORTED",
+ "STATE_CONNECTING",
+ "ACTION_SKIP_TO_NEXT",
+ "SHUFFLE_MODE_INVALID",
+ "ACTION_PLAY_FROM_SEARCH",
+ "ERROR_CODE_UNKNOWN_ERROR",
+ "ACTION_PAUSE",
+ "ACTION_PLAY_FROM_URI",
+ "REPEAT_MODE_ONE",
+ "ACTION_SET_RATING",
+ "ACTION_PREPARE_FROM_SEARCH",
+ "STATE_PAUSED",
+ "SHUFFLE_MODE_GROUP",
+ "STATE_REWINDING",
+ "ACTION_PREPARE_FROM_MEDIA_ID",
+ "ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED",
+ "STATE_SKIPPING_TO_QUEUE_ITEM",
+ "ACTION_SET_SHUFFLE_MODE_ENABLED"
+ ]
+ },
+ "android/support/v7/appcompat/R$styleable": {
+ "androidx/appcompat/R$styleable": [
+ "MenuItem_android_title",
+ "Toolbar_android_gravity",
+ "ActionMode_titleTextStyle",
+ "ActionBar_popupTheme",
+ "MenuView_android_itemTextAppearance",
+ "SearchView_goIcon",
+ "MenuItem_actionLayout",
+ "Toolbar_navigationIcon",
+ "ColorStateListItem_android_alpha",
+ "AppCompatTheme_android_windowAnimationStyle",
+ "LinearLayoutCompat_android_orientation",
+ "AppCompatTheme_windowActionBar",
+ "MenuItem_showAsAction",
+ "ColorStateListItem_android_color",
+ "ActivityChooserView_initialActivityCount",
+ "AppCompatSeekBar_tickMarkTint",
+ "CompoundButton_android_button",
+ "MenuGroup_android_orderInCategory",
+ "PopupWindow_overlapAnchor",
+ "ViewBackgroundHelper_backgroundTint",
+ "PopupWindow",
+ "Toolbar_contentInsetEndWithActions",
+ "MenuItem_android_titleCondensed",
+ "TextAppearance",
+ "MenuItem_android_id",
+ "LinearLayoutCompat_measureWithLargestChild",
+ "AppCompatTextView_autoSizeTextType",
+ "AppCompatTheme_windowMinWidthMajor",
+ "DrawerArrowToggle_color",
+ "AppCompatTheme",
+ "SwitchCompat_trackTintMode",
+ "AppCompatTheme_windowActionBarOverlay",
+ "DrawerArrowToggle_spinBars",
+ "LinearLayoutCompat",
+ "AppCompatTextHelper",
+ "ActionMode_subtitleTextStyle",
+ "Toolbar_titleTextAppearance",
+ "ActivityChooserView",
+ "LinearLayoutCompat_divider",
+ "MenuItem_android_alphabeticShortcut",
+ "Toolbar_subtitleTextColor",
+ "AppCompatImageView_tint",
+ "AppCompatTheme_windowFixedHeightMajor",
+ "LinearLayoutCompat_android_baselineAlignedChildIndex",
+ "AppCompatTheme_windowMinWidthMinor",
+ "SearchView_suggestionRowLayout",
+ "ListPopupWindow_android_dropDownHorizontalOffset",
+ "ActionBar_subtitleTextStyle",
+ "Toolbar_titleMarginEnd",
+ "Toolbar_titleMarginTop",
+ "LinearLayoutCompat_Layout",
+ "TextAppearance_android_textColor",
+ "Toolbar_subtitleTextAppearance",
+ "ActionBar_displayOptions",
+ "Toolbar_title",
+ "Spinner_android_entries",
+ "MenuItem_numericModifiers",
+ "RecycleListView",
+ "AppCompatTextHelper_android_drawableEnd",
+ "SearchView_searchHintIcon",
+ "Toolbar_collapseIcon",
+ "AppCompatImageView",
+ "MenuItem_android_icon",
+ "ActionBar_contentInsetStart",
+ "MenuItem_android_onClick",
+ "SearchView_searchIcon",
+ "MenuItem_actionViewClass",
+ "MenuGroup_android_enabled",
+ "Toolbar_subtitle",
+ "MenuGroup_android_id",
+ "TextAppearance_android_fontFamily",
+ "ViewBackgroundHelper_android_background",
+ "TextAppearance_android_textColorHint",
+ "LinearLayoutCompat_android_baselineAligned",
+ "MenuItem_contentDescription",
+ "SearchView_voiceIcon",
+ "ActionBar_background",
+ "ActionMenuItemView",
+ "SwitchCompat_switchMinWidth",
+ "AppCompatTheme_windowFixedWidthMajor",
+ "ActionMenuItemView_android_minWidth",
+ "AlertDialog_buttonPanelSideLayout",
+ "SearchView_defaultQueryHint",
+ "MenuItem_android_numericShortcut",
+ "ActionBar_homeAsUpIndicator",
+ "AppCompatTextHelper_android_drawableTop",
+ "DrawerArrowToggle_arrowHeadLength",
+ "TextAppearance_android_shadowRadius",
+ "Toolbar_titleMargins",
+ "SwitchCompat",
+ "ActionBar_height",
+ "LinearLayoutCompat_Layout_android_layout_gravity",
+ "AlertDialog_multiChoiceItemLayout",
+ "CompoundButton_buttonTint",
+ "SearchView_android_imeOptions",
+ "MenuGroup",
+ "ActionBar_customNavigationLayout",
+ "Toolbar_navigationContentDescription",
+ "Toolbar_popupTheme",
+ "View",
+ "ActionBar",
+ "SwitchCompat_android_textOff",
+ "MenuGroup_android_menuCategory",
+ "MenuItem_tooltipText",
+ "AppCompatTextView",
+ "Spinner",
+ "ViewStubCompat_android_inflatedId",
+ "Spinner_popupTheme",
+ "SearchView_closeIcon",
+ "TextAppearance_textAllCaps",
+ "SwitchCompat_trackTint",
+ "Toolbar_logoDescription",
+ "MenuView_android_itemBackground",
+ "TextAppearance_android_textSize",
+ "SearchView_queryBackground",
+ "MenuItem_android_checked",
+ "SearchView_commitIcon",
+ "LinearLayoutCompat_Layout_android_layout_weight",
+ "ViewStubCompat_android_id",
+ "AppCompatTextView_autoSizePresetSizes",
+ "ActionBar_hideOnContentScroll",
+ "Toolbar_contentInsetStartWithNavigation",
+ "AppCompatTextHelper_android_drawableBottom",
+ "PopupWindow_android_popupBackground",
+ "Toolbar_buttonGravity",
+ "AlertDialog",
+ "TextAppearance_android_textStyle",
+ "SwitchCompat_thumbTintMode",
+ "MenuItem_android_checkable",
+ "AppCompatTheme_windowFixedWidthMinor",
+ "TextAppearance_android_textColorLink",
+ "Toolbar_titleMarginStart",
+ "RecycleListView_paddingBottomNoButtons",
+ "ActionMode_closeItemLayout",
+ "Toolbar",
+ "Toolbar_collapseContentDescription",
+ "MenuItem_android_menuCategory",
+ "AppCompatTextHelper_android_textAppearance",
+ "View_theme",
+ "MenuItem_iconTintMode",
+ "Toolbar_contentInsetLeft",
+ "Toolbar_contentInsetStart",
+ "LinearLayoutCompat_android_weightSum",
+ "SwitchCompat_android_textOn",
+ "AppCompatSeekBar",
+ "MenuItem_actionProviderClass",
+ "Toolbar_titleMargin",
+ "AlertDialog_singleChoiceItemLayout",
+ "Toolbar_contentInsetRight",
+ "LinearLayoutCompat_showDividers",
+ "SwitchCompat_android_thumb",
+ "AlertDialog_showTitle",
+ "TextAppearance_android_shadowDy",
+ "TextAppearance_android_shadowDx",
+ "AppCompatTheme_windowActionModeOverlay",
+ "MenuItem_android_visible",
+ "MenuView",
+ "SearchView",
+ "MenuItem",
+ "SearchView_queryHint",
+ "SwitchCompat_thumbTint",
+ "SwitchCompat_thumbTextPadding",
+ "AlertDialog_listLayout",
+ "ActionBar_subtitle",
+ "AlertDialog_android_layout",
+ "ListPopupWindow_android_dropDownVerticalOffset",
+ "Toolbar_titleMarginBottom",
+ "AppCompatSeekBar_android_thumb",
+ "ListPopupWindow",
+ "ButtonBarLayout_allowStacking",
+ "MenuGroup_android_checkableBehavior",
+ "SwitchCompat_switchPadding",
+ "LinearLayoutCompat_android_gravity",
+ "AppCompatTheme_windowNoTitle",
+ "ActionBar_icon",
+ "AppCompatTextView_autoSizeMinTextSize",
+ "Toolbar_logo",
+ "ViewStubCompat_android_layout",
+ "MenuItem_android_enabled",
+ "MenuItem_iconTint",
+ "AppCompatTextHelper_android_drawableRight",
+ "AppCompatTheme_android_windowIsFloating",
+ "Spinner_android_popupBackground",
+ "TextAppearance_android_shadowColor",
+ "Toolbar_maxButtonHeight",
+ "TextAppearance_android_typeface",
+ "DrawerArrowToggle_drawableSize",
+ "DrawerArrowToggle_barLength",
+ "CompoundButton",
+ "ActionMode_height",
+ "DrawerArrowToggle_arrowShaftLength",
+ "DrawerArrowToggle_gapBetweenBars",
+ "SearchView_android_focusable",
+ "ActionMode",
+ "AppCompatTextHelper_android_drawableStart",
+ "SearchView_android_maxWidth",
+ "ActivityChooserView_expandActivityOverflowButtonDrawable",
+ "ActionMode_background",
+ "ActionBar_backgroundSplit",
+ "SwitchCompat_track",
+ "MenuItem_alphabeticModifiers",
+ "TextAppearance_fontFamily",
+ "DrawerArrowToggle_thickness",
+ "AppCompatTextHelper_android_drawableLeft",
+ "ActionBar_contentInsetEnd",
+ "Spinner_android_dropDownWidth",
+ "ColorStateListItem_alpha",
+ "LinearLayoutCompat_dividerPadding",
+ "ViewStubCompat",
+ "View_android_theme",
+ "ActionBar_backgroundStacked",
+ "SearchView_android_inputType",
+ "AlertDialog_listItemLayout",
+ "AppCompatTheme_panelBackground",
+ "AppCompatImageView_srcCompat",
+ "ColorStateListItem",
+ "AppCompatTheme_windowFixedHeightMinor",
+ "MenuView_preserveIconSpacing",
+ "ActionBar_logo",
+ "AppCompatSeekBar_tickMarkTintMode",
+ "SwitchCompat_showText",
+ "AppCompatTextView_autoSizeStepGranularity",
+ "Toolbar_contentInsetEnd",
+ "SearchView_submitBackground",
+ "MenuView_subMenuArrow",
+ "CompoundButton_buttonTintMode",
+ "MenuItem_android_orderInCategory",
+ "ViewBackgroundHelper_backgroundTintMode",
+ "SwitchCompat_switchTextAppearance",
+ "ActionBar_titleTextStyle",
+ "Toolbar_titleTextColor",
+ "MenuGroup_android_visible",
+ "SwitchCompat_splitTrack",
+ "ButtonBarLayout",
+ "AppCompatSeekBar_tickMark",
+ "Spinner_android_prompt",
+ "AppCompatTextView_autoSizeMaxTextSize",
+ "ActionBar_elevation",
+ "ActionBarLayout_android_layout_gravity",
+ "DrawerArrowToggle",
+ "ActionBar_title",
+ "AppCompatImageView_tintMode",
+ "SearchView_layout",
+ "ViewBackgroundHelper",
+ "RecycleListView_paddingTopNoTitle",
+ "ActionBarLayout",
+ "SearchView_iconifiedByDefault"
+ ]
+ },
+ "android/support/text/emoji/appcompat/BuildConfig": {
+ "androidx/text/emoji/appcompat/BuildConfig": [
+ "DEBUG",
+ "APPLICATION_ID",
+ "FLAVOR",
+ "VERSION_CODE",
+ "BUILD_TYPE",
+ "VERSION_NAME"
+ ]
+ },
+ "android/support/v17/leanback/widget/FocusHighlight": {
+ "androidx/leanback/widget/FocusHighlight": [
+ "ZOOM_FACTOR_SMALL",
+ "ZOOM_FACTOR_XSMALL",
+ "ZOOM_FACTOR_NONE",
+ "ZOOM_FACTOR_LARGE",
+ "ZOOM_FACTOR_MEDIUM"
+ ]
+ },
+ "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase$Command": {
+ "androidx/media/session/MediaSessionCompat$MediaSessionImplBase$Command": [
+ "extras",
+ "command",
+ "stub"
+ ]
+ },
+ "android/support/v7/appcompat/R$attr": {
+ "androidx/appcompat/R$attr": [
+ "checkboxStyle",
+ "colorButtonNormal",
+ "editTextStyle",
+ "actionDropDownStyle",
+ "colorControlNormal",
+ "colorAccent",
+ "actionBarSize",
+ "listMenuViewStyle",
+ "buttonStyle",
+ "colorControlHighlight",
+ "panelMenuListTheme",
+ "seekBarStyle",
+ "actionModeStyle",
+ "alertDialogStyle",
+ "isLightTheme",
+ "ratingBarStyle",
+ "radioButtonStyle",
+ "actionBarTabTextStyle",
+ "alertDialogCenterButtons",
+ "actionBarStyle",
+ "listPopupWindowStyle",
+ "actionBarPopupTheme",
+ "actionOverflowButtonStyle",
+ "spinnerStyle",
+ "popupMenuStyle",
+ "colorPrimaryDark",
+ "drawerArrowStyle",
+ "actionBarWidgetTheme",
+ "alpha",
+ "actionBarTabStyle",
+ "imageButtonStyle",
+ "colorControlActivated",
+ "toolbarStyle",
+ "homeAsUpIndicator",
+ "toolbarNavigationButtonStyle",
+ "colorPrimary",
+ "actionBarTheme",
+ "actionOverflowMenuStyle",
+ "dropDownListViewStyle",
+ "actionModePopupWindowStyle",
+ "actionModeShareDrawable",
+ "dialogTheme",
+ "alertDialogTheme",
+ "searchViewStyle",
+ "colorSwitchThumbNormal",
+ "actionBarTabBarStyle",
+ "textColorSearchUrl",
+ "switchStyle",
+ "autoCompleteTextViewStyle"
+ ]
+ },
+ "android/support/v7/widget/StaggeredGridLayoutManager$Span": {
+ "androidx/widget/StaggeredGridLayoutManager$Span": [
+ "INVALID_LINE"
+ ]
+ },
+ "android/support/v4/app/NotificationManagerCompat": {
+ "androidx/app/NotificationManagerCompat": [
+ "OP_POST_NOTIFICATION",
+ "sEnabledNotificationListeners",
+ "IMPORTANCE_HIGH",
+ "SIDE_CHANNEL_RETRY_MAX_COUNT",
+ "TAG",
+ "SETTING_ENABLED_NOTIFICATION_LISTENERS",
+ "sSideChannelManager",
+ "sLock",
+ "IMPORTANCE_DEFAULT",
+ "SIDE_CHANNEL_RETRY_BASE_INTERVAL_MS",
+ "EXTRA_USE_SIDE_CHANNEL",
+ "IMPORTANCE_NONE",
+ "sEnabledNotificationListenersLock",
+ "ACTION_BIND_SIDE_CHANNEL",
+ "CHECK_OP_NO_THROW",
+ "sEnabledNotificationListenerPackages",
+ "IMPORTANCE_LOW",
+ "IMPORTANCE_MAX",
+ "MAX_SIDE_CHANNEL_SDK_VERSION",
+ "IMPORTANCE_MIN",
+ "IMPORTANCE_UNSPECIFIED"
+ ]
+ },
+ "android/support/v4/util/LruCache": {
+ "androidx/util/LruCache": [
+ "map",
+ "hitCount",
+ "missCount",
+ "maxSize",
+ "putCount",
+ "createCount",
+ "evictionCount",
+ "size"
+ ]
+ },
+ "android/support/v4/content/FileProvider": {
+ "androidx/content/FileProvider": [
+ "META_DATA_FILE_PROVIDER_PATHS",
+ "TAG_EXTERNAL_CACHE",
+ "TAG_FILES_PATH",
+ "TAG_EXTERNAL_FILES",
+ "ATTR_PATH",
+ "ATTR_NAME",
+ "DEVICE_ROOT",
+ "sCache",
+ "COLUMNS",
+ "TAG_EXTERNAL",
+ "TAG_ROOT_PATH",
+ "TAG_CACHE_PATH"
+ ]
+ },
+ "android/support/v4/media/AudioAttributesCompat": {
+ "androidx/media/AudioAttributesCompat": [
+ "FLAG_LOW_LATENCY",
+ "FLAG_DEEP_BUFFER",
+ "USAGE_NOTIFICATION",
+ "SUPPRESSIBLE_USAGES",
+ "SUPPRESSIBLE_CALL",
+ "USAGE_NOTIFICATION_COMMUNICATION_INSTANT",
+ "USAGE_NOTIFICATION_RINGTONE",
+ "USAGE_NOTIFICATION_EVENT",
+ "USAGE_VIRTUAL_SOURCE",
+ "FLAG_BYPASS_MUTE",
+ "USAGE_ASSISTANCE_SONIFICATION",
+ "CONTENT_TYPE_SPEECH",
+ "FLAG_BYPASS_INTERRUPTION_POLICY",
+ "SDK_USAGES",
+ "USAGE_GAME",
+ "USAGE_UNKNOWN",
+ "USAGE_NOTIFICATION_COMMUNICATION_DELAYED",
+ "FLAG_ALL_PUBLIC",
+ "FLAG_SCO",
+ "FLAG_SECURE",
+ "FLAG_ALL",
+ "USAGE_VOICE_COMMUNICATION",
+ "USAGE_VOICE_COMMUNICATION_SIGNALLING",
+ "USAGE_MEDIA",
+ "USAGE_ALARM",
+ "CONTENT_TYPE_MOVIE",
+ "TAG",
+ "FLAG_HW_AV_SYNC",
+ "sForceLegacyBehavior",
+ "USAGE_ASSISTANCE_NAVIGATION_GUIDANCE",
+ "FLAG_BEACON",
+ "CONTENT_TYPE_UNKNOWN",
+ "USAGE_ASSISTANT",
+ "FLAG_AUDIBILITY_ENFORCED",
+ "FLAG_HW_HOTWORD",
+ "USAGE_NOTIFICATION_COMMUNICATION_REQUEST",
+ "USAGE_ASSISTANCE_ACCESSIBILITY",
+ "CONTENT_TYPE_MUSIC",
+ "SUPPRESSIBLE_NOTIFICATION",
+ "CONTENT_TYPE_SONIFICATION"
+ ]
+ },
+ "android/support/v7/mediarouter/R$id": {
+ "androidx/mediarouter/R$id": [
+ "mr_custom_control",
+ "mr_art",
+ "mr_name",
+ "mr_control_subtitle",
+ "mr_control_title",
+ "mr_control_playback_ctrl",
+ "mr_chooser_title",
+ "mr_group_expand_collapse",
+ "mr_close",
+ "mr_chooser_list",
+ "mr_volume_group_list",
+ "mr_expandable_area",
+ "mr_chooser_route_desc",
+ "mr_chooser_route_icon",
+ "mr_control_divider",
+ "volume_item_container",
+ "mr_chooser_route_name",
+ "mr_volume_control",
+ "mr_dialog_area",
+ "mr_default_control",
+ "mr_volume_slider",
+ "mr_volume_item_icon",
+ "mr_media_main_control",
+ "mr_playback_control",
+ "mr_control_title_container"
+ ]
+ },
+ "android/support/text/emoji/flatbuffer/Table": {
+ "androidx/text/emoji/flatbuffer/Table": [
+ "UTF8_CHARSET",
+ "bb",
+ "bb_pos",
+ "UTF8_DECODER",
+ "CHAR_BUFFER"
+ ]
+ },
+ "android/support/v17/leanback/R$id": {
+ "androidx/leanback/R$id": [
+ "paused",
+ "content_container",
+ "guidedactions_item_title",
+ "container_list",
+ "lb_parallax_source",
+ "description_dock",
+ "guidedactions_list",
+ "browse_grid_dock",
+ "details_overview_image",
+ "scale_frame",
+ "details_overview_right_panel",
+ "playback_progress",
+ "guidedactions_sub_list_background",
+ "guidedactions_root2",
+ "mediaItemDetails",
+ "button_start",
+ "title_badge",
+ "lb_search_text_editor",
+ "bottom_spacer",
+ "lb_slide_transition_value",
+ "info_field",
+ "mediaItemActionsContainer",
+ "thumbs_row",
+ "controls_container",
+ "guidedactions_list_background2",
+ "guidedactions_item_content",
+ "lb_action_button",
+ "guidedactions_item_icon",
+ "guidedactions_item_checkmark",
+ "lb_control_closed_captioning",
+ "browse_grid",
+ "title_orb",
+ "details_root",
+ "guidedactions_list_background",
+ "total_time",
+ "controls_card",
+ "lb_control_more_actions",
+ "lb_control_shuffle",
+ "mediaRowSeparator",
+ "image",
+ "lb_control_fast_rewind",
+ "row_header",
+ "controls_card_right_panel",
+ "description",
+ "background_imagein",
+ "title_text",
+ "details_fragment_root",
+ "playback_fragment_background",
+ "browse_frame",
+ "title",
+ "current_time",
+ "browse_headers_dock",
+ "guidedactions_sub_list",
+ "details_overview_actions_background",
+ "background_imageout",
+ "guidedactions_item_chevron",
+ "mediaItemDuration",
+ "lb_control_skip_previous",
+ "browse_container_dock",
+ "lb_control_skip_next",
+ "mediaListHeader",
+ "main_image",
+ "lb_control_thumbs_down",
+ "mediaItemNumberViewFlipper",
+ "details_overview",
+ "actionIcon",
+ "guidedactions_item_description",
+ "guidance_container",
+ "guidedstep_background",
+ "guidedactions_activator_item",
+ "transport_row",
+ "playback_controls_dock",
+ "page_container",
+ "lb_shadow_focused",
+ "icon",
+ "guidedactions_content",
+ "playing",
+ "lb_control_high_quality",
+ "guidance_description",
+ "details_frame",
+ "guidance_icon",
+ "control_bar",
+ "page_indicator",
+ "lb_search_bar_speech_orb",
+ "details_rows_dock",
+ "row_header_description",
+ "lb_control_thumbs_up",
+ "secondary_controls_dock",
+ "button",
+ "lb_shadow_impl",
+ "lb_focus_animator",
+ "spacer",
+ "lb_search_bar_badge",
+ "initial",
+ "lb_control_repeat",
+ "guidedactions_content2",
+ "guidance_title",
+ "message",
+ "action_fragment_root",
+ "lb_shadow_normal",
+ "guidedactions_root",
+ "lb_details_description_title",
+ "guidance_breadcrumb",
+ "action_fragment",
+ "background_container",
+ "lb_row_container_header_dock",
+ "details_background_view",
+ "browse_title_group",
+ "main_icon",
+ "video_surface_container",
+ "lb_search_frame",
+ "picker",
+ "lb_control_play_pause",
+ "lb_details_description_body",
+ "controls_dock",
+ "lb_control_picture_in_picture",
+ "lb_results_frame",
+ "grid_frame",
+ "lb_control_fast_forward",
+ "details_overview_description",
+ "mediaItemRow",
+ "mediaItemName",
+ "content_fragment",
+ "details_overview_actions",
+ "more_actions_dock",
+ "fade_out_edge",
+ "label",
+ "action_fragment_background",
+ "browse_headers",
+ "foreground_container",
+ "transitionPosition",
+ "lb_search_bar",
+ "error_frame",
+ "guidedactions_list2",
+ "lb_details_description_subtitle",
+ "lb_search_bar_items",
+ "mediaRowSelector",
+ "bar3",
+ "bar2",
+ "bar1",
+ "logo",
+ "search_orb",
+ "row_content",
+ "guidedstep_background_view_root"
+ ]
+ },
+ "android/support/v17/leanback/widget/picker/Picker$ViewHolder": {
+ "androidx/leanback/widget/picker/Picker$ViewHolder": [
+ "textView",
+ "itemView"
+ ]
+ },
+ "android/support/v4/media/MediaMetadataCompat": {
+ "androidx/media/MediaMetadataCompat": [
+ "METADATA_KEY_COMPILATION",
+ "METADATA_KEY_ART",
+ "METADATA_KEY_NUM_TRACKS",
+ "METADATA_KEY_ALBUM",
+ "METADATA_TYPE_TEXT",
+ "METADATA_TYPE_LONG",
+ "METADATA_KEY_TRACK_NUMBER",
+ "METADATA_KEY_ARTIST",
+ "METADATA_KEY_DOWNLOAD_STATUS",
+ "METADATA_KEY_AUTHOR",
+ "METADATA_KEY_DATE",
+ "METADATA_KEY_DISPLAY_TITLE",
+ "METADATA_KEY_DISPLAY_DESCRIPTION",
+ "METADATA_KEY_DURATION",
+ "METADATA_KEY_YEAR",
+ "METADATA_TYPE_BITMAP",
+ "METADATA_KEY_USER_RATING",
+ "METADATA_KEY_ALBUM_ART_URI",
+ "METADATA_KEY_MEDIA_URI",
+ "METADATA_KEY_MEDIA_ID",
+ "PREFERRED_BITMAP_ORDER",
+ "CREATOR",
+ "METADATA_KEY_BT_FOLDER_TYPE",
+ "METADATA_KEY_TITLE",
+ "METADATA_KEY_DISPLAY_ICON_URI",
+ "PREFERRED_URI_ORDER",
+ "METADATA_TYPE_RATING",
+ "METADATA_KEY_WRITER",
+ "PREFERRED_DESCRIPTION_ORDER",
+ "TAG",
+ "METADATA_KEY_COMPOSER",
+ "METADATA_KEY_ALBUM_ART",
+ "METADATA_KEY_GENRE",
+ "METADATA_KEY_ART_URI",
+ "METADATA_KEY_DISPLAY_ICON",
+ "METADATA_KEY_ALBUM_ARTIST",
+ "METADATA_KEY_ADVERTISEMENT",
+ "METADATA_KEYS_TYPE",
+ "METADATA_KEY_RATING",
+ "METADATA_KEY_DISPLAY_SUBTITLE",
+ "METADATA_KEY_DISC_NUMBER"
+ ]
+ },
+ "android/support/transition/Fade": {
+ "androidx/transition/Fade": [
+ "PROPNAME_TRANSITION_ALPHA",
+ "IN",
+ "LOG_TAG",
+ "OUT"
+ ]
+ },
+ "android/support/v17/leanback/R$layout": {
+ "androidx/leanback/R$layout": [
+ "lb_rows_fragment",
+ "lb_video_surface",
+ "lb_headers_fragment",
+ "lb_image_card_view_themed_badge_left",
+ "lb_search_orb",
+ "lb_details_fragment",
+ "lb_guidedstep_fragment",
+ "lb_image_card_view",
+ "lb_details_overview",
+ "lb_playback_controls",
+ "lb_guidedactions_datepicker_item",
+ "lb_image_card_view_themed_title",
+ "lb_picker_column",
+ "lb_playback_transport_controls_row",
+ "lb_image_card_view_themed_badge_right",
+ "lb_row_media_item",
+ "lb_row_container",
+ "lb_search_bar",
+ "lb_shadow",
+ "lb_error_fragment",
+ "lb_guidedbuttonactions",
+ "lb_browse_fragment",
+ "lb_guidedactions_item",
+ "lb_browse_title",
+ "lb_list_row",
+ "lb_section_header",
+ "lb_image_card_view_themed_content",
+ "lb_action_1_line",
+ "lb_media_list_header",
+ "lb_media_item_number_view_flipper",
+ "lb_vertical_grid_fragment",
+ "lb_divider",
+ "lb_details_description",
+ "lb_playback_now_playing_bars",
+ "lb_row_media_item_action",
+ "lb_fullwidth_details_overview",
+ "lb_picker",
+ "lb_guidedstep_background",
+ "lb_guidance",
+ "lb_picker_item",
+ "lb_speech_orb",
+ "lb_vertical_grid",
+ "lb_control_button_primary",
+ "lb_search_fragment",
+ "lb_playback_fragment",
+ "lb_picker_separator",
+ "lb_onboarding_fragment",
+ "lb_playback_controls_row",
+ "lb_row_header",
+ "lb_list_row_hovercard",
+ "lb_control_bar",
+ "lb_header",
+ "lb_guidedactions",
+ "lb_action_2_lines",
+ "lb_control_button_secondary",
+ "lb_title_view",
+ "lb_fullwidth_details_overview_logo"
+ ]
+ },
+ "android/support/coreui/BuildConfig": {
+ "androidx/coreui/BuildConfig": [
+ "APPLICATION_ID",
+ "DEBUG",
+ "FLAVOR",
+ "VERSION_CODE",
+ "VERSION_NAME",
+ "BUILD_TYPE"
+ ]
+ },
+ "android/support/v4/app/NotificationCompat": {
+ "androidx/app/NotificationCompat": [
+ "EXTRA_BACKGROUND_IMAGE_URI",
+ "FLAG_FOREGROUND_SERVICE",
+ "CATEGORY_SYSTEM",
+ "EXTRA_REMOTE_INPUT_HISTORY",
+ "EXTRA_LARGE_ICON",
+ "EXTRA_SHOW_WHEN",
+ "EXTRA_COMPACT_ACTIONS",
+ "CATEGORY_ERROR",
+ "GROUP_ALERT_CHILDREN",
+ "BADGE_ICON_LARGE",
+ "PRIORITY_DEFAULT",
+ "EXTRA_PEOPLE",
+ "STREAM_DEFAULT",
+ "VISIBILITY_PRIVATE",
+ "FLAG_ONLY_ALERT_ONCE",
+ "CATEGORY_EMAIL",
+ "DEFAULT_VIBRATE",
+ "CATEGORY_PROGRESS",
+ "FLAG_ONGOING_EVENT",
+ "EXTRA_PROGRESS_MAX",
+ "EXTRA_TITLE",
+ "CATEGORY_PROMO",
+ "EXTRA_SELF_DISPLAY_NAME",
+ "VISIBILITY_SECRET",
+ "PRIORITY_LOW",
+ "EXTRA_LARGE_ICON_BIG",
+ "CATEGORY_TRANSPORT",
+ "DEFAULT_SOUND",
+ "CATEGORY_CALL",
+ "EXTRA_SMALL_ICON",
+ "CATEGORY_RECOMMENDATION",
+ "EXTRA_PROGRESS",
+ "PRIORITY_HIGH",
+ "EXTRA_CONVERSATION_TITLE",
+ "GROUP_ALERT_SUMMARY",
+ "EXTRA_INFO_TEXT",
+ "BADGE_ICON_NONE",
+ "EXTRA_BIG_TEXT",
+ "EXTRA_TEXT_LINES",
+ "EXTRA_PICTURE",
+ "PRIORITY_MIN",
+ "FLAG_HIGH_PRIORITY",
+ "COLOR_DEFAULT",
+ "PRIORITY_MAX",
+ "EXTRA_TEMPLATE",
+ "FLAG_LOCAL_ONLY",
+ "CATEGORY_ALARM",
+ "EXTRA_SUMMARY_TEXT",
+ "BADGE_ICON_SMALL",
+ "DEFAULT_ALL",
+ "CATEGORY_STATUS",
+ "CATEGORY_EVENT",
+ "GROUP_ALERT_ALL",
+ "EXTRA_SHOW_CHRONOMETER",
+ "DEFAULT_LIGHTS",
+ "VISIBILITY_PUBLIC",
+ "CATEGORY_SOCIAL",
+ "CATEGORY_MESSAGE",
+ "FLAG_INSISTENT",
+ "CATEGORY_REMINDER",
+ "EXTRA_AUDIO_CONTENTS_URI",
+ "CATEGORY_SERVICE",
+ "EXTRA_TITLE_BIG",
+ "FLAG_AUTO_CANCEL",
+ "EXTRA_MEDIA_SESSION",
+ "EXTRA_MESSAGES",
+ "EXTRA_TEXT",
+ "FLAG_SHOW_LIGHTS",
+ "FLAG_GROUP_SUMMARY",
+ "FLAG_NO_CLEAR",
+ "EXTRA_SUB_TEXT",
+ "EXTRA_PROGRESS_INDETERMINATE"
+ ]
+ },
+ "android/support/content/BuildConfig": {
+ "androidx/content/BuildConfig": [
+ "FLAVOR",
+ "APPLICATION_ID",
+ "DEBUG",
+ "VERSION_NAME",
+ "BUILD_TYPE",
+ "VERSION_CODE"
+ ]
+ },
+ "android/support/animation/AnimationHandler": {
+ "androidx/animation/AnimationHandler": [
+ "sAnimatorHandler",
+ "FRAME_DELAY_MS"
+ ]
+ },
+ "android/support/media/ExifInterface": {
+ "androidx/media/ExifInterface": [
+ "FLAG_FLASH_RED_EYE_SUPPORTED",
+ "sTagSetForCompatibility",
+ "TAG_CUSTOM_RENDERED",
+ "TAG_SENSITIVITY_TYPE",
+ "GAIN_CONTROL_HIGH_GAIN_UP",
+ "TAG_FOCAL_PLANE_Y_RESOLUTION",
+ "LIGHT_SOURCE_OTHER",
+ "TAG_GPS_TIMESTAMP",
+ "TAG_COMPRESSION",
+ "IFD_INTEROPERABILITY_TAGS",
+ "IFD_FORMAT_DOUBLE",
+ "TAG_PIXEL_Y_DIMENSION",
+ "TAG_GPS_IMG_DIRECTION_REF",
+ "JPEG_INTERCHANGE_FORMAT_LENGTH_TAG",
+ "FLIPPED_ROTATION_ORDER",
+ "LIGHT_SOURCE_WARM_WHITE_FLUORESCENT",
+ "LIGHT_SOURCE_UNKNOWN",
+ "WHITE_BALANCE_MANUAL",
+ "TAG_SUBSEC_TIME",
+ "FILE_SOURCE_DSC",
+ "IFD_FORMAT_SSHORT",
+ "MARKER",
+ "LONGITUDE_WEST",
+ "IMAGE_TYPE_UNKNOWN",
+ "METERING_MODE_SPOT",
+ "IMAGE_TYPE_CR2",
+ "TAG_GPS_DOP",
+ "MAX_THUMBNAIL_SIZE",
+ "SENSOR_TYPE_TWO_CHIP",
+ "TAG_GPS_TRACK",
+ "SENSITIVITY_TYPE_REI_AND_ISO",
+ "SENSOR_TYPE_ONE_CHIP",
+ "GPS_MEASUREMENT_NO_DIFFERENTIAL",
+ "ORIENTATION_ROTATE_90",
+ "TAG_WHITE_POINT",
+ "PEF_SIGNATURE",
+ "TAG_GPS_IMG_DIRECTION",
+ "ORIGINAL_RESOLUTION_IMAGE",
+ "METERING_MODE_CENTER_WEIGHT_AVERAGE",
+ "TAG_ORF_CAMERA_SETTINGS_IFD_POINTER",
+ "TAG_ISO_SPEED",
+ "IMAGE_TYPE_DNG",
+ "GAIN_CONTROL_NONE",
+ "LONGITUDE_EAST",
+ "IFD_TYPE_ORF_MAKER_NOTE",
+ "TAG_DEVICE_SETTING_DESCRIPTION",
+ "TAG_BRIGHTNESS_VALUE",
+ "TAG_GPS_MAP_DATUM",
+ "METERING_MODE_MULTI_SPOT",
+ "TAG_RW2_ISO",
+ "TAG_ORF_PREVIEW_IMAGE_START",
+ "LIGHT_SOURCE_FLUORESCENT",
+ "COLOR_SPACE_S_RGB",
+ "IMAGE_TYPE_SRW",
+ "FLAG_FLASH_RETURN_LIGHT_DETECTED",
+ "SUBJECT_DISTANCE_RANGE_DISTANT_VIEW",
+ "TAG_ISO_SPEED_LATITUDE_YYY",
+ "RAF_INFO_SIZE",
+ "TAG",
+ "ORIENTATION_NORMAL",
+ "TAG_SUB_IFD_POINTER",
+ "LIGHT_SOURCE_TUNGSTEN",
+ "RESOLUTION_UNIT_CENTIMETERS",
+ "ALTITUDE_ABOVE_SEA_LEVEL",
+ "BYTE_ALIGN_MM",
+ "METERING_MODE_OTHER",
+ "TAG_EXIF_IFD_POINTER",
+ "BYTE_ALIGN_II",
+ "TAG_GPS_TRACK_REF",
+ "SHARPNESS_NORMAL",
+ "FILE_SOURCE_OTHER",
+ "TAG_OECF",
+ "SENSOR_TYPE_COLOR_SEQUENTIAL",
+ "sFormatter",
+ "FLAG_FLASH_MODE_COMPULSORY_FIRING",
+ "GPS_SPEED_KNOTS",
+ "DATA_DEFLATE_ZIP",
+ "TAG_DNG_VERSION",
+ "IMAGE_TYPE_ARW",
+ "TAG_RELATED_SOUND_FILE",
+ "TAG_BODY_SERIAL_NUMBER",
+ "EXPOSURE_PROGRAM_NOT_DEFINED",
+ "SIGNATURE_CHECK_SIZE",
+ "JPEG_INTERCHANGE_FORMAT_TAG",
+ "TAG_RW2_SENSOR_RIGHT_BORDER",
+ "TAG_CAMARA_OWNER_NAME",
+ "TAG_SPATIAL_FREQUENCY_RESPONSE",
+ "COLOR_SPACE_UNCALIBRATED",
+ "EXPOSURE_PROGRAM_NORMAL",
+ "EXPOSURE_PROGRAM_SHUTTER_PRIORITY",
+ "TAG_THUMBNAIL_LENGTH",
+ "TAG_TRANSFER_FUNCTION",
+ "IMAGE_TYPE_RW2",
+ "TAG_RW2_SENSOR_LEFT_BORDER",
+ "TAG_CFA_PATTERN",
+ "TAG_THUMBNAIL_IMAGE_LENGTH",
+ "TAG_GPS_H_POSITIONING_ERROR",
+ "sGpsTimestampPattern",
+ "PEF_MAKER_NOTE_SKIP_SIZE",
+ "IFD_FORMAT_STRING",
+ "TAG_SUBJECT_DISTANCE",
+ "TAG_GPS_SPEED_REF",
+ "SENSITIVITY_TYPE_SOS_AND_REI_AND_ISO",
+ "TAG_ORIENTATION",
+ "TAG_PHOTOMETRIC_INTERPRETATION",
+ "LIGHT_SOURCE_DAYLIGHT",
+ "TAG_MODEL",
+ "IFD_TYPE_GPS",
+ "LIGHT_SOURCE_SHADE",
+ "Y_CB_CR_POSITIONING_CO_SITED",
+ "TAG_RAF_IMAGE_SIZE",
+ "IFD_FORMAT_BYTES_PER_FORMAT",
+ "SENSITIVITY_TYPE_SOS_AND_REI",
+ "TAG_Y_RESOLUTION",
+ "TAG_GPS_DIFFERENTIAL",
+ "EXPOSURE_MODE_AUTO",
+ "MARKER_SOS",
+ "MARKER_SOI",
+ "IFD_TYPE_PREVIEW",
+ "IMAGE_TYPE_RAF",
+ "IFD_FORMAT_SBYTE",
+ "ORIENTATION_FLIP_VERTICAL",
+ "TAG_LENS_SERIAL_NUMBER",
+ "TAG_FLASHPIX_VERSION",
+ "EXIF_ASCII_PREFIX",
+ "IFD_TYPE_ORF_IMAGE_PROCESSING",
+ "TAG_ORF_IMAGE_PROCESSING_IFD_POINTER",
+ "DATA_LOSSY_JPEG",
+ "TAG_GPS_SPEED",
+ "TAG_USER_COMMENT",
+ "TAG_SUBSEC_TIME_ORIGINAL",
+ "TAG_THUMBNAIL_IMAGE_WIDTH",
+ "IFD_FORMAT_UNDEFINED",
+ "RW2_SIGNATURE",
+ "ORF_MAKER_NOTE_HEADER_2",
+ "ORF_MAKER_NOTE_HEADER_1",
+ "TAG_WHITE_BALANCE",
+ "TAG_ISO_SPEED_LATITUDE_ZZZ",
+ "TAG_PHOTOGRAPHIC_SENSITIVITY",
+ "SCENE_CAPTURE_TYPE_LANDSCAPE",
+ "MARKER_COM",
+ "TAG_HAS_THUMBNAIL",
+ "TAG_EXPOSURE_TIME",
+ "TAG_GPS_SATELLITES",
+ "TAG_COLOR_SPACE",
+ "TAG_GPS_LATITUDE_REF",
+ "IMAGE_TYPE_JPEG",
+ "START_CODE",
+ "TAG_APERTURE_VALUE",
+ "TAG_BITS_PER_SAMPLE",
+ "TAG_DIGITAL_ZOOM_RATIO",
+ "METERING_MODE_PATTERN",
+ "TAG_SHUTTER_SPEED_VALUE",
+ "DATA_PACK_BITS_COMPRESSED",
+ "sExifPointerTagMap",
+ "EXPOSURE_PROGRAM_APERTURE_PRIORITY",
+ "TAG_SAMPLES_PER_PIXEL",
+ "TAG_FILE_SOURCE",
+ "LIGHT_SOURCE_DAY_WHITE_FLUORESCENT",
+ "IFD_EXIF_TAGS",
+ "TAG_GPS_INFO_IFD_POINTER",
+ "TAG_GAMMA",
+ "IMAGE_TYPE_ORF",
+ "TAG_GAIN_CONTROL",
+ "IFD_TYPE_EXIF",
+ "TAG_SUBJECT_AREA",
+ "FORMAT_CHUNKY",
+ "ASCII",
+ "ORF_IMAGE_PROCESSING_TAGS",
+ "TAG_ORF_THUMBNAIL_IMAGE",
+ "IMAGE_TYPE_PEF",
+ "IFD_TYPE_ORF_CAMERA_SETTINGS",
+ "EXPOSURE_MODE_MANUAL",
+ "TAG_GPS_DATESTAMP",
+ "IFD_FORMAT_SRATIONAL",
+ "TAG_SUBJECT_LOCATION",
+ "FILE_SOURCE_REFLEX_SCANNER",
+ "TAG_LENS_SPECIFICATION",
+ "LIGHT_SOURCE_DAYLIGHT_FLUORESCENT",
+ "TAG_COMPONENTS_CONFIGURATION",
+ "TAG_REFERENCE_BLACK_WHITE",
+ "IMAGE_TYPE_NEF",
+ "GAIN_CONTROL_HIGH_GAIN_DOWN",
+ "LIGHT_SOURCE_ISO_STUDIO_TUNGSTEN",
+ "ORIENTATION_TRANSVERSE",
+ "IFD_FORMAT_URATIONAL",
+ "EXPOSURE_PROGRAM_LANDSCAPE_MODE",
+ "IMAGE_TYPE_NRW",
+ "TAG_FLASH",
+ "RAF_SIGNATURE",
+ "EXPOSURE_PROGRAM_ACTION",
+ "TAG_PLANAR_CONFIGURATION",
+ "LIGHT_SOURCE_CLOUDY_WEATHER",
+ "FLAG_FLASH_FIRED",
+ "EXPOSURE_MODE_AUTO_BRACKET",
+ "ORIENTATION_TRANSPOSE",
+ "REDUCED_RESOLUTION_IMAGE",
+ "WHITE_BALANCE_AUTO",
+ "TAG_FOCAL_PLANE_RESOLUTION_UNIT",
+ "PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO",
+ "DATA_UNCOMPRESSED",
+ "MARKER_EOI",
+ "TAG_SUBSEC_TIME_DIGITIZED",
+ "TAG_THUMBNAIL_DATA",
+ "TAG_GPS_DEST_BEARING_REF",
+ "EXPOSURE_PROGRAM_PORTRAIT_MODE",
+ "TAG_GPS_ALTITUDE",
+ "DATA_JPEG",
+ "TAG_GPS_DEST_LATITUDE_REF",
+ "ALTITUDE_BELOW_SEA_LEVEL",
+ "TAG_F_NUMBER",
+ "SUBJECT_DISTANCE_RANGE_UNKNOWN",
+ "TAG_SPECTRAL_SENSITIVITY",
+ "SCENE_CAPTURE_TYPE_NIGHT",
+ "TAG_PIXEL_X_DIMENSION",
+ "TAG_DEFAULT_CROP_SIZE",
+ "LIGHT_SOURCE_D75",
+ "LIGHT_SOURCE_D65",
+ "GPS_MEASUREMENT_INTERRUPTED",
+ "TAG_GPS_DEST_DISTANCE",
+ "LIGHT_SOURCE_D50",
+ "LIGHT_SOURCE_D55",
+ "ORIENTATION_ROTATE_180",
+ "SATURATION_NORMAL",
+ "TAG_THUMBNAIL_OFFSET",
+ "RESOLUTION_UNIT_INCHES",
+ "ORF_CAMERA_SETTINGS_TAGS",
+ "IFD_FORMAT_BYTE",
+ "TAG_LENS_MAKE",
+ "JPEG_SIGNATURE",
+ "EXPOSURE_PROGRAM_MANUAL",
+ "EXPOSURE_PROGRAM_CREATIVE",
+ "SUBJECT_DISTANCE_RANGE_CLOSE_VIEW",
+ "TAG_MAX_APERTURE_VALUE",
+ "DEBUG",
+ "METERING_MODE_AVERAGE",
+ "RENDERED_PROCESS_NORMAL",
+ "LIGHT_SOURCE_STANDARD_LIGHT_B",
+ "LIGHT_SOURCE_STANDARD_LIGHT_C",
+ "LIGHT_SOURCE_STANDARD_LIGHT_A",
+ "TAG_ISO_SPEED_RATINGS",
+ "TAG_STANDARD_OUTPUT_SENSITIVITY",
+ "PHOTOMETRIC_INTERPRETATION_YCBCR",
+ "TAG_ARTIST",
+ "IFD_TYPE_THUMBNAIL",
+ "PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO",
+ "FLAG_FLASH_RETURN_LIGHT_NOT_DETECTED",
+ "TAG_FOCAL_PLANE_X_RESOLUTION",
+ "TAG_LIGHT_SOURCE",
+ "MARKER_SOF1",
+ "MARKER_SOF2",
+ "MARKER_SOF0",
+ "MARKER_SOF9",
+ "MARKER_SOF7",
+ "MARKER_SOF5",
+ "MARKER_SOF6",
+ "MARKER_SOF3",
+ "sExifTagMapsForWriting",
+ "SHARPNESS_SOFT",
+ "TAG_SCENE_TYPE",
+ "TAG_GPS_DEST_LONGITUDE",
+ "sNonZeroTimePattern",
+ "GPS_DIRECTION_MAGNETIC",
+ "EXIF_TAGS",
+ "TAG_GPS_AREA_INFORMATION",
+ "FLAG_FLASH_MODE_COMPULSORY_SUPPRESSION",
+ "IFD_THUMBNAIL_TAGS",
+ "IFD_FORMAT_ULONG",
+ "TAG_INTEROPERABILITY_IFD_POINTER",
+ "TAG_SUBFILE_TYPE",
+ "TAG_RW2_SENSOR_TOP_BORDER",
+ "TAG_INTEROPERABILITY_INDEX",
+ "GPS_MEASUREMENT_3D",
+ "GPS_DIRECTION_TRUE",
+ "GPS_MEASUREMENT_2D",
+ "sExifTagMapsForReading",
+ "TAG_JPEG_INTERCHANGE_FORMAT",
+ "LATITUDE_SOUTH",
+ "PHOTOMETRIC_INTERPRETATION_RGB",
+ "BITS_PER_SAMPLE_RGB",
+ "CONTRAST_HARD",
+ "SHARPNESS_HARD",
+ "LATITUDE_NORTH",
+ "TAG_CONTRAST",
+ "ORIENTATION_FLIP_HORIZONTAL",
+ "TAG_GPS_LONGITUDE",
+ "TAG_COMPRESSED_BITS_PER_PIXEL",
+ "TAG_METERING_MODE",
+ "BITS_PER_SAMPLE_GREYSCALE_1",
+ "BITS_PER_SAMPLE_GREYSCALE_2",
+ "TAG_ROWS_PER_STRIP",
+ "GPS_DISTANCE_MILES",
+ "TAG_MAKER_NOTE",
+ "SUBJECT_DISTANCE_RANGE_MACRO",
+ "GAIN_CONTROL_LOW_GAIN_DOWN",
+ "SATURATION_HIGH",
+ "SCENE_TYPE_DIRECTLY_PHOTOGRAPHED",
+ "LIGHT_SOURCE_WHITE_FLUORESCENT",
+ "TAG_SHARPNESS",
+ "GPS_DISTANCE_KILOMETERS",
+ "TAG_GPS_LATITUDE",
+ "TAG_RW2_SENSOR_BOTTOM_BORDER",
+ "WHITEBALANCE_AUTO",
+ "TAG_SCENE_CAPTURE_TYPE",
+ "TAG_STRIP_BYTE_COUNTS",
+ "TAG_GPS_LONGITUDE_REF",
+ "GPS_MEASUREMENT_IN_PROGRESS",
+ "ORIENTATION_UNDEFINED",
+ "RAF_OFFSET_TO_JPEG_IMAGE_OFFSET",
+ "TAG_SUBJECT_DISTANCE_RANGE",
+ "ROTATION_ORDER",
+ "TAG_GPS_STATUS",
+ "ORF_MAKER_NOTE_HEADER_1_SIZE",
+ "TAG_GPS_DEST_BEARING",
+ "TAG_Y_CB_CR_COEFFICIENTS",
+ "TAG_MAKE",
+ "IFD_TYPE_PEF",
+ "TAG_RESOLUTION_UNIT",
+ "TAG_IMAGE_DESCRIPTION",
+ "SENSOR_TYPE_NOT_DEFINED",
+ "ORF_MAKER_NOTE_HEADER_2_SIZE",
+ "IFD_FORMAT_IFD",
+ "TAG_SATURATION",
+ "TAG_FOCAL_LENGTH_IN_35MM_FILM",
+ "TAG_FOCAL_LENGTH",
+ "SENSITIVITY_TYPE_SOS_AND_ISO",
+ "TAG_EXIF_VERSION",
+ "TAG_ORF_PREVIEW_IMAGE_LENGTH",
+ "GPS_MEASUREMENT_DIFFERENTIAL_CORRECTED",
+ "IFD_FORMAT_SINGLE",
+ "CONTRAST_NORMAL",
+ "TAG_PRIMARY_CHROMATICITIES",
+ "TAG_LENS_MODEL",
+ "TAG_IMAGE_LENGTH",
+ "TAG_RW2_JPG_FROM_RAW",
+ "SATURATION_LOW",
+ "TAG_SOFTWARE",
+ "IFD_TIFF_TAGS",
+ "SENSITIVITY_TYPE_ISO_SPEED",
+ "TAG_GPS_PROCESSING_METHOD",
+ "TAG_X_RESOLUTION",
+ "LIGHT_SOURCE_COOL_WHITE_FLUORESCENT",
+ "DATA_HUFFMAN_COMPRESSED",
+ "SENSOR_TYPE_THREE_CHIP",
+ "TAG_IMAGE_WIDTH",
+ "METERING_MODE_PARTIAL",
+ "SENSOR_TYPE_COLOR_SEQUENTIAL_LINEAR",
+ "LIGHT_SOURCE_FINE_WEATHER",
+ "TAG_EXPOSURE_INDEX",
+ "TAG_STRIP_OFFSETS",
+ "TAG_EXPOSURE_PROGRAM",
+ "TAG_IMAGE_UNIQUE_ID",
+ "IFD_FORMAT_USHORT",
+ "TAG_GPS_VERSION_ID",
+ "CONTRAST_SOFT",
+ "TAG_DATETIME_DIGITIZED",
+ "EXIF_POINTER_TAGS",
+ "FLAG_FLASH_NO_FLASH_FUNCTION",
+ "IFD_FORMAT_NAMES",
+ "ORF_MAKER_NOTE_TAGS",
+ "TAG_EXPOSURE_BIAS_VALUE",
+ "TAG_GPS_DEST_LONGITUDE_REF",
+ "IFD_OFFSET",
+ "ORF_SIGNATURE_1",
+ "ORF_SIGNATURE_2",
+ "METERING_MODE_UNKNOWN",
+ "GPS_SPEED_KILOMETERS_PER_HOUR",
+ "FORMAT_PLANAR",
+ "MARKER_SOF10",
+ "MARKER_SOF11",
+ "MARKER_SOF13",
+ "MARKER_SOF14",
+ "MARKER_SOF15",
+ "IFD_FORMAT_SLONG",
+ "TAG_COPYRIGHT",
+ "TAG_GPS_DEST_DISTANCE_REF",
+ "TAG_GPS_MEASURE_MODE",
+ "Y_CB_CR_POSITIONING_CENTERED",
+ "TAG_Y_CB_CR_POSITIONING",
+ "GPS_DISTANCE_NAUTICAL_MILES",
+ "WHITEBALANCE_MANUAL",
+ "GAIN_CONTROL_LOW_GAIN_UP",
+ "IDENTIFIER_EXIF_APP1",
+ "DATA_JPEG_COMPRESSED",
+ "SCENE_CAPTURE_TYPE_PORTRAIT",
+ "GPS_SPEED_MILES_PER_HOUR",
+ "IFD_TYPE_PRIMARY",
+ "TAG_Y_CB_CR_SUB_SAMPLING",
+ "TAG_GPS_ALTITUDE_REF",
+ "SENSITIVITY_TYPE_SOS",
+ "TAG_SENSING_METHOD",
+ "TAG_ORF_ASPECT_FRAME",
+ "TAG_NEW_SUBFILE_TYPE",
+ "TAG_EXPOSURE_MODE",
+ "ORIENTATION_ROTATE_270",
+ "IFD_GPS_TAGS",
+ "RAF_JPEG_LENGTH_VALUE_SIZE",
+ "TAG_FLASH_ENERGY",
+ "TAG_RECOMMENDED_EXPOSURE_INDEX",
+ "SENSOR_TYPE_TRILINEAR",
+ "SCENE_CAPTURE_TYPE_STANDARD",
+ "PEF_TAGS",
+ "SENSITIVITY_TYPE_UNKNOWN",
+ "TAG_DATETIME",
+ "TAG_JPEG_INTERCHANGE_FORMAT_LENGTH",
+ "LIGHT_SOURCE_FLASH",
+ "FLAG_FLASH_MODE_AUTO",
+ "MARKER_APP1",
+ "SENSITIVITY_TYPE_REI",
+ "TAG_DATETIME_ORIGINAL",
+ "TAG_GPS_DEST_LATITUDE",
+ "FILE_SOURCE_TRANSPARENT_SCANNER",
+ "RENDERED_PROCESS_CUSTOM",
+ "IFD_TYPE_INTEROPERABILITY"
+ ]
+ },
+ "android/support/v4/widget/ViewDragHelper": {
+ "androidx/widget/ViewDragHelper": [
+ "DIRECTION_HORIZONTAL",
+ "TAG",
+ "INVALID_POINTER",
+ "EDGE_SIZE",
+ "EDGE_LEFT",
+ "STATE_IDLE",
+ "STATE_DRAGGING",
+ "EDGE_ALL",
+ "DIRECTION_ALL",
+ "EDGE_RIGHT",
+ "sInterpolator",
+ "EDGE_TOP",
+ "STATE_SETTLING",
+ "BASE_SETTLE_DURATION",
+ "EDGE_BOTTOM",
+ "MAX_SETTLE_DURATION",
+ "DIRECTION_VERTICAL"
+ ]
+ },
+ "android/support/design/widget/NavigationView": {
+ "androidx/design/widget/NavigationView": [
+ "EMPTY_STATE_SET",
+ "CHECKED_STATE_SET",
+ "PRESENTER_NAVIGATION_VIEW_ID",
+ "DISABLED_STATE_SET"
+ ]
+ },
+ "android/support/customtabs/ICustomTabsCallback$Stub": {
+ "androidx/browser/customtabs/ICustomTabsCallback$Stub": [
+ "TRANSACTION_onMessageChannelReady",
+ "TRANSACTION_onPostMessage",
+ "TRANSACTION_onNavigationEvent",
+ "TRANSACTION_onRelationshipValidationResult",
+ "TRANSACTION_extraCallback",
+ "DESCRIPTOR"
+ ]
+ },
+ "android/support/v7/media/MediaRouterJellybeanMr1$ActiveScanWorkaround": {
+ "androidx/media/MediaRouterJellybeanMr1$ActiveScanWorkaround": [
+ "WIFI_DISPLAY_SCAN_INTERVAL"
+ ]
+ },
+ "android/support/v17/leanback/widget/GridLayoutManager$LayoutParams": {
+ "androidx/leanback/widget/GridLayoutManager$LayoutParams": [
+ "bottomMargin",
+ "leftMargin",
+ "topMargin",
+ "width",
+ "height",
+ "rightMargin"
+ ]
+ },
+ "android/support/v7/cardview/R$styleable": {
+ "androidx/cardview/R$styleable": [
+ "CardView_contentPaddingRight",
+ "CardView",
+ "CardView_android_minWidth",
+ "CardView_cardCornerRadius",
+ "CardView_contentPaddingLeft",
+ "CardView_cardBackgroundColor",
+ "CardView_contentPadding",
+ "CardView_contentPaddingBottom",
+ "CardView_cardElevation",
+ "CardView_cardUseCompatPadding",
+ "CardView_contentPaddingTop",
+ "CardView_android_minHeight",
+ "CardView_cardPreventCornerOverlap",
+ "CardView_cardMaxElevation"
+ ]
+ },
+ "android/support/v17/leanback/widget/PlaybackControlsRow$ThumbsAction": {
+ "androidx/leanback/widget/PlaybackControlsRow$ThumbsAction": [
+ "INDEX_OUTLINE",
+ "OUTLINE",
+ "SOLID",
+ "INDEX_SOLID"
+ ]
+ },
+ "android/support/v4/media/session/IMediaSession$Stub": {
+ "androidx/media/session/IMediaSession$Stub": [
+ "TRANSACTION_playFromUri",
+ "TRANSACTION_playFromSearch",
+ "TRANSACTION_getRepeatMode",
+ "TRANSACTION_previous",
+ "TRANSACTION_getPlaybackState",
+ "TRANSACTION_adjustVolume",
+ "TRANSACTION_setShuffleMode",
+ "TRANSACTION_setVolumeTo",
+ "TRANSACTION_prepareFromSearch",
+ "TRANSACTION_removeQueueItemAt",
+ "TRANSACTION_playFromMediaId",
+ "TRANSACTION_getPackageName",
+ "TRANSACTION_sendCommand",
+ "TRANSACTION_isTransportControlEnabled",
+ "TRANSACTION_pause",
+ "DESCRIPTOR",
+ "TRANSACTION_rewind",
+ "TRANSACTION_getRatingType",
+ "TRANSACTION_prepareFromUri",
+ "TRANSACTION_getMetadata",
+ "TRANSACTION_addQueueItemAt",
+ "TRANSACTION_getQueueTitle",
+ "TRANSACTION_getLaunchPendingIntent",
+ "TRANSACTION_getQueue",
+ "TRANSACTION_registerCallbackListener",
+ "TRANSACTION_getShuffleMode",
+ "TRANSACTION_seekTo",
+ "TRANSACTION_prepareFromMediaId",
+ "TRANSACTION_setShuffleModeEnabledRemoved",
+ "TRANSACTION_removeQueueItem",
+ "TRANSACTION_setRepeatMode",
+ "TRANSACTION_getFlags",
+ "TRANSACTION_prepare",
+ "TRANSACTION_isShuffleModeEnabledRemoved",
+ "TRANSACTION_addQueueItem",
+ "TRANSACTION_isCaptioningEnabled",
+ "TRANSACTION_setCaptioningEnabled",
+ "TRANSACTION_rateWithExtras",
+ "TRANSACTION_stop",
+ "TRANSACTION_getVolumeAttributes",
+ "TRANSACTION_next",
+ "TRANSACTION_skipToQueueItem",
+ "TRANSACTION_rate",
+ "TRANSACTION_unregisterCallbackListener",
+ "TRANSACTION_play",
+ "TRANSACTION_getTag",
+ "TRANSACTION_sendMediaButton",
+ "TRANSACTION_sendCustomAction",
+ "TRANSACTION_fastForward",
+ "TRANSACTION_getExtras"
+ ]
+ },
+ "android/support/v4/provider/FontsContractCompat$Columns": {
+ "androidx/provider/FontsContractCompat$Columns": [
+ "TTC_INDEX",
+ "FILE_ID",
+ "RESULT_CODE",
+ "WEIGHT",
+ "ITALIC",
+ "VARIATION_SETTINGS",
+ "RESULT_CODE_OK",
+ "RESULT_CODE_MALFORMED_QUERY",
+ "RESULT_CODE_FONT_UNAVAILABLE",
+ "RESULT_CODE_FONT_NOT_FOUND"
+ ]
+ },
+ "android/support/v4/media/MediaBrowserProtocol": {
+ "androidx/media/MediaBrowserProtocol": [
+ "DATA_CALLING_UID",
+ "EXTRA_MESSENGER_BINDER",
+ "DATA_ROOT_HINTS",
+ "CLIENT_MSG_UNREGISTER_CALLBACK_MESSENGER",
+ "EXTRA_SERVICE_VERSION",
+ "SERVICE_VERSION_1",
+ "DATA_OPTIONS",
+ "CLIENT_MSG_DISCONNECT",
+ "EXTRA_SESSION_BINDER",
+ "SERVICE_VERSION_CURRENT",
+ "CLIENT_VERSION_CURRENT",
+ "EXTRA_CLIENT_VERSION",
+ "CLIENT_VERSION_1",
+ "CLIENT_MSG_GET_MEDIA_ITEM",
+ "DATA_MEDIA_ITEM_LIST",
+ "DATA_MEDIA_SESSION_TOKEN",
+ "SERVICE_MSG_ON_CONNECT",
+ "DATA_RESULT_RECEIVER",
+ "CLIENT_MSG_SEND_CUSTOM_ACTION",
+ "CLIENT_MSG_CONNECT",
+ "SERVICE_MSG_ON_CONNECT_FAILED",
+ "SERVICE_MSG_ON_LOAD_CHILDREN",
+ "DATA_MEDIA_ITEM_ID",
+ "DATA_CALLBACK_TOKEN",
+ "DATA_SEARCH_QUERY",
+ "DATA_CUSTOM_ACTION_EXTRAS",
+ "CLIENT_MSG_SEARCH",
+ "DATA_SEARCH_EXTRAS",
+ "CLIENT_MSG_ADD_SUBSCRIPTION",
+ "DATA_CUSTOM_ACTION",
+ "CLIENT_MSG_REGISTER_CALLBACK_MESSENGER",
+ "DATA_PACKAGE_NAME",
+ "CLIENT_MSG_REMOVE_SUBSCRIPTION"
+ ]
+ },
+ "android/support/v17/leanback/R$color": {
+ "androidx/leanback/R$color": [
+ "lb_error_background_color_opaque",
+ "lb_playback_controls_background_dark",
+ "lb_default_brand_color_dark",
+ "lb_error_background_color_translucent",
+ "lb_background_protection",
+ "lb_speech_orb_recording",
+ "lb_default_brand_color",
+ "lb_page_indicator_dot",
+ "lb_search_bar_hint",
+ "lb_playback_progress_color_no_theme",
+ "lb_speech_orb_not_recording",
+ "lb_search_bar_text_speech_mode",
+ "lb_view_dim_mask_color",
+ "lb_playback_controls_background_light",
+ "lb_playback_media_row_highlight_color",
+ "lb_default_search_color",
+ "lb_playback_icon_highlight_no_theme",
+ "lb_search_bar_hint_speech_mode",
+ "lb_page_indicator_arrow_shadow",
+ "lb_speech_orb_not_recording_icon",
+ "lb_speech_orb_not_recording_pulsed",
+ "lb_search_bar_text",
+ "lb_page_indicator_arrow_background"
+ ]
+ },
+ "android/support/transition/ViewGroupUtilsApi18": {
+ "androidx/transition/ViewGroupUtilsApi18": [
+ "sSuppressLayoutMethod",
+ "TAG",
+ "sSuppressLayoutMethodFetched"
+ ]
+ },
+ "android/support/v4/text/TextDirectionHeuristicsCompat": {
+ "androidx/text/TextDirectionHeuristicsCompat": [
+ "STATE_UNKNOWN",
+ "RTL",
+ "LOCALE",
+ "ANYRTL_LTR",
+ "LTR",
+ "FIRSTSTRONG_RTL",
+ "FIRSTSTRONG_LTR",
+ "STATE_TRUE",
+ "STATE_FALSE"
+ ]
+ },
+ "android/support/v7/widget/ListViewCompat": {
+ "androidx/widget/ListViewCompat": [
+ "INVALID_POSITION",
+ "NO_POSITION",
+ "STATE_SET_NOTHING"
+ ]
+ },
+ "android/support/v17/leanback/app/GuidedStepSupportFragment": {
+ "androidx/leanback/app/GuidedStepSupportFragment": [
+ "SLIDE_FROM_BOTTOM",
+ "SLIDE_FROM_SIDE",
+ "EXTRA_BUTTON_ACTION_PREFIX",
+ "TAG_LEAN_BACK_ACTIONS_FRAGMENT",
+ "ENTRY_NAME_ENTRANCE",
+ "DEBUG",
+ "UI_STYLE_DEFAULT",
+ "UI_STYLE_REPLACE",
+ "IS_FRAMEWORK_FRAGMENT",
+ "UI_STYLE_ACTIVITY_ROOT",
+ "EXTRA_UI_STYLE",
+ "UI_STYLE_ENTRANCE",
+ "entranceTransitionType",
+ "TAG",
+ "ENTRY_NAME_REPLACE",
+ "EXTRA_ACTION_PREFIX"
+ ]
+ },
+ "android/support/v7/media/MediaRouter$GlobalMediaRouter$CallbackHandler": {
+ "androidx/media/MediaRouter$GlobalMediaRouter$CallbackHandler": [
+ "MSG_TYPE_MASK",
+ "MSG_PROVIDER_REMOVED",
+ "MSG_ROUTE_SELECTED",
+ "MSG_ROUTE_VOLUME_CHANGED",
+ "MSG_PROVIDER_ADDED",
+ "MSG_TYPE_ROUTE",
+ "MSG_ROUTE_REMOVED",
+ "MSG_ROUTE_UNSELECTED",
+ "MSG_TYPE_PROVIDER",
+ "MSG_PROVIDER_CHANGED",
+ "MSG_ROUTE_ADDED",
+ "MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED",
+ "MSG_ROUTE_CHANGED"
+ ]
+ },
+ "android/support/v7/view/menu/ActionMenuItem": {
+ "androidx/view/menu/ActionMenuItem": [
+ "EXCLUSIVE",
+ "CHECKED",
+ "ENABLED",
+ "CHECKABLE",
+ "NO_ICON",
+ "HIDDEN"
+ ]
+ },
+ "android/support/v4/app/NotificationCompat$WearableExtender": {
+ "androidx/app/NotificationCompat$WearableExtender": [
+ "SCREEN_TIMEOUT_LONG",
+ "KEY_FLAGS",
+ "KEY_DISMISSAL_ID",
+ "SIZE_LARGE",
+ "KEY_GRAVITY",
+ "KEY_CONTENT_ICON",
+ "FLAG_START_SCROLL_BOTTOM",
+ "DEFAULT_FLAGS",
+ "DEFAULT_CONTENT_ICON_GRAVITY",
+ "FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE",
+ "UNSET_ACTION_INDEX",
+ "DEFAULT_GRAVITY",
+ "FLAG_HINT_SHOW_BACKGROUND_ONLY",
+ "SIZE_XSMALL",
+ "KEY_CUSTOM_CONTENT_HEIGHT",
+ "FLAG_HINT_AVOID_BACKGROUND_CLIPPING",
+ "SIZE_DEFAULT",
+ "KEY_BACKGROUND",
+ "FLAG_BIG_PICTURE_AMBIENT",
+ "SCREEN_TIMEOUT_SHORT",
+ "SIZE_FULL_SCREEN",
+ "KEY_ACTIONS",
+ "EXTRA_WEARABLE_EXTENSIONS",
+ "KEY_CONTENT_ACTION_INDEX",
+ "FLAG_HINT_CONTENT_INTENT_LAUNCHES_ACTIVITY",
+ "KEY_CONTENT_ICON_GRAVITY",
+ "KEY_DISPLAY_INTENT",
+ "SIZE_SMALL",
+ "KEY_CUSTOM_SIZE_PRESET",
+ "KEY_HINT_SCREEN_TIMEOUT",
+ "FLAG_HINT_HIDE_ICON",
+ "KEY_BRIDGE_TAG",
+ "SIZE_MEDIUM",
+ "KEY_PAGES"
+ ]
+ },
+ "android/support/design/R$styleable": {
+ "androidx/design/R$styleable": [
+ "TabLayout_tabSelectedTextColor",
+ "BottomSheetBehavior_Layout_behavior_peekHeight",
+ "TextInputLayout_counterOverflowTextAppearance",
+ "BottomNavigationView_itemTextColor",
+ "ScrimInsetsFrameLayout_insetForeground",
+ "TabItem_android_icon",
+ "CoordinatorLayout",
+ "TextInputLayout_counterTextAppearance",
+ "TabLayout_tabMode",
+ "TextInputLayout_hintAnimationEnabled",
+ "TextInputLayout_passwordToggleTint",
+ "NavigationView_android_fitsSystemWindows",
+ "AppBarLayout_android_background",
+ "BottomSheetBehavior_Layout",
+ "FloatingActionButton_fabSize",
+ "TextInputLayout_android_hint",
+ "FloatingActionButton_elevation",
+ "TabItem_android_text",
+ "CollapsingToolbarLayout_expandedTitleTextAppearance",
+ "TextInputLayout_hintTextAppearance",
+ "BottomNavigationView_elevation",
+ "BottomNavigationView_itemIconTint",
+ "CollapsingToolbarLayout_collapsedTitleTextAppearance",
+ "TabLayout_tabPaddingEnd",
+ "TextInputLayout",
+ "TextInputLayout_counterEnabled",
+ "TextInputLayout_passwordToggleContentDescription",
+ "NavigationView_itemBackground",
+ "CollapsingToolbarLayout_expandedTitleMarginBottom",
+ "AppBarLayout_android_keyboardNavigationCluster",
+ "FloatingActionButton_Behavior_Layout",
+ "NavigationView_itemTextAppearance",
+ "TabLayout_tabBackground",
+ "TabLayout_tabContentStart",
+ "ScrollingViewBehavior_Layout",
+ "TabItem_android_layout",
+ "TextInputLayout_hintEnabled",
+ "CollapsingToolbarLayout_scrimVisibleHeightTrigger",
+ "TabLayout_tabPaddingTop",
+ "CoordinatorLayout_Layout_layout_anchorGravity",
+ "CoordinatorLayout_statusBarBackground",
+ "NavigationView",
+ "CollapsingToolbarLayout_expandedTitleMarginEnd",
+ "CoordinatorLayout_Layout_layout_anchor",
+ "TabLayout_tabMinWidth",
+ "TabLayout_tabPaddingStart",
+ "TextInputLayout_errorEnabled",
+ "TabLayout_tabMaxWidth",
+ "TabLayout_tabTextColor",
+ "CollapsingToolbarLayout_collapsedTitleGravity",
+ "BottomNavigationView",
+ "TabLayout_tabTextAppearance",
+ "NavigationView_itemIconTint",
+ "TabLayout_tabIndicatorColor",
+ "TabLayout",
+ "TabLayout_tabIndicatorHeight",
+ "NavigationView_headerLayout",
+ "CoordinatorLayout_Layout",
+ "BottomNavigationView_menu",
+ "CollapsingToolbarLayout_Layout_layout_collapseParallaxMultiplier",
+ "NavigationView_menu",
+ "TextInputLayout_passwordToggleDrawable",
+ "ScrimInsetsFrameLayout",
+ "CoordinatorLayout_Layout_layout_insetEdge",
+ "CollapsingToolbarLayout_titleEnabled",
+ "ForegroundLinearLayout",
+ "TabLayout_tabGravity",
+ "CollapsingToolbarLayout_contentScrim",
+ "ForegroundLinearLayout_android_foreground",
+ "CollapsingToolbarLayout_expandedTitleGravity",
+ "TextInputLayout_errorTextAppearance",
+ "TabLayout_tabPaddingBottom",
+ "CollapsingToolbarLayout",
+ "AppBarLayout",
+ "FloatingActionButton_pressedTranslationZ",
+ "FloatingActionButton_Behavior_Layout_behavior_autoHide",
+ "FloatingActionButton_useCompatPadding",
+ "NavigationView_android_maxWidth",
+ "CollapsingToolbarLayout_title",
+ "CollapsingToolbarLayout_Layout",
+ "SnackbarLayout_maxActionInlineWidth",
+ "ForegroundLinearLayout_android_foregroundGravity",
+ "AppBarLayout_android_touchscreenBlocksFocus",
+ "ScrollingViewBehavior_Layout_behavior_overlapTop",
+ "BottomSheetBehavior_Layout_behavior_skipCollapsed",
+ "CollapsingToolbarLayout_expandedTitleMarginTop",
+ "BottomNavigationView_itemBackground",
+ "FloatingActionButton_rippleColor",
+ "NavigationView_android_background",
+ "SnackbarLayout_elevation",
+ "TextInputLayout_android_textColorHint",
+ "NavigationView_itemTextColor",
+ "BottomSheetBehavior_Layout_behavior_hideable",
+ "AppBarLayout_Layout_layout_scrollInterpolator",
+ "FloatingActionButton_backgroundTint",
+ "AppBarLayout_Layout_layout_scrollFlags",
+ "CollapsingToolbarLayout_Layout_layout_collapseMode",
+ "TabLayout_tabPadding",
+ "FloatingActionButton_backgroundTintMode",
+ "CoordinatorLayout_Layout_layout_behavior",
+ "CoordinatorLayout_Layout_android_layout_gravity",
+ "AppBarLayout_elevation",
+ "ForegroundLinearLayout_foregroundInsidePadding",
+ "TabItem",
+ "AppBarLayout_expanded",
+ "FloatingActionButton",
+ "TextInputLayout_passwordToggleTintMode",
+ "SnackbarLayout_android_maxWidth",
+ "TextInputLayout_passwordToggleEnabled",
+ "CollapsingToolbarLayout_expandedTitleMargin",
+ "NavigationView_elevation",
+ "FloatingActionButton_borderWidth",
+ "CoordinatorLayout_Layout_layout_keyline",
+ "SnackbarLayout",
+ "CollapsingToolbarLayout_toolbarId",
+ "CoordinatorLayout_keylines",
+ "CollapsingToolbarLayout_scrimAnimationDuration",
+ "TextInputLayout_counterMaxLength",
+ "CoordinatorLayout_Layout_layout_dodgeInsetEdges",
+ "AppBarLayout_Layout",
+ "CollapsingToolbarLayout_statusBarScrim",
+ "CollapsingToolbarLayout_expandedTitleMarginStart"
+ ]
+ },
+ "android/support/text/emoji/MetadataListReader": {
+ "androidx/text/emoji/MetadataListReader": [
+ "META_TABLE_NAME",
+ "EMJI_TAG_DEPRECATED",
+ "EMJI_TAG"
+ ]
+ },
+ "android/support/v4/widget/DrawerLayout": {
+ "androidx/widget/DrawerLayout": [
+ "TAG",
+ "DRAWER_ELEVATION",
+ "SET_DRAWER_SHADOW_FROM_ELEVATION",
+ "STATE_DRAGGING",
+ "MIN_FLING_VELOCITY",
+ "TOUCH_SLOP_SENSITIVITY",
+ "LOCK_MODE_UNDEFINED",
+ "MIN_DRAWER_MARGIN",
+ "STATE_IDLE",
+ "THEME_ATTRS",
+ "LOCK_MODE_LOCKED_OPEN",
+ "ALLOW_EDGE_LOCK",
+ "CAN_HIDE_DESCENDANTS",
+ "CHILDREN_DISALLOW_INTERCEPT",
+ "PEEK_DELAY",
+ "LOCK_MODE_UNLOCKED",
+ "DEFAULT_SCRIM_COLOR",
+ "STATE_SETTLING",
+ "LOCK_MODE_LOCKED_CLOSED",
+ "LAYOUT_ATTRS"
+ ]
+ },
+ "android/support/v4/content/ModernAsyncTask": {
+ "androidx/content/ModernAsyncTask": [
+ "MESSAGE_POST_RESULT",
+ "MESSAGE_POST_PROGRESS",
+ "sDefaultExecutor",
+ "KEEP_ALIVE",
+ "sThreadFactory",
+ "sPoolWorkQueue",
+ "THREAD_POOL_EXECUTOR",
+ "CORE_POOL_SIZE",
+ "MAXIMUM_POOL_SIZE",
+ "sHandler",
+ "LOG_TAG"
+ ]
+ },
+ "android/support/v7/media/MediaControlIntent": {
+ "androidx/media/MediaControlIntent": [
+ "EXTRA_SESSION_STATUS_UPDATE_RECEIVER",
+ "CATEGORY_REMOTE_PLAYBACK",
+ "ACTION_START_SESSION",
+ "ACTION_PLAY",
+ "ACTION_SEEK",
+ "ERROR_UNSUPPORTED_OPERATION",
+ "ERROR_INVALID_ITEM_ID",
+ "ACTION_ENQUEUE",
+ "ACTION_SEND_MESSAGE",
+ "EXTRA_ITEM_CONTENT_POSITION",
+ "ERROR_UNKNOWN",
+ "ACTION_STOP",
+ "CATEGORY_LIVE_VIDEO",
+ "EXTRA_ITEM_STATUS_UPDATE_RECEIVER",
+ "EXTRA_ITEM_METADATA",
+ "EXTRA_SESSION_ID",
+ "EXTRA_MESSAGE",
+ "EXTRA_ITEM_HTTP_HEADERS",
+ "CATEGORY_LIVE_AUDIO",
+ "ACTION_END_SESSION",
+ "EXTRA_MESSAGE_RECEIVER",
+ "ACTION_GET_SESSION_STATUS",
+ "ACTION_REMOVE",
+ "EXTRA_ITEM_STATUS",
+ "EXTRA_ERROR_CODE",
+ "ACTION_GET_STATUS",
+ "ERROR_INVALID_SESSION_ID",
+ "EXTRA_SESSION_STATUS",
+ "EXTRA_ITEM_ID",
+ "ACTION_RESUME",
+ "ACTION_PAUSE"
+ ]
+ },
+ "android/support/design/widget/CoordinatorLayout$LayoutParams": {
+ "androidx/design/widget/CoordinatorLayout$LayoutParams": [
+ "keyline",
+ "topMargin",
+ "leftMargin",
+ "anchorGravity",
+ "bottomMargin",
+ "rightMargin",
+ "height",
+ "gravity",
+ "dodgeInsetEdges",
+ "insetEdge"
+ ]
+ },
+ "android/support/design/internal/NavigationMenuPresenter$NormalViewHolder": {
+ "androidx/design/internal/NavigationMenuPresenter$NormalViewHolder": [
+ "itemView"
+ ]
+ },
+ "android/support/v7/recyclerview/R$styleable": {
+ "androidx/recyclerview/R$styleable": [
+ "RecyclerView_fastScrollHorizontalThumbDrawable",
+ "RecyclerView_fastScrollVerticalTrackDrawable",
+ "RecyclerView_android_descendantFocusability",
+ "RecyclerView_spanCount",
+ "RecyclerView_stackFromEnd",
+ "RecyclerView_reverseLayout",
+ "RecyclerView_fastScrollVerticalThumbDrawable",
+ "RecyclerView_layoutManager",
+ "RecyclerView_android_orientation",
+ "RecyclerView",
+ "RecyclerView_fastScrollEnabled",
+ "RecyclerView_fastScrollHorizontalTrackDrawable"
+ ]
+ },
+ "android/support/v4/app/ActionBarDrawerToggle": {
+ "androidx/app/ActionBarDrawerToggle": [
+ "TAG",
+ "ID_HOME",
+ "THEME_ATTRS",
+ "TOGGLE_DRAWABLE_OFFSET"
+ ]
+ },
+ "android/support/v7/widget/GridLayout$Axis": {
+ "androidx/widget/GridLayout$Axis": [
+ "backwardLinks",
+ "orderPreserved",
+ "trailingMargins",
+ "leadingMargins",
+ "locationsValid",
+ "groupBounds",
+ "hasWeights",
+ "groupBoundsValid",
+ "PENDING",
+ "arcsValid",
+ "trailingMarginsValid",
+ "arcs",
+ "locations",
+ "backwardLinksValid",
+ "leadingMarginsValid",
+ "maxIndex",
+ "horizontal",
+ "forwardLinksValid",
+ "definedCount",
+ "NEW",
+ "deltas",
+ "parentMax",
+ "parentMin",
+ "COMPLETE",
+ "hasWeightsValid",
+ "forwardLinks"
+ ]
+ },
+ "android/support/v4/app/BundleCompat$BundleCompatBaseImpl": {
+ "androidx/app/BundleCompat$BundleCompatBaseImpl": [
+ "sGetIBinderMethod",
+ "sGetIBinderMethodFetched",
+ "sPutIBinderMethodFetched",
+ "TAG",
+ "sPutIBinderMethod"
+ ]
+ },
+ "android/support/v7/app/AppCompatViewInflater": {
+ "androidx/app/AppCompatViewInflater": [
+ "sOnClickAttrs",
+ "sConstructorMap",
+ "sClassPrefixList",
+ "sConstructorSignature",
+ "LOG_TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/SearchBar": {
+ "androidx/leanback/widget/SearchBar": [
+ "FULL_RIGHT_VOLUME",
+ "DEBUG",
+ "DEFAULT_RATE",
+ "FULL_LEFT_VOLUME",
+ "DO_NOT_LOOP",
+ "DEFAULT_PRIORITY",
+ "TAG"
+ ]
+ },
+ "android/support/v7/appcompat/R$drawable": {
+ "androidx/appcompat/R$drawable": [
+ "abc_ic_ab_back_material",
+ "abc_text_select_handle_middle_mtrl_dark",
+ "abc_text_select_handle_left_mtrl_light",
+ "abc_textfield_activated_mtrl_alpha",
+ "abc_text_select_handle_left_mtrl_dark",
+ "abc_text_cursor_material",
+ "abc_text_select_handle_right_mtrl_light",
+ "abc_ratingbar_material",
+ "abc_ic_menu_share_mtrl_alpha",
+ "abc_ratingbar_small_material",
+ "abc_ic_menu_paste_mtrl_am_alpha",
+ "abc_textfield_search_default_mtrl_alpha",
+ "abc_menu_hardkey_panel_mtrl_mult",
+ "abc_text_select_handle_right_mtrl_dark",
+ "abc_dialog_material_background",
+ "abc_ratingbar_indicator_material",
+ "abc_btn_colored_material",
+ "abc_edit_text_material",
+ "abc_btn_borderless_material",
+ "abc_btn_check_material",
+ "abc_ab_share_pack_mtrl_alpha",
+ "abc_tab_indicator_material",
+ "abc_spinner_textfield_background_material",
+ "abc_ic_commit_search_api_mtrl_alpha",
+ "abc_textfield_default_mtrl_alpha",
+ "abc_switch_track_mtrl_alpha",
+ "abc_seekbar_thumb_material",
+ "abc_list_divider_mtrl_alpha",
+ "abc_spinner_mtrl_am_alpha",
+ "abc_btn_radio_material",
+ "abc_cab_background_top_material",
+ "abc_cab_background_top_mtrl_alpha",
+ "abc_text_select_handle_middle_mtrl_light",
+ "abc_vector_test",
+ "abc_btn_default_mtrl_shape",
+ "abc_switch_thumb_material",
+ "abc_seekbar_track_material",
+ "abc_popup_background_mtrl_mult",
+ "abc_seekbar_tick_mark_material",
+ "abc_ic_menu_copy_mtrl_am_alpha",
+ "abc_ic_menu_selectall_mtrl_alpha",
+ "abc_textfield_search_activated_mtrl_alpha",
+ "abc_cab_background_internal_bg",
+ "abc_ic_menu_cut_mtrl_alpha",
+ "abc_textfield_search_material"
+ ]
+ },
+ "android/support/v17/leanback/widget/GuidedActionsStylist": {
+ "androidx/leanback/widget/GuidedActionsStylist": [
+ "sGuidedActionItemAlignFacet",
+ "TAG",
+ "VIEW_TYPE_DEFAULT",
+ "VIEW_TYPE_DATE_PICKER"
+ ]
+ },
+ "android/support/v17/leanback/R$dimen": {
+ "androidx/leanback/R$dimen": [
+ "lb_details_v2_align_pos_for_description",
+ "lb_details_overview_image_margin_vertical",
+ "lb_search_browse_rows_align_top",
+ "lb_material_shadow_normal_z",
+ "lb_details_v2_left",
+ "lb_details_v2_description_margin_top",
+ "lb_playback_controls_child_margin_bigger",
+ "lb_details_v2_actions_height",
+ "lb_playback_transport_thumbs_height",
+ "lb_details_rows_align_top",
+ "lb_control_icon_width",
+ "lb_page_indicator_dot_radius",
+ "lb_playback_controls_z",
+ "lb_error_under_image_baseline_margin",
+ "lb_browse_rows_margin_start",
+ "lb_playback_transport_thumbs_margin",
+ "lb_playback_transport_hero_thumbs_width",
+ "lb_details_description_under_subtitle_baseline_margin",
+ "lb_rounded_rect_corner_radius",
+ "lb_search_orb_unfocused_z",
+ "lb_playback_transport_progressbar_active_bar_height",
+ "picker_item_height",
+ "lb_page_indicator_arrow_shadow_offset",
+ "lb_page_indicator_arrow_gap",
+ "lb_details_description_title_baseline",
+ "lb_details_v2_blank_height",
+ "lb_search_bar_height",
+ "lb_playback_controls_child_margin_default",
+ "lb_details_v2_logo_margin_start",
+ "lb_browse_selected_row_top_padding",
+ "lb_details_cover_drawable_parallax_movement",
+ "lb_playback_transport_hero_thumbs_height",
+ "lb_details_overview_height_small",
+ "lb_material_shadow_focused_z",
+ "lb_playback_transport_thumbs_width",
+ "lb_browse_rows_margin_top",
+ "lb_action_padding_horizontal",
+ "lb_page_indicator_arrow_radius",
+ "lb_details_description_body_line_spacing",
+ "lb_browse_expanded_selected_row_top_padding",
+ "lb_browse_header_select_scale",
+ "lb_details_v2_align_pos_for_actions",
+ "lb_action_with_icon_padding_start",
+ "lb_page_indicator_arrow_shadow_radius",
+ "lb_playback_transport_progressbar_bar_height",
+ "lb_playback_controls_child_margin_biggest",
+ "lb_playback_controls_padding_bottom",
+ "lb_browse_expanded_row_no_hovercard_bottom_padding",
+ "lb_browse_header_select_duration",
+ "lb_playback_other_rows_center_to_bottom",
+ "lb_details_overview_image_margin_horizontal",
+ "lb_search_orb_focused_z",
+ "lb_error_under_message_baseline_margin",
+ "lb_playback_major_fade_translate_y",
+ "lb_page_indicator_dot_gap",
+ "lb_details_overview_height_large",
+ "lb_details_overview_actions_fade_size",
+ "lb_action_with_icon_padding_end",
+ "lb_details_description_title_line_spacing",
+ "lb_playback_minor_fade_translate_y",
+ "lb_playback_transport_progressbar_active_radius",
+ "lb_details_description_under_title_baseline_margin"
+ ]
+ },
+ "android/support/v7/appcompat/R$layout": {
+ "androidx/appcompat/R$layout": [
+ "abc_screen_toolbar",
+ "abc_screen_simple",
+ "abc_action_mode_close_item_material",
+ "abc_dialog_title_material",
+ "abc_list_menu_item_checkbox",
+ "abc_activity_chooser_view",
+ "abc_search_dropdown_item_icons_2line",
+ "support_simple_spinner_dropdown_item",
+ "abc_list_menu_item_radio",
+ "abc_popup_menu_header_item_layout",
+ "abc_list_menu_item_layout",
+ "tooltip",
+ "abc_action_menu_layout",
+ "abc_list_menu_item_icon",
+ "abc_action_menu_item_layout",
+ "abc_action_bar_title_item",
+ "abc_popup_menu_item_layout",
+ "abc_activity_chooser_view_list_item",
+ "abc_search_view",
+ "abc_expanded_menu_layout",
+ "abc_screen_simple_overlay_action_mode"
+ ]
+ },
+ "android/support/v7/appcompat/R$id": {
+ "androidx/appcompat/R$id": [
+ "submit_area",
+ "split_action_bar",
+ "scrollIndicatorUp",
+ "search_button",
+ "contentPanel",
+ "title",
+ "action_mode_close_button",
+ "custom",
+ "search_edit_frame",
+ "decor_content_parent",
+ "action_bar_title",
+ "submenuarrow",
+ "search_voice_btn",
+ "title_template",
+ "action_bar",
+ "action_bar_subtitle",
+ "alertTitle",
+ "default_activity_button",
+ "search_close_btn",
+ "textSpacerNoTitle",
+ "action_mode_bar_stub",
+ "titleDividerNoCustom",
+ "action_bar_container",
+ "parentPanel",
+ "shortcut",
+ "icon",
+ "search_src_text",
+ "activity_chooser_view_content",
+ "search_plate",
+ "customPanel",
+ "edit_query",
+ "action_menu_presenter",
+ "spacer",
+ "scrollIndicatorDown",
+ "scrollView",
+ "message",
+ "buttonPanel",
+ "topPanel",
+ "list_item",
+ "action_context_bar",
+ "search_go_btn",
+ "textSpacerNoButtons",
+ "search_mag_icon",
+ "action_bar_activity_content",
+ "expand_activities_button",
+ "image"
+ ]
+ },
+ "android/support/v7/widget/Toolbar$LayoutParams": {
+ "androidx/widget/Toolbar$LayoutParams": [
+ "gravity",
+ "EXPANDED",
+ "width",
+ "SYSTEM",
+ "leftMargin",
+ "CUSTOM",
+ "bottomMargin",
+ "rightMargin",
+ "topMargin",
+ "height"
+ ]
+ },
+ "android/support/v4/app/NotificationCompatJellybean": {
+ "androidx/app/NotificationCompatJellybean": [
+ "KEY_LABEL",
+ "sActionIntentField",
+ "KEY_ACTION_INTENT",
+ "sActionClass",
+ "sExtrasLock",
+ "KEY_REMOTE_INPUTS",
+ "KEY_ALLOWED_DATA_TYPES",
+ "sActionsLock",
+ "KEY_CHOICES",
+ "sExtrasField",
+ "EXTRA_DATA_ONLY_REMOTE_INPUTS",
+ "sActionTitleField",
+ "sActionIconField",
+ "KEY_EXTRAS",
+ "KEY_TITLE",
+ "sActionsAccessFailed",
+ "TAG",
+ "KEY_ICON",
+ "EXTRA_ALLOW_GENERATED_REPLIES",
+ "KEY_ALLOW_FREE_FORM_INPUT",
+ "KEY_DATA_ONLY_REMOTE_INPUTS",
+ "sExtrasFieldAccessFailed",
+ "KEY_RESULT_KEY",
+ "sActionsField"
+ ]
+ },
+ "android/support/v7/widget/GridLayout": {
+ "androidx/widget/GridLayout": [
+ "RIGHT",
+ "DEFAULT_COUNT",
+ "DEFAULT_ORIENTATION",
+ "ROW_ORDER_PRESERVED",
+ "TOP",
+ "LEADING",
+ "START",
+ "BASELINE",
+ "UNDEFINED",
+ "ALIGN_BOUNDS",
+ "CENTER",
+ "MAX_SIZE",
+ "ALIGNMENT_MODE",
+ "COLUMN_COUNT",
+ "ROW_COUNT",
+ "CAN_STRETCH",
+ "USE_DEFAULT_MARGINS",
+ "FILL",
+ "HORIZONTAL",
+ "DEFAULT_CONTAINER_MARGIN",
+ "LOG_PRINTER",
+ "ALIGN_MARGINS",
+ "VERTICAL",
+ "DEFAULT_ALIGNMENT_MODE",
+ "COLUMN_ORDER_PRESERVED",
+ "ORIENTATION",
+ "LEFT",
+ "TRAILING",
+ "DEFAULT_ORDER_PRESERVED",
+ "BOTTOM",
+ "END",
+ "DEFAULT_USE_DEFAULT_MARGINS",
+ "INFLEXIBLE",
+ "UNINITIALIZED_HASH",
+ "UNDEFINED_ALIGNMENT",
+ "NO_PRINTER"
+ ]
+ },
+ "android/support/wear/widget/BoxInsetLayout$LayoutParams": {
+ "androidx/wear/widget/BoxInsetLayout$LayoutParams": [
+ "BOX_ALL",
+ "BOX_LEFT",
+ "BOX_TOP",
+ "gravity",
+ "height",
+ "topMargin",
+ "rightMargin",
+ "bottomMargin",
+ "boxedEdges",
+ "BOX_RIGHT",
+ "width",
+ "leftMargin",
+ "BOX_NONE",
+ "BOX_BOTTOM"
+ ]
+ },
+ "android/support/design/widget/TabLayout": {
+ "androidx/design/widget/TabLayout": [
+ "GRAVITY_FILL",
+ "TAB_MIN_WIDTH_MARGIN",
+ "DEFAULT_HEIGHT_WITH_TEXT_ICON",
+ "ANIMATION_DURATION",
+ "INVALID_WIDTH",
+ "FIXED_WRAP_GUTTER_MIN",
+ "MOTION_NON_ADJACENT_OFFSET",
+ "DEFAULT_HEIGHT",
+ "MODE_FIXED",
+ "SELECTED_STATE_SET",
+ "MODE_SCROLLABLE",
+ "EMPTY_STATE_SET",
+ "sTabPool",
+ "GRAVITY_CENTER",
+ "DEFAULT_GAP_TEXT_ICON"
+ ]
+ },
+ "android/support/v4/view/MotionEventCompat": {
+ "androidx/view/MotionEventCompat": [
+ "ACTION_SCROLL",
+ "AXIS_RUDDER",
+ "AXIS_BRAKE",
+ "AXIS_TOOL_MINOR",
+ "AXIS_GENERIC_3",
+ "AXIS_GENERIC_4",
+ "AXIS_GENERIC_5",
+ "AXIS_GENERIC_6",
+ "AXIS_GENERIC_7",
+ "AXIS_GENERIC_8",
+ "AXIS_GENERIC_9",
+ "AXIS_GENERIC_1",
+ "AXIS_GENERIC_2",
+ "AXIS_DISTANCE",
+ "AXIS_ORIENTATION",
+ "AXIS_LTRIGGER",
+ "AXIS_HSCROLL",
+ "ACTION_POINTER_DOWN",
+ "AXIS_TILT",
+ "AXIS_WHEEL",
+ "AXIS_Y",
+ "AXIS_Z",
+ "AXIS_X",
+ "AXIS_SCROLL",
+ "AXIS_TOUCH_MAJOR",
+ "ACTION_HOVER_ENTER",
+ "AXIS_GAS",
+ "ACTION_HOVER_MOVE",
+ "ACTION_HOVER_EXIT",
+ "AXIS_THROTTLE",
+ "AXIS_HAT_X",
+ "AXIS_HAT_Y",
+ "AXIS_SIZE",
+ "ACTION_POINTER_INDEX_SHIFT",
+ "AXIS_RTRIGGER",
+ "AXIS_RELATIVE_X",
+ "AXIS_RELATIVE_Y",
+ "AXIS_RY",
+ "AXIS_RZ",
+ "AXIS_RX",
+ "AXIS_TOUCH_MINOR",
+ "ACTION_POINTER_INDEX_MASK",
+ "BUTTON_PRIMARY",
+ "AXIS_PRESSURE",
+ "AXIS_TOOL_MAJOR",
+ "AXIS_GENERIC_13",
+ "AXIS_GENERIC_12",
+ "AXIS_GENERIC_11",
+ "AXIS_GENERIC_10",
+ "AXIS_GENERIC_16",
+ "AXIS_GENERIC_15",
+ "AXIS_GENERIC_14",
+ "ACTION_POINTER_UP",
+ "ACTION_MASK",
+ "AXIS_VSCROLL"
+ ]
+ },
+ "android/support/v4/view/PagerTitleStrip": {
+ "androidx/widget/PagerTitleStrip": [
+ "ATTRS",
+ "SIDE_ALPHA",
+ "TEXT_ATTRS",
+ "TEXT_SPACING"
+ ]
+ },
+ "android/support/v7/preference/BuildConfig": {
+ "androidx/preference/BuildConfig": [
+ "APPLICATION_ID",
+ "FLAVOR",
+ "VERSION_CODE",
+ "DEBUG",
+ "VERSION_NAME",
+ "BUILD_TYPE"
+ ]
+ },
+ "android/support/v4/graphics/TypefaceCompatApi26Impl": {
+ "androidx/graphics/TypefaceCompatApi26Impl": [
+ "sAddFontFromAssetManager",
+ "sFreeze",
+ "TAG",
+ "RESOLVE_BY_FONT_TABLE",
+ "sFontFamily",
+ "ADD_FONT_FROM_ASSET_MANAGER_METHOD",
+ "sCreateFromFamiliesWithDefault",
+ "FONT_FAMILY_CLASS",
+ "ABORT_CREATION_METHOD",
+ "sFontFamilyCtor",
+ "CREATE_FROM_FAMILIES_WITH_DEFAULT_METHOD",
+ "sAbortCreation",
+ "ADD_FONT_FROM_BUFFER_METHOD",
+ "sAddFontFromBuffer",
+ "FREEZE_METHOD"
+ ]
+ },
+ "android/support/mediacompat/BuildConfig": {
+ "androidx/mediacompat/BuildConfig": [
+ "DEBUG",
+ "APPLICATION_ID",
+ "FLAVOR",
+ "VERSION_CODE",
+ "BUILD_TYPE",
+ "VERSION_NAME"
+ ]
+ },
+ "android/support/v7/app/AppCompatDelegate": {
+ "androidx/app/AppCompatDelegate": [
+ "sCompatVectorFromResourcesEnabled",
+ "MODE_NIGHT_FOLLOW_SYSTEM",
+ "MODE_NIGHT_YES",
+ "TAG",
+ "FEATURE_SUPPORT_ACTION_BAR_OVERLAY",
+ "sDefaultNightMode",
+ "MODE_NIGHT_NO",
+ "MODE_NIGHT_AUTO",
+ "FEATURE_ACTION_MODE_OVERLAY",
+ "FEATURE_SUPPORT_ACTION_BAR",
+ "MODE_NIGHT_UNSPECIFIED"
+ ]
+ },
+ "android/support/v7/cardview/BuildConfig": {
+ "androidx/cardview/BuildConfig": [
+ "VERSION_NAME",
+ "BUILD_TYPE",
+ "VERSION_CODE",
+ "DEBUG",
+ "APPLICATION_ID",
+ "FLAVOR"
+ ]
+ },
+ "android/support/v7/view/menu/ListMenuItemView": {
+ "androidx/view/menu/ListMenuItemView": [
+ "TAG"
+ ]
+ },
+ "android/support/media/instantvideo/preload/InstantVideoPreloadManager": {
+ "androidx/media/instantvideo/preload/InstantVideoPreloadManager": [
+ "DEBUG",
+ "sInstance",
+ "TAG",
+ "DEFAULT_MAX_VIDEO_COUNT"
+ ]
+ },
+ "android/support/graphics/drawable/AndroidResources": {
+ "androidx/graphics/drawable/AndroidResources": [
+ "STYLEABLE_ANIMATED_VECTOR_DRAWABLE_TARGET",
+ "STYLEABLE_VECTOR_DRAWABLE_CLIP_PATH_NAME",
+ "STYLEABLE_VECTOR_DRAWABLE_GROUP_NAME",
+ "STYLEABLE_ANIMATED_VECTOR_DRAWABLE_DRAWABLE",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_END",
+ "STYLEABLE_PATH_INTERPOLATOR",
+ "STYLEABLE_PROPERTY_VALUES_HOLDER_PROPERTY_NAME",
+ "STYLEABLE_KEYFRAME_INTERPOLATOR",
+ "STYLEABLE_KEYFRAME_FRACTION",
+ "STYLEABLE_ANIMATOR_REPEAT_MODE",
+ "STYLEABLE_ANIMATED_VECTOR_DRAWABLE_TARGET_NAME",
+ "STYLEABLE_VECTOR_DRAWABLE_VIEWPORT_WIDTH",
+ "FAST_OUT_LINEAR_IN",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_LINE_JOIN",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH_PATH_DATA",
+ "STYLEABLE_VECTOR_DRAWABLE_TINT_MODE",
+ "STYLEABLE_VECTOR_DRAWABLE_TINT",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH_NAME",
+ "STYLEABLE_KEYFRAME_VALUE_TYPE",
+ "STYLEABLE_PATH_INTERPOLATOR_PATH_DATA",
+ "STYLEABLE_ANIMATOR_START_OFFSET",
+ "STYLEABLE_VECTOR_DRAWABLE_GROUP",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_COLOR",
+ "STYLEABLE_ANIMATED_VECTOR_DRAWABLE_TARGET_ANIMATION",
+ "STYLEABLE_VECTOR_DRAWABLE_GROUP_ROTATION",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_WIDTH",
+ "STYLEABLE_PROPERTY_ANIMATOR_PROPERTY_Y_NAME",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_ALPHA",
+ "STYLEABLE_ANIMATOR_INTERPOLATOR",
+ "STYLEABLE_VECTOR_DRAWABLE_WIDTH",
+ "STYLEABLE_ANIMATOR_SET_ORDERING",
+ "STYLEABLE_ANIMATED_VECTOR_DRAWABLE",
+ "STYLEABLE_ANIMATOR_DURATION",
+ "STYLEABLE_VECTOR_DRAWABLE_ALPHA",
+ "STYLEABLE_VECTOR_DRAWABLE_HEIGHT",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH_FILL_ALPHA",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_MITER_LIMIT",
+ "STYLEABLE_PATH_INTERPOLATOR_CONTROL_X_2",
+ "STYLEABLE_PATH_INTERPOLATOR_CONTROL_X_1",
+ "LINEAR_OUT_SLOW_IN",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH_FILL_COLOR",
+ "STYLEABLE_PROPERTY_VALUES_HOLDER_VALUE_TO",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH",
+ "STYLEABLE_ANIMATOR_REMOVE_BEFORE_M_RELEASE",
+ "STYLEABLE_PATH_INTERPOLATOR_CONTROL_Y_1",
+ "STYLEABLE_PATH_INTERPOLATOR_CONTROL_Y_2",
+ "FAST_OUT_SLOW_IN",
+ "STYLEABLE_ANIMATOR_VALUE_FROM",
+ "STYLEABLE_ANIMATOR_REPEAT_COUNT",
+ "STYLEABLE_ANIMATOR_SET",
+ "STYLEABLE_PROPERTY_ANIMATOR_PATH_DATA",
+ "STYLEABLE_ANIMATOR_VALUE_TO",
+ "STYLEABLE_VECTOR_DRAWABLE_VIEWPORT_HEIGHT",
+ "STYLEABLE_KEYFRAME",
+ "STYLEABLE_VECTOR_DRAWABLE_TYPE_ARRAY",
+ "STYLEABLE_ANIMATOR_VALUE_TYPE",
+ "STYLEABLE_PROPERTY_VALUES_HOLDER",
+ "STYLEABLE_VECTOR_DRAWABLE_GROUP_PIVOT_X",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_OFFSET",
+ "STYLEABLE_VECTOR_DRAWABLE_GROUP_PIVOT_Y",
+ "STYLEABLE_VECTOR_DRAWABLE_GROUP_TRANSLATE_X",
+ "STYLEABLE_VECTOR_DRAWABLE_GROUP_TRANSLATE_Y",
+ "STYLEABLE_VECTOR_DRAWABLE_AUTO_MIRRORED",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_START",
+ "STYLEABLE_KEYFRAME_VALUE",
+ "STYLEABLE_PROPERTY_VALUES_HOLDER_VALUE_TYPE",
+ "STYLEABLE_PROPERTY_ANIMATOR_PROPERTY_NAME",
+ "STYLEABLE_VECTOR_DRAWABLE_CLIP_PATH",
+ "STYLEABLE_VECTOR_DRAWABLE_NAME",
+ "STYLEABLE_PROPERTY_VALUES_HOLDER_VALUE_FROM",
+ "STYLEABLE_VECTOR_DRAWABLE_GROUP_SCALE_Y",
+ "STYLEABLE_VECTOR_DRAWABLE_GROUP_SCALE_X",
+ "STYLEABLE_ANIMATOR",
+ "STYLEABLE_VECTOR_DRAWABLE_CLIP_PATH_PATH_DATA",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_LINE_CAP",
+ "STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_FILLTYPE",
+ "STYLEABLE_PROPERTY_ANIMATOR",
+ "STYLEABLE_PROPERTY_ANIMATOR_PROPERTY_X_NAME"
+ ]
+ },
+ "android/support/v7/app/ActionBar$LayoutParams": {
+ "androidx/app/ActionBar$LayoutParams": [
+ "gravity"
+ ]
+ },
+ "android/support/v7/widget/LinearLayoutCompat": {
+ "androidx/widget/LinearLayoutCompat": [
+ "VERTICAL_GRAVITY_COUNT",
+ "SHOW_DIVIDER_BEGINNING",
+ "HORIZONTAL",
+ "SHOW_DIVIDER_MIDDLE",
+ "SHOW_DIVIDER_NONE",
+ "INDEX_CENTER_VERTICAL",
+ "INDEX_TOP",
+ "INDEX_FILL",
+ "VERTICAL",
+ "INDEX_BOTTOM",
+ "SHOW_DIVIDER_END"
+ ]
+ },
+ "android/support/percent/PercentLayoutHelper$PercentMarginLayoutParams": {
+ "androidx/PercentLayoutHelper$PercentMarginLayoutParams": [
+ "topMargin",
+ "leftMargin",
+ "rightMargin",
+ "height",
+ "width",
+ "bottomMargin"
+ ]
+ },
+ "android/support/v17/leanback/widget/StreamingTextView": {
+ "androidx/leanback/widget/StreamingTextView": [
+ "STREAM_POSITION_PROPERTY",
+ "DOTS_FOR_STABLE",
+ "ANIMATE_DOTS_FOR_PENDING",
+ "STREAM_UPDATE_DELAY_MILLIS",
+ "DEBUG",
+ "TEXT_DOT_SCALE",
+ "DOTS_FOR_PENDING",
+ "SPLIT_PATTERN",
+ "TAG"
+ ]
+ },
+ "android/support/v7/view/SupportMenuInflater$MenuState": {
+ "androidx/view/SupportMenuInflater$MenuState": [
+ "itemListenerMethodName",
+ "itemActionViewClassName",
+ "itemContentDescription",
+ "itemEnabled",
+ "defaultItemChecked",
+ "itemCategoryOrder",
+ "itemTitle",
+ "groupCategory",
+ "itemIconTintMode",
+ "itemAdded",
+ "groupCheckable",
+ "itemNumericShortcut",
+ "groupVisible",
+ "itemNumericModifiers",
+ "itemTitleCondensed",
+ "defaultItemVisible",
+ "itemAlphabeticShortcut",
+ "itemShowAsAction",
+ "menu",
+ "defaultItemCheckable",
+ "itemActionProvider",
+ "itemCheckable",
+ "itemActionViewLayout",
+ "itemIconResId",
+ "itemVisible",
+ "itemTooltipText",
+ "defaultItemCategory",
+ "defaultGroupId",
+ "groupOrder",
+ "defaultItemId",
+ "itemActionProviderClassName",
+ "itemId",
+ "itemIconTintList",
+ "itemChecked",
+ "groupId",
+ "defaultItemEnabled",
+ "defaultItemOrder",
+ "itemAlphabeticModifiers",
+ "groupEnabled"
+ ]
+ },
+ "android/support/v4/view/InputDeviceCompat": {
+ "androidx/view/InputDeviceCompat": [
+ "SOURCE_CLASS_JOYSTICK",
+ "SOURCE_KEYBOARD",
+ "SOURCE_CLASS_MASK",
+ "SOURCE_CLASS_POINTER",
+ "SOURCE_ROTARY_ENCODER",
+ "SOURCE_TOUCHSCREEN",
+ "SOURCE_TOUCHPAD",
+ "SOURCE_STYLUS",
+ "SOURCE_CLASS_POSITION",
+ "SOURCE_UNKNOWN",
+ "SOURCE_DPAD",
+ "SOURCE_CLASS_BUTTON",
+ "SOURCE_JOYSTICK",
+ "SOURCE_ANY",
+ "SOURCE_TOUCH_NAVIGATION",
+ "SOURCE_TRACKBALL",
+ "SOURCE_MOUSE",
+ "SOURCE_HDMI",
+ "SOURCE_GAMEPAD",
+ "SOURCE_CLASS_TRACKBALL",
+ "SOURCE_CLASS_NONE"
+ ]
+ },
+ "android/support/v17/leanback/R$styleable": {
+ "androidx/leanback/R$styleable": [
+ "lbImageCardView_lbImageCardViewType",
+ "LeanbackTheme_browseRowsMarginTop",
+ "lbPlaybackControlsActionIcons_thumb_down_outline",
+ "lbSlide_android_interpolator",
+ "lbBaseCardView_cardType",
+ "lbResizingTextView_resizedPaddingAdjustmentBottom",
+ "lbBaseGridView_android_horizontalSpacing",
+ "lbResizingTextView_maintainLineSpacing",
+ "lbBaseGridView_verticalMargin",
+ "lbPlaybackControlsActionIcons_repeat_one",
+ "lbBaseGridView_horizontalMargin",
+ "lbHorizontalGridView_rowHeight",
+ "lbHorizontalGridView_numberOfRows",
+ "LeanbackTheme_browseRowsFadingEdgeLength",
+ "PagingIndicator_dotToDotGap",
+ "PagingIndicator_arrowColor",
+ "PagingIndicator",
+ "lbSearchOrbView_searchOrbColor",
+ "lbTimePicker_is24HourFormat",
+ "lbDatePicker",
+ "lbSearchOrbView_searchOrbBrightColor",
+ "lbDatePicker_android_maxDate",
+ "lbVerticalGridView_columnWidth",
+ "PagingIndicator_arrowRadius",
+ "lbTimePicker_useCurrentTime",
+ "LeanbackGuidedStepTheme",
+ "lbPlaybackControlsActionIcons_shuffle",
+ "lbBaseCardView_cardBackground",
+ "lbPlaybackControlsActionIcons",
+ "lbBaseCardView",
+ "lbPlaybackControlsActionIcons_play",
+ "lbSlide_lb_slideEdge",
+ "lbBaseCardView_extraVisibility",
+ "LeanbackTheme_overlayDimActiveLevel",
+ "lbResizingTextView_resizeTrigger",
+ "lbPlaybackControlsActionIcons_picture_in_picture",
+ "lbBaseGridView_android_gravity",
+ "lbBaseGridView_focusOutEnd",
+ "LeanbackTheme",
+ "lbPlaybackControlsActionIcons_thumb_up",
+ "PagingIndicator_dotBgColor",
+ "lbSearchOrbView_searchOrbIconColor",
+ "lbSearchOrbView",
+ "lbBaseGridView_focusOutFront",
+ "lbBaseCardView_infoVisibility",
+ "lbResizingTextView_resizedTextSize",
+ "lbPlaybackControlsActionIcons_skip_previous",
+ "PagingIndicator_dotToArrowGap",
+ "lbHorizontalGridView",
+ "lbDatePicker_datePickerFormat",
+ "lbVerticalGridView_numberOfColumns",
+ "lbSlide_android_duration",
+ "PagingIndicator_lbDotRadius",
+ "lbPlaybackControlsActionIcons_skip_next",
+ "lbSlide",
+ "lbSlide_android_startDelay",
+ "lbPlaybackControlsActionIcons_fast_forward",
+ "lbImageCardView",
+ "LeanbackTheme_browseRowsMarginStart",
+ "lbBaseCardView_Layout_layout_viewType",
+ "lbTimePicker",
+ "lbResizingTextView",
+ "lbImageCardView_infoAreaBackground",
+ "lbBaseCardView_Layout",
+ "lbPlaybackControlsActionIcons_repeat",
+ "lbPlaybackControlsActionIcons_rewind",
+ "lbBaseCardView_selectedAnimationDelay",
+ "lbBaseGridView_focusOutSideStart",
+ "lbBaseCardView_selectedAnimationDuration",
+ "lbBaseGridView_android_verticalSpacing",
+ "lbSearchOrbView_searchOrbIcon",
+ "lbPlaybackControlsActionIcons_pause",
+ "lbBaseGridView",
+ "PagingIndicator_arrowBgColor",
+ "lbVerticalGridView",
+ "lbDatePicker_android_minDate",
+ "lbPlaybackControlsActionIcons_thumb_up_outline",
+ "LeanbackTheme_overlayDimDimmedLevel",
+ "lbBaseGridView_focusOutSideEnd",
+ "lbPlaybackControlsActionIcons_high_quality",
+ "lbResizingTextView_resizedPaddingAdjustmentTop",
+ "lbBaseCardView_activatedAnimationDuration",
+ "lbPlaybackControlsActionIcons_closed_captioning",
+ "LeanbackTheme_overlayDimMaskColor",
+ "lbPlaybackControlsActionIcons_thumb_down",
+ "LeanbackGuidedStepTheme_guidedStepKeyline",
+ "lbBaseCardView_cardForeground"
+ ]
+ },
+ "android/support/v17/leanback/R$drawable": {
+ "androidx/leanback/R$drawable": [
+ "lb_ic_in_app_search",
+ "lb_text_dot_one",
+ "lb_ic_search_mic_out",
+ "lb_ic_search_mic",
+ "lb_background",
+ "lb_text_dot_two",
+ "lb_ic_nav_arrow",
+ "lb_ic_more"
+ ]
+ },
+ "android/support/v7/widget/RecyclerView$ViewHolder": {
+ "androidx/widget/RecyclerView$ViewHolder": [
+ "FLAG_NOT_RECYCLABLE",
+ "FLAG_INVALID",
+ "FULLUPDATE_PAYLOADS",
+ "FLAG_RETURNED_FROM_SCRAP",
+ "PENDING_ACCESSIBILITY_STATE_NOT_SET",
+ "FLAG_REMOVED",
+ "FLAG_TMP_DETACHED",
+ "FLAG_ADAPTER_POSITION_UNKNOWN",
+ "FLAG_SET_A11Y_ITEM_DELEGATE",
+ "itemView",
+ "FLAG_APPEARED_IN_PRE_LAYOUT",
+ "FLAG_ADAPTER_FULLUPDATE",
+ "FLAG_BOUNCED_FROM_HIDDEN_LIST",
+ "FLAG_IGNORE",
+ "FLAG_BOUND",
+ "FLAG_UPDATE",
+ "FLAG_MOVED"
+ ]
+ },
+ "android/support/v4/media/session/MediaSessionCompat$Token": {
+ "androidx/media/session/MediaSessionCompat$Token": [
+ "CREATOR"
+ ]
+ },
+ "android/support/v17/leanback/app/BrowseFragment$ExpandPreLayout": {
+ "androidx/leanback/app/BrowseFragment$ExpandPreLayout": [
+ "STATE_SECOND_DRAW",
+ "STATE_INIT",
+ "mainFragmentAdapter",
+ "STATE_FIRST_DRAW"
+ ]
+ },
+ "android/support/v13/app/FragmentTabHost$TabInfo": {
+ "androidx/app/FragmentTabHost$TabInfo": [
+ "fragment",
+ "args",
+ "tag",
+ "clss"
+ ]
+ },
+ "android/support/media/tv/Channel": {
+ "androidx/media/tv/Channel": [
+ "IS_SEARCHABLE",
+ "IS_SYSTEM_APPROVED",
+ "INVALID_INT_VALUE",
+ "INVALID_CHANNEL_ID",
+ "PROJECTION",
+ "IS_TRANSIENT",
+ "IS_BROWSABLE",
+ "IS_LOCKED"
+ ]
+ },
+ "android/support/v4/text/BidiFormatter$DirectionalityEstimator": {
+ "androidx/text/BidiFormatter$DirectionalityEstimator": [
+ "lastChar",
+ "DIR_TYPE_CACHE_SIZE",
+ "DIR_TYPE_CACHE",
+ "charIndex",
+ "isHtml",
+ "text",
+ "length"
+ ]
+ },
+ "android/support/v7/widget/AppCompatDrawableManager": {
+ "androidx/widget/AppCompatDrawableManager": [
+ "COLOR_FILTER_CACHE",
+ "TINT_COLOR_CONTROL_NORMAL",
+ "TAG",
+ "COLORFILTER_TINT_COLOR_CONTROL_NORMAL",
+ "COLORFILTER_COLOR_CONTROL_ACTIVATED",
+ "TINT_CHECKABLE_BUTTON_LIST",
+ "INSTANCE",
+ "TINT_COLOR_CONTROL_STATE_LIST",
+ "DEFAULT_MODE",
+ "DEBUG",
+ "COLORFILTER_COLOR_BACKGROUND_MULTIPLY",
+ "PLATFORM_VD_CLAZZ",
+ "SKIP_DRAWABLE_TAG"
+ ]
+ },
+ "android/support/media/tv/TvContractCompat": {
+ "androidx/media/tv/TvContractCompat": [
+ "PARAM_INPUT",
+ "PATH_CHANNEL",
+ "ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED",
+ "ACTION_REQUEST_CHANNEL_BROWSABLE",
+ "EXTRA_PREVIEW_PROGRAM_ID",
+ "PATH_RECORDED_PROGRAM",
+ "PATH_PASSTHROUGH",
+ "PARAM_CHANNEL",
+ "AUTHORITY",
+ "PARAM_START_TIME",
+ "PARAM_BROWSABLE_ONLY",
+ "EXTRA_DATA_TYPE",
+ "EXTRA_DEFAULT_VALUE",
+ "PARAM_END_TIME",
+ "EXTRA_WATCH_NEXT_PROGRAM_ID",
+ "PARAM_CANONICAL_GENRE",
+ "METHOD_GET_COLUMNS",
+ "PATH_PROGRAM",
+ "METHOD_ADD_COLUMN",
+ "PATH_PREVIEW_PROGRAM",
+ "PATH_WATCH_NEXT_PROGRAM",
+ "EXTRA_COLUMN_NAME",
+ "ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED",
+ "PERMISSION_READ_TV_LISTINGS",
+ "EXTRA_EXISTING_COLUMN_NAMES",
+ "ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT",
+ "EXTRA_PACKAGE_NAME",
+ "ACTION_CHANNEL_BROWSABLE_REQUESTED",
+ "EXTRA_CHANNEL_ID",
+ "ACTION_INITIALIZE_PROGRAMS"
+ ]
+ },
+ "android/support/v17/leanback/widget/GridLayoutManager$PendingMoveSmoothScroller": {
+ "androidx/leanback/widget/GridLayoutManager$PendingMoveSmoothScroller": [
+ "TARGET_UNDEFINED"
+ ]
+ },
+ "android/support/v7/media/RemoteControlClientCompat$PlaybackInfo": {
+ "androidx/media/RemoteControlClientCompat$PlaybackInfo": [
+ "volumeMax",
+ "playbackType",
+ "volume",
+ "volumeHandling",
+ "playbackStream"
+ ]
+ },
+ "android/support/v4/util/ArraySet": {
+ "androidx/util/ArraySet": [
+ "OBJECT",
+ "TAG",
+ "sTwiceBaseCacheSize",
+ "CACHE_SIZE",
+ "sBaseCacheSize",
+ "sTwiceBaseCache",
+ "BASE_SIZE",
+ "INT",
+ "sBaseCache",
+ "DEBUG"
+ ]
+ },
+ "android/support/v17/leanback/app/OnboardingFragment": {
+ "androidx/leanback/app/OnboardingFragment": [
+ "DESCRIPTION_START_DELAY_MS",
+ "TAG",
+ "HEADER_ANIMATION_DURATION_MS",
+ "HEADER_APPEAR_DELAY_MS",
+ "KEY_LOGO_ANIMATION_FINISHED",
+ "HEADER_DISAPPEAR_INTERPOLATOR",
+ "DEBUG",
+ "HEADER_APPEAR_INTERPOLATOR",
+ "KEY_ENTER_ANIMATION_FINISHED",
+ "KEY_CURRENT_PAGE_INDEX",
+ "sSlideDistance",
+ "LOGO_SPLASH_PAUSE_DURATION_MS",
+ "SLIDE_DISTANCE"
+ ]
+ },
+ "android/support/v17/leanback/R$string": {
+ "androidx/leanback/R$string": [
+ "lb_control_display_fast_forward_multiplier",
+ "lb_playback_controls_repeat_one",
+ "lb_playback_controls_thumb_up_outline",
+ "lb_playback_controls_thumb_up",
+ "lb_playback_controls_repeat_none",
+ "lb_guidedaction_finish_title",
+ "lb_control_display_rewind_multiplier",
+ "lb_playback_controls_closed_captioning_disable",
+ "lb_playback_controls_repeat_all",
+ "lb_playback_controls_pause",
+ "lb_playback_controls_thumb_down",
+ "lb_playback_controls_shuffle_enable",
+ "lb_playback_controls_rewind_multiplier",
+ "lb_guidedaction_continue_title",
+ "lb_playback_controls_shuffle_disable",
+ "lb_media_player_error",
+ "lb_playback_controls_hidden",
+ "lb_playback_controls_play",
+ "lb_guidedactions_item_unselected_description_text_alpha",
+ "lb_playback_controls_skip_next",
+ "lb_playback_controls_fast_forward",
+ "lb_playback_controls_high_quality_enable",
+ "lb_search_bar_hint_speech",
+ "lb_search_bar_hint_with_title_speech",
+ "lb_playback_controls_closed_captioning_enable",
+ "lb_playback_controls_shown",
+ "lb_guidedactions_item_disabled_description_text_alpha",
+ "lb_search_bar_hint",
+ "lb_playback_controls_fast_forward_multiplier",
+ "lb_playback_controls_picture_in_picture",
+ "lb_playback_controls_thumb_down_outline",
+ "lb_playback_controls_high_quality_disable",
+ "lb_playback_controls_rewind",
+ "lb_playback_controls_more_actions",
+ "lb_guidedactions_item_unselected_text_alpha",
+ "lb_guidedactions_item_disabled_text_alpha",
+ "lb_playback_controls_skip_previous",
+ "lb_search_bar_hint_with_title"
+ ]
+ },
+ "android/support/v7/preference/PreferenceInflater": {
+ "androidx/preference/PreferenceInflater": [
+ "EXTRA_TAG_NAME",
+ "INTENT_TAG_NAME",
+ "CONSTRUCTOR_MAP",
+ "TAG",
+ "CONSTRUCTOR_SIGNATURE"
+ ]
+ },
+ "android/support/constraint/R$styleable": {
+ "androidx/constraint/R$styleable": [
+ "ConstraintLayout_Layout_layout_constraintWidth_max",
+ "ConstraintLayout_Layout_layout_constraintWidth_min",
+ "ConstraintSet_layout_constraintDimensionRatio",
+ "ConstraintSet_android_transformPivotY",
+ "ConstraintSet_android_transformPivotX",
+ "ConstraintSet_layout_goneMarginRight",
+ "ConstraintLayout_Layout_layout_constraintGuide_percent",
+ "ConstraintLayout_Layout_layout_constraintLeft_toLeftOf",
+ "ConstraintSet_layout_goneMarginStart",
+ "ConstraintSet_android_orientation",
+ "ConstraintLayout_Layout_layout_constraintRight_toLeftOf",
+ "ConstraintSet_android_layout_marginBottom",
+ "ConstraintSet_layout_constraintBaseline_toBaselineOf",
+ "ConstraintSet_android_layout_height",
+ "ConstraintSet_layout_constraintRight_creator",
+ "ConstraintSet_layout_constraintWidth_max",
+ "ConstraintSet_layout_constraintEnd_toStartOf",
+ "ConstraintLayout_Layout_layout_constraintBottom_creator",
+ "ConstraintSet_android_visibility",
+ "ConstraintLayout_Layout_layout_constraintTop_toBottomOf",
+ "ConstraintSet_layout_constraintGuide_begin",
+ "ConstraintSet_layout_constraintWidth_min",
+ "ConstraintLayout_Layout_android_maxHeight",
+ "ConstraintSet_android_id",
+ "ConstraintSet_layout_constraintBottom_creator",
+ "ConstraintLayout_Layout_layout_optimizationLevel",
+ "ConstraintLayout_Layout_layout_constraintVertical_bias",
+ "ConstraintSet_layout_constraintHorizontal_bias",
+ "ConstraintSet_layout_constraintHeight_default",
+ "ConstraintSet",
+ "ConstraintLayout_Layout_layout_constraintBottom_toBottomOf",
+ "ConstraintLayout_Layout",
+ "ConstraintLayout_Layout_layout_constraintBaseline_creator",
+ "ConstraintLayout_Layout_layout_constraintVertical_chainStyle",
+ "ConstraintSet_android_rotationY",
+ "ConstraintSet_android_rotationX",
+ "ConstraintSet_android_alpha",
+ "ConstraintLayout_Layout_layout_constraintDimensionRatio",
+ "ConstraintLayout_Layout_android_orientation",
+ "ConstraintSet_layout_constraintLeft_creator",
+ "ConstraintSet_layout_goneMarginLeft",
+ "ConstraintSet_layout_constraintLeft_toLeftOf",
+ "ConstraintLayout_Layout_layout_constraintVertical_weight",
+ "ConstraintSet_layout_constraintStart_toStartOf",
+ "ConstraintLayout_Layout_layout_constraintHorizontal_chainStyle",
+ "ConstraintLayout_Layout_layout_constraintEnd_toEndOf",
+ "ConstraintSet_layout_editor_absoluteY",
+ "ConstraintSet_layout_editor_absoluteX",
+ "ConstraintLayout_Layout_layout_constraintEnd_toStartOf",
+ "ConstraintLayout_Layout_layout_constraintTop_toTopOf",
+ "ConstraintSet_android_layout_marginEnd",
+ "ConstraintLayout_Layout_layout_goneMarginLeft",
+ "ConstraintLayout_Layout_layout_constraintGuide_begin",
+ "ConstraintSet_layout_constraintGuide_end",
+ "ConstraintSet_android_translationZ",
+ "ConstraintSet_android_translationY",
+ "ConstraintSet_android_translationX",
+ "ConstraintSet_layout_constraintStart_toEndOf",
+ "ConstraintSet_layout_constraintRight_toRightOf",
+ "ConstraintSet_layout_constraintHeight_max",
+ "ConstraintSet_android_layout_marginTop",
+ "ConstraintSet_layout_constraintHeight_min",
+ "ConstraintSet_layout_constraintTop_creator",
+ "ConstraintLayout_Layout_layout_editor_absoluteX",
+ "ConstraintLayout_Layout_layout_editor_absoluteY",
+ "ConstraintLayout_Layout_layout_goneMarginTop",
+ "ConstraintSet_layout_goneMarginEnd",
+ "ConstraintSet_layout_constraintLeft_toRightOf",
+ "ConstraintLayout_Layout_layout_goneMarginBottom",
+ "ConstraintLayout_Layout_android_minHeight",
+ "ConstraintLayout_Layout_layout_constraintBaseline_toBaselineOf",
+ "ConstraintSet_android_layout_marginLeft",
+ "ConstraintSet_layout_constraintHorizontal_weight",
+ "ConstraintLayout_Layout_layout_goneMarginEnd",
+ "ConstraintSet_layout_constraintVertical_weight",
+ "ConstraintSet_layout_constraintBaseline_creator",
+ "ConstraintSet_layout_constraintVertical_bias",
+ "ConstraintSet_layout_goneMarginTop",
+ "ConstraintLayout_Layout_layout_constraintRight_creator",
+ "ConstraintSet_layout_constraintBottom_toTopOf",
+ "ConstraintLayout_Layout_layout_constraintWidth_default",
+ "ConstraintSet_android_layout_marginStart",
+ "ConstraintSet_android_layout_width",
+ "ConstraintSet_layout_constraintWidth_default",
+ "ConstraintLayout_Layout_layout_constraintBottom_toTopOf",
+ "ConstraintLayout_Layout_layout_constraintStart_toEndOf",
+ "ConstraintLayout_Layout_layout_constraintHorizontal_weight",
+ "ConstraintSet_android_layout_marginRight",
+ "ConstraintSet_layout_constraintBottom_toBottomOf",
+ "ConstraintSet_android_scaleX",
+ "ConstraintSet_android_scaleY",
+ "ConstraintLayout_Layout_layout_constraintRight_toRightOf",
+ "ConstraintSet_layout_constraintGuide_percent",
+ "ConstraintLayout_Layout_layout_constraintLeft_creator",
+ "ConstraintLayout_Layout_layout_constraintTop_creator",
+ "ConstraintSet_layout_constraintTop_toTopOf",
+ "ConstraintLayout_Layout_layout_goneMarginRight",
+ "ConstraintSet_layout_constraintEnd_toEndOf",
+ "ConstraintLayout_Layout_layout_constraintHeight_max",
+ "ConstraintLayout_Layout_constraintSet",
+ "ConstraintLayout_Layout_layout_constraintHeight_min",
+ "ConstraintLayout_Layout_layout_goneMarginStart",
+ "ConstraintSet_android_elevation",
+ "ConstraintSet_layout_constraintTop_toBottomOf",
+ "ConstraintLayout_Layout_layout_constraintLeft_toRightOf",
+ "ConstraintLayout_Layout_layout_constraintStart_toStartOf",
+ "ConstraintSet_layout_constraintHorizontal_chainStyle",
+ "ConstraintLayout_Layout_android_maxWidth",
+ "ConstraintLayout_Layout_layout_constraintHorizontal_bias",
+ "ConstraintLayout_Layout_layout_constraintHeight_default",
+ "ConstraintSet_layout_constraintRight_toLeftOf",
+ "ConstraintLayout_Layout_android_minWidth",
+ "ConstraintSet_layout_constraintVertical_chainStyle",
+ "ConstraintLayout_Layout_layout_constraintGuide_end",
+ "ConstraintSet_layout_goneMarginBottom"
+ ]
+ },
+ "android/support/v4/view/ViewPager": {
+ "androidx/widget/ViewPager": [
+ "SCROLL_STATE_DRAGGING",
+ "MIN_FLING_VELOCITY",
+ "LAYOUT_ATTRS",
+ "DRAW_ORDER_DEFAULT",
+ "DEFAULT_OFFSCREEN_PAGES",
+ "USE_CACHE",
+ "INVALID_POINTER",
+ "sPositionComparator",
+ "SCROLL_STATE_IDLE",
+ "TAG",
+ "DEBUG",
+ "MAX_SETTLE_DURATION",
+ "SCROLL_STATE_SETTLING",
+ "DEFAULT_GUTTER_SIZE",
+ "sInterpolator",
+ "MIN_DISTANCE_FOR_FLING",
+ "DRAW_ORDER_REVERSE",
+ "CLOSE_ENOUGH",
+ "DRAW_ORDER_FORWARD",
+ "COMPARATOR"
+ ]
+ },
+ "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase$MessageHandler": {
+ "androidx/media/session/MediaSessionCompat$MediaSessionImplBase$MessageHandler": [
+ "MSG_CUSTOM_ACTION",
+ "MSG_SET_VOLUME",
+ "MSG_SET_SHUFFLE_MODE",
+ "MSG_PREPARE",
+ "MSG_COMMAND",
+ "MSG_REMOVE_QUEUE_ITEM",
+ "MSG_RATE_EXTRA",
+ "MSG_PREPARE_SEARCH",
+ "MSG_FAST_FORWARD",
+ "MSG_PREPARE_URI",
+ "MSG_PAUSE",
+ "MSG_PLAY_URI",
+ "MSG_STOP",
+ "MSG_SKIP_TO_ITEM",
+ "MSG_ADD_QUEUE_ITEM",
+ "MSG_RATE",
+ "MSG_PLAY",
+ "MSG_NEXT",
+ "MSG_REMOVE_QUEUE_ITEM_AT",
+ "MSG_SET_REPEAT_MODE",
+ "MSG_PREVIOUS",
+ "MSG_SEEK_TO",
+ "MSG_PLAY_SEARCH",
+ "MSG_PLAY_MEDIA_ID",
+ "MSG_MEDIA_BUTTON",
+ "KEYCODE_MEDIA_PAUSE",
+ "MSG_PREPARE_MEDIA_ID",
+ "KEYCODE_MEDIA_PLAY",
+ "MSG_ADD_QUEUE_ITEM_AT",
+ "MSG_SET_CAPTIONING_ENABLED",
+ "MSG_ADJUST_VOLUME",
+ "MSG_REWIND"
+ ]
+ },
+ "android/support/design/R$dimen": {
+ "androidx/design/R$dimen": [
+ "design_bottom_navigation_item_min_width",
+ "design_tab_scrollable_min_width",
+ "design_tab_text_size_2line",
+ "design_bottom_sheet_peek_height_min",
+ "design_fab_size_mini",
+ "design_snackbar_padding_vertical_2lines",
+ "design_snackbar_padding_vertical",
+ "design_bottom_navigation_item_max_width",
+ "design_bottom_navigation_active_text_size",
+ "design_navigation_separator_vertical_padding",
+ "design_navigation_icon_size",
+ "design_bottom_navigation_text_size",
+ "design_fab_image_size",
+ "design_bottom_navigation_height",
+ "design_bottom_navigation_margin",
+ "design_fab_size_normal",
+ "design_bottom_navigation_active_item_max_width",
+ "design_bottom_navigation_shadow_height"
+ ]
+ },
+ "android/support/multidex/MultiDex": {
+ "androidx/multidex/MultiDex": [
+ "installedApk",
+ "CODE_CACHE_SECONDARY_FOLDER_NAME",
+ "CODE_CACHE_NAME",
+ "VM_WITH_MULTIDEX_VERSION_MAJOR",
+ "TAG",
+ "NO_KEY_PREFIX",
+ "IS_VM_MULTIDEX_CAPABLE",
+ "VM_WITH_MULTIDEX_VERSION_MINOR",
+ "MIN_SDK_VERSION",
+ "MAX_SUPPORTED_SDK_VERSION",
+ "OLD_SECONDARY_FOLDER_NAME"
+ ]
+ },
+ "android/support/constraint/ConstraintSet$Constraint": {
+ "androidx/constraint/ConstraintSet$Constraint": [
+ "guidePercent",
+ "topToTop",
+ "guideEnd",
+ "heightDefault",
+ "topMargin",
+ "goneRightMargin",
+ "goneTopMargin",
+ "visibility",
+ "elevation",
+ "dimensionRatio",
+ "startToStart",
+ "widthMax",
+ "applyElevation",
+ "widthMin",
+ "verticalWeight",
+ "endToStart",
+ "bottomToTop",
+ "rotationY",
+ "rotationX",
+ "horizontalBias",
+ "translationY",
+ "translationZ",
+ "translationX",
+ "transformPivotX",
+ "transformPivotY",
+ "leftMargin",
+ "horizontalChainStyle",
+ "orientation",
+ "leftToRight",
+ "endMargin",
+ "verticalBias",
+ "heightMax",
+ "scaleX",
+ "scaleY",
+ "rightMargin",
+ "leftToLeft",
+ "heightMin",
+ "endToEnd",
+ "topToBottom",
+ "startMargin",
+ "goneLeftMargin",
+ "bottomToBottom",
+ "editorAbsoluteY",
+ "editorAbsoluteX",
+ "baselineToBaseline",
+ "horizontalWeight",
+ "guideBegin",
+ "bottomMargin",
+ "widthDefault",
+ "startToEnd",
+ "rightToRight",
+ "alpha",
+ "UNSET",
+ "goneStartMargin",
+ "rightToLeft",
+ "goneBottomMargin",
+ "verticalChainStyle",
+ "goneEndMargin"
+ ]
+ },
+ "android/support/compat/R$id": {
+ "androidx/compat/R$id": [
+ "right_icon",
+ "action_container",
+ "icon",
+ "notification_background",
+ "line1",
+ "line3",
+ "text",
+ "action_divider",
+ "time",
+ "action_text",
+ "right_side",
+ "notification_main_column",
+ "action_image",
+ "tag_transition_group",
+ "title",
+ "text2",
+ "actions",
+ "notification_main_column_container",
+ "info",
+ "chronometer"
+ ]
+ },
+ "android/support/v7/widget/helper/ItemTouchHelper": {
+ "androidx/widget/helper/ItemTouchHelper": [
+ "DOWN",
+ "DEBUG",
+ "PIXELS_PER_SECOND",
+ "ACTION_STATE_SWIPE",
+ "ANIMATION_TYPE_SWIPE_CANCEL",
+ "END",
+ "UP",
+ "START",
+ "ANIMATION_TYPE_SWIPE_SUCCESS",
+ "ANIMATION_TYPE_DRAG",
+ "LEFT",
+ "ACTIVE_POINTER_ID_NONE",
+ "RIGHT",
+ "TAG",
+ "ACTION_STATE_DRAG",
+ "ACTION_MODE_IDLE_MASK",
+ "ACTION_MODE_SWIPE_MASK",
+ "DIRECTION_FLAG_COUNT",
+ "ACTION_MODE_DRAG_MASK",
+ "ACTION_STATE_IDLE"
+ ]
+ },
+ "android/support/graphics/drawable/VectorDrawableCompat": {
+ "androidx/graphics/drawable/VectorDrawableCompat": [
+ "LINECAP_ROUND",
+ "SHAPE_VECTOR",
+ "LOGTAG",
+ "DEFAULT_TINT_MODE",
+ "SHAPE_CLIP_PATH",
+ "LINECAP_SQUARE",
+ "LINEJOIN_MITER",
+ "LINEJOIN_ROUND",
+ "LINEJOIN_BEVEL",
+ "LINECAP_BUTT",
+ "SHAPE_PATH",
+ "MAX_CACHED_BITMAP_SIZE",
+ "DBG_VECTOR_DRAWABLE",
+ "SHAPE_GROUP"
+ ]
+ },
+ "android/support/v14/preference/R$styleable": {
+ "androidx/preference/R$styleable": [
+ "SwitchPreference_switchTextOff",
+ "SwitchPreference_switchTextOn",
+ "SwitchPreference_disableDependentsState",
+ "PreferenceFragment",
+ "SwitchPreference_android_summaryOn",
+ "PreferenceFragment_android_dividerHeight",
+ "SwitchPreference_android_switchTextOff",
+ "SwitchPreference_android_summaryOff",
+ "PreferenceFragment_allowDividerAfterLastItem",
+ "SwitchPreference",
+ "SwitchPreference_summaryOff",
+ "SwitchPreference_summaryOn",
+ "SwitchPreference_android_switchTextOn",
+ "PreferenceFragment_android_divider",
+ "SwitchPreference_android_disableDependentsState",
+ "PreferenceFragment_android_layout"
+ ]
+ },
+ "android/support/v7/app/MediaRouteControllerDialog": {
+ "androidx/app/MediaRouteControllerDialog": [
+ "BUTTON_DISCONNECT_RES_ID",
+ "DEBUG",
+ "BUTTON_NEUTRAL_RES_ID",
+ "VOLUME_UPDATE_DELAY_MILLIS",
+ "CONNECTION_TIMEOUT_MILLIS",
+ "BUTTON_STOP_RES_ID",
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/picker/PickerUtility": {
+ "androidx/leanback/widget/picker/PickerUtility": [
+ "SUPPORTS_BEST_DATE_TIME_PATTERN"
+ ]
+ },
+ "android/support/wear/widget/drawer/WearableActionDrawerView$TitleViewHolder": {
+ "androidx/wear/widget/drawer/WearableActionDrawerView$TitleViewHolder": [
+ "textView",
+ "view"
+ ]
+ },
+ "android/support/customtabs/CustomTabsIntent": {
+ "androidx/browser/customtabs/CustomTabsIntent": [
+ "TOOLBAR_ACTION_BUTTON_ID",
+ "EXTRA_ACTION_BUTTON_BUNDLE",
+ "EXTRA_EXIT_ANIMATION_BUNDLE",
+ "EXTRA_MENU_ITEMS",
+ "EXTRA_CLOSE_BUTTON_ICON",
+ "startAnimationBundle",
+ "KEY_ICON",
+ "EXTRA_SESSION",
+ "EXTRA_DEFAULT_SHARE_MENU_ITEM",
+ "MAX_TOOLBAR_ITEMS",
+ "intent",
+ "EXTRA_SECONDARY_TOOLBAR_COLOR",
+ "KEY_ID",
+ "EXTRA_TOOLBAR_COLOR",
+ "SHOW_PAGE_TITLE",
+ "EXTRA_TITLE_VISIBILITY_STATE",
+ "EXTRA_TOOLBAR_ITEMS",
+ "EXTRA_TINT_ACTION_BUTTON",
+ "NO_TITLE",
+ "KEY_DESCRIPTION",
+ "EXTRA_ENABLE_INSTANT_APPS",
+ "EXTRA_REMOTEVIEWS_PENDINGINTENT",
+ "EXTRA_REMOTEVIEWS_CLICKED_ID",
+ "KEY_MENU_ITEM_TITLE",
+ "EXTRA_ENABLE_URLBAR_HIDING",
+ "KEY_PENDING_INTENT",
+ "EXTRA_REMOTEVIEWS",
+ "EXTRA_USER_OPT_OUT_FROM_CUSTOM_TABS",
+ "EXTRA_REMOTEVIEWS_VIEW_IDS"
+ ]
+ },
+ "android/support/wear/R$styleable": {
+ "androidx/wear/R$styleable": [
+ "PageIndicatorView_wsPageIndicatorDotFadeInDuration",
+ "CircularProgressLayout_strokeWidth",
+ "WearableActionDrawerView",
+ "WearableRecyclerView_circularScrollingGestureEnabled",
+ "PageIndicatorView_wsPageIndicatorDotColor",
+ "PageIndicatorView",
+ "WearableActionDrawerView_actionMenu",
+ "PageIndicatorView_wsPageIndicatorDotFadeOutDelay",
+ "PageIndicatorView_wsPageIndicatorDotRadius",
+ "PageIndicatorView_wsPageIndicatorDotRadiusSelected",
+ "RoundedDrawable",
+ "WearableNavigationDrawerView_navigationStyle",
+ "CircledImageView_img_horizontal_offset_percentage",
+ "CircularProgressLayout",
+ "CircledImageView_img_tint",
+ "WearableActionDrawerView_showOverflowInPeek",
+ "CircledImageView_background_border_cap",
+ "CircledImageView_img_circle_percentage",
+ "BoxInsetLayout_Layout",
+ "CircledImageView_background_radius_pressed_percent",
+ "WearableActionDrawerView_drawerTitle",
+ "WearableRecyclerView",
+ "PageIndicatorView_wsPageIndicatorDotColorSelected",
+ "CircledImageView_img_padding",
+ "WearableDrawerView_android_elevation",
+ "RoundedDrawable_backgroundColor",
+ "PageIndicatorView_wsPageIndicatorDotShadowDx",
+ "PageIndicatorView_wsPageIndicatorDotShadowDy",
+ "CircularProgressLayout_backgroundColor",
+ "CircledImageView_background_radius_pressed",
+ "WearableDrawerView",
+ "BoxInsetLayout_Layout_boxedEdges",
+ "RoundedDrawable_radius",
+ "CircularProgressLayout_indeterminate",
+ "WearableDrawerView_peekView",
+ "WearableDrawerView_android_background",
+ "WearableDrawerView_enableAutoPeek",
+ "CircledImageView",
+ "PageIndicatorView_wsPageIndicatorDotFadeOutDuration",
+ "CircledImageView_background_shadow_width",
+ "CircledImageView_android_src",
+ "CircledImageView_background_radius_percent",
+ "PageIndicatorView_wsPageIndicatorDotShadowRadius",
+ "WearableRecyclerView_scrollDegreesPerScreen",
+ "CircledImageView_background_color",
+ "CircledImageView_clip_dimen",
+ "CircledImageView_background_radius",
+ "PageIndicatorView_wsPageIndicatorDotShadowColor",
+ "RoundedDrawable_clipEnabled",
+ "RoundedDrawable_android_src",
+ "WearableRecyclerView_bezelWidth",
+ "CircularProgressLayout_colorSchemeColors",
+ "WearableDrawerView_drawerContent",
+ "CircledImageView_background_border_color",
+ "WearableNavigationDrawerView",
+ "PageIndicatorView_wsPageIndicatorDotSpacing",
+ "CircledImageView_background_border_width",
+ "PageIndicatorView_wsPageIndicatorDotFadeWhenIdle"
+ ]
+ },
+ "android/support/v17/leanback/widget/PlaybackControlsRow$ShuffleAction": {
+ "androidx/leanback/widget/PlaybackControlsRow$ShuffleAction": [
+ "INDEX_ON",
+ "INDEX_OFF",
+ "ON",
+ "OFF"
+ ]
+ },
+ "android/support/v7/widget/TooltipCompatHandler": {
+ "androidx/widget/TooltipCompatHandler": [
+ "LONG_CLICK_HIDE_TIMEOUT_MS",
+ "sActiveHandler",
+ "HOVER_HIDE_TIMEOUT_MS",
+ "TAG",
+ "HOVER_HIDE_TIMEOUT_SHORT_MS"
+ ]
+ },
+ "android/support/v7/appcompat/BuildConfig": {
+ "androidx/appcompat/BuildConfig": [
+ "APPLICATION_ID",
+ "FLAVOR",
+ "DEBUG",
+ "VERSION_CODE",
+ "VERSION_NAME",
+ "BUILD_TYPE"
+ ]
+ },
+ "android/support/v4/media/AudioAttributesCompat$AudioManagerHidden": {
+ "androidx/media/AudioAttributesCompat$AudioManagerHidden": [
+ "STREAM_TTS",
+ "STREAM_BLUETOOTH_SCO",
+ "STREAM_SYSTEM_ENFORCED",
+ "STREAM_ACCESSIBILITY"
+ ]
+ },
+ "android/support/v17/leanback/widget/CursorObjectAdapter": {
+ "androidx/leanback/widget/CursorObjectAdapter": [
+ "CACHE_SIZE"
+ ]
+ },
+ "android/support/v7/mediarouter/R$dimen": {
+ "androidx/mediarouter/R$dimen": [
+ "mr_controller_volume_group_list_padding_top",
+ "mr_controller_volume_group_list_max_height",
+ "mr_controller_volume_group_list_item_height",
+ "mr_controller_volume_group_list_item_icon_size",
+ "mr_dialog_fixed_width_major",
+ "mr_dialog_fixed_width_minor"
+ ]
+ },
+ "android/support/transition/Transition": {
+ "androidx/transition/Transition": [
+ "MATCH_INSTANCE",
+ "MATCH_LAST",
+ "MATCH_FIRST",
+ "sRunningAnimators",
+ "MATCH_ID_STR",
+ "DBG",
+ "MATCH_INSTANCE_STR",
+ "MATCH_ITEM_ID",
+ "DEFAULT_MATCH_ORDER",
+ "MATCH_NAME_STR",
+ "MATCH_NAME",
+ "STRAIGHT_PATH_MOTION",
+ "MATCH_ITEM_ID_STR",
+ "MATCH_ID",
+ "LOG_TAG"
+ ]
+ },
+ "android/support/design/widget/CoordinatorLayout": {
+ "androidx/widget/CoordinatorLayout": [
+ "EVENT_VIEW_REMOVED",
+ "sConstructors",
+ "TOP_SORTED_CHILDREN_COMPARATOR",
+ "TYPE_ON_TOUCH",
+ "sRectPool",
+ "CONSTRUCTOR_PARAMS",
+ "TAG",
+ "EVENT_NESTED_SCROLL",
+ "WIDGET_PACKAGE_NAME",
+ "EVENT_PRE_DRAW",
+ "TYPE_ON_INTERCEPT"
+ ]
+ },
+ "android/support/constraint/ConstraintSet": {
+ "androidx/constraint/ConstraintSet": [
+ "CHAIN_SPREAD_INSIDE",
+ "UNUSED",
+ "GONE_LEFT_MARGIN",
+ "WIDTH_MAX",
+ "DIMENSION_RATIO",
+ "WIDTH_MIN",
+ "GUIDE_BEGIN",
+ "START_TO_START",
+ "ORIENTATION",
+ "RIGHT_TO_LEFT",
+ "VERTICAL",
+ "GUIDE_PERCENT",
+ "GONE_END_MARGIN",
+ "CHAIN_SPREAD",
+ "LAYOUT_HEIGHT",
+ "HORIZONTAL_STYLE",
+ "TOP_MARGIN",
+ "TRANSLATION_X",
+ "TRANSLATION_Z",
+ "TRANSLATION_Y",
+ "ELEVATION",
+ "EDITOR_ABSOLUTE_Y",
+ "EDITOR_ABSOLUTE_X",
+ "END_TO_START",
+ "DEBUG",
+ "MATCH_CONSTRAINT",
+ "BOTTOM_TO_TOP",
+ "RIGHT_MARGIN",
+ "TRANSFORM_PIVOT_Y",
+ "TRANSFORM_PIVOT_X",
+ "WRAP_CONTENT",
+ "BASELINE",
+ "HORIZONTAL_BIAS",
+ "SCALE_Y",
+ "SCALE_X",
+ "VISIBILITY_FLAGS",
+ "CHAIN_PACKED",
+ "VERTICAL_STYLE",
+ "mapToConstant",
+ "HORIZONTAL_GUIDELINE",
+ "LEFT",
+ "START_MARGIN",
+ "PARENT_ID",
+ "GUIDE_END",
+ "END_TO_END",
+ "TOP",
+ "LAYOUT_VISIBILITY",
+ "GONE_BOTTOM_MARGIN",
+ "LEFT_MARGIN",
+ "RIGHT",
+ "GONE_TOP_MARGIN",
+ "VERTICAL_GUIDELINE",
+ "START",
+ "GONE_RIGHT_MARGIN",
+ "TAG",
+ "GONE_START_MARGIN",
+ "HEIGHT_MIN",
+ "MATCH_CONSTRAINT_WRAP",
+ "UNSET",
+ "HEIGHT_MAX",
+ "END",
+ "BASELINE_TO_BASELINE",
+ "LAYOUT_WIDTH",
+ "VERTICAL_BIAS",
+ "HORIZONTAL",
+ "MATCH_CONSTRAINT_SPREAD",
+ "ALPHA",
+ "TOP_TO_TOP",
+ "RIGHT_TO_RIGHT",
+ "TOP_TO_BOTTOM",
+ "BOTTOM",
+ "LEFT_TO_LEFT",
+ "VIEW_ID",
+ "INVISIBLE",
+ "VERTICAL_WEIGHT",
+ "VISIBLE",
+ "HEIGHT_DEFAULT",
+ "WIDTH_DEFAULT",
+ "LEFT_TO_RIGHT",
+ "END_MARGIN",
+ "BOTTOM_MARGIN",
+ "HORIZONTAL_WEIGHT",
+ "START_TO_END",
+ "BOTTOM_TO_BOTTOM",
+ "GONE",
+ "ROTATION_X",
+ "ROTATION_Y"
+ ]
+ },
+ "android/support/v4/app/FrameMetricsAggregator$FrameMetricsApi24Impl": {
+ "androidx/app/FrameMetricsAggregator$FrameMetricsApi24Impl": [
+ "NANOS_PER_MS",
+ "NANOS_ROUNDING_VALUE",
+ "sHandlerThread",
+ "sHandler"
+ ]
+ },
+ "android/support/v4/view/GestureDetectorCompat$GestureDetectorCompatImplBase": {
+ "androidx/view/GestureDetectorCompat$GestureDetectorCompatImplBase": [
+ "LONGPRESS_TIMEOUT",
+ "TAP_TIMEOUT",
+ "DOUBLE_TAP_TIMEOUT",
+ "LONG_PRESS",
+ "TAP",
+ "SHOW_PRESS"
+ ]
+ },
+ "android/support/multidex/MultiDexExtractor": {
+ "androidx/multidex/MultiDexExtractor": [
+ "KEY_DEX_TIME",
+ "MAX_EXTRACT_ATTEMPTS",
+ "TAG",
+ "DEX_PREFIX",
+ "DEX_SUFFIX",
+ "EXTRACTED_NAME_EXT",
+ "KEY_CRC",
+ "KEY_DEX_CRC",
+ "NO_VALUE",
+ "LOCK_FILENAME",
+ "KEY_TIME_STAMP",
+ "EXTRACTED_SUFFIX",
+ "BUFFER_SIZE",
+ "KEY_DEX_NUMBER",
+ "PREFS_FILE"
+ ]
+ },
+ "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$AccessibilityActionCompat": {
+ "androidx/view/accessibility/AccessibilityNodeInfoCompat$AccessibilityActionCompat": [
+ "ACTION_FOCUS",
+ "ACTION_SCROLL_BACKWARD",
+ "ACTION_SCROLL_DOWN",
+ "ACTION_CONTEXT_CLICK",
+ "ACTION_CLEAR_FOCUS",
+ "ACTION_ACCESSIBILITY_FOCUS",
+ "ACTION_PASTE",
+ "ACTION_SET_PROGRESS",
+ "ACTION_EXPAND",
+ "ACTION_NEXT_HTML_ELEMENT",
+ "ACTION_SCROLL_UP",
+ "ACTION_SCROLL_FORWARD",
+ "ACTION_CLEAR_SELECTION",
+ "ACTION_LONG_CLICK",
+ "ACTION_SET_TEXT",
+ "ACTION_NEXT_AT_MOVEMENT_GRANULARITY",
+ "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY",
+ "ACTION_SHOW_ON_SCREEN",
+ "ACTION_COLLAPSE",
+ "ACTION_COPY",
+ "ACTION_SCROLL_LEFT",
+ "ACTION_PREVIOUS_HTML_ELEMENT",
+ "ACTION_SET_SELECTION",
+ "ACTION_CLEAR_ACCESSIBILITY_FOCUS",
+ "ACTION_SCROLL_TO_POSITION",
+ "ACTION_DISMISS",
+ "ACTION_CLICK",
+ "ACTION_CUT",
+ "ACTION_SCROLL_RIGHT",
+ "ACTION_SELECT"
+ ]
+ },
+ "android/support/v4/graphics/drawable/DrawableWrapperApi21": {
+ "androidx/graphics/drawable/DrawableWrapperApi21": [
+ "sIsProjectedDrawableMethod",
+ "TAG"
+ ]
+ },
+ "android/support/v7/media/MediaRouter$RouteInfo": {
+ "androidx/media/MediaRouter$RouteInfo": [
+ "PRESENTATION_DISPLAY_ID_NONE",
+ "SYSTEM_MEDIA_ROUTE_PROVIDER_PACKAGE_NAME",
+ "PLAYBACK_TYPE_REMOTE",
+ "CHANGE_VOLUME",
+ "DEVICE_TYPE_BLUETOOTH",
+ "CHANGE_PRESENTATION_DISPLAY",
+ "CHANGE_GENERAL",
+ "CONNECTION_STATE_DISCONNECTED",
+ "DEVICE_TYPE_TV",
+ "PLAYBACK_VOLUME_VARIABLE",
+ "CONNECTION_STATE_CONNECTING",
+ "PLAYBACK_TYPE_LOCAL",
+ "DEVICE_TYPE_UNKNOWN",
+ "CONNECTION_STATE_CONNECTED",
+ "PLAYBACK_VOLUME_FIXED",
+ "DEVICE_TYPE_SPEAKER"
+ ]
+ },
+ "android/support/v17/leanback/widget/picker/TimePicker": {
+ "androidx/leanback/widget/picker/TimePicker": [
+ "TAG",
+ "HOURS_IN_HALF_DAY",
+ "AM_INDEX",
+ "PM_INDEX"
+ ]
+ },
+ "android/support/v7/widget/RecyclerView": {
+ "androidx/widget/RecyclerView": [
+ "LAYOUT_MANAGER_CONSTRUCTOR_SIGNATURE",
+ "TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG",
+ "NO_ID",
+ "NO_POSITION",
+ "DISPATCH_TEMP_DETACH",
+ "TRACE_SCROLL_TAG",
+ "SCROLL_STATE_DRAGGING",
+ "TRACE_PREFETCH_TAG",
+ "INVALID_POINTER",
+ "MAX_SCROLL_DURATION",
+ "TOUCH_SLOP_PAGING",
+ "TOUCH_SLOP_DEFAULT",
+ "VERBOSE_TRACING",
+ "TRACE_CREATE_VIEW_TAG",
+ "ALLOW_SIZE_IN_UNSPECIFIED_SPEC",
+ "FORCE_ABS_FOCUS_SEARCH_DIRECTION",
+ "TRACE_BIND_VIEW_TAG",
+ "HORIZONTAL",
+ "ALLOW_THREAD_GAP_WORK",
+ "DEBUG",
+ "TRACE_NESTED_PREFETCH_TAG",
+ "SCROLL_STATE_SETTLING",
+ "POST_UPDATES_ON_ANIMATION",
+ "sQuinticInterpolator",
+ "VERTICAL",
+ "CLIP_TO_PADDING_ATTR",
+ "FOREVER_NS",
+ "IGNORE_DETACHED_FOCUSED_CHILD",
+ "INVALID_TYPE",
+ "SCROLL_STATE_IDLE",
+ "NESTED_SCROLLING_ATTRS",
+ "TAG",
+ "TRACE_ON_LAYOUT_TAG",
+ "FORCE_INVALIDATE_DISPLAY_LIST",
+ "TRACE_HANDLE_ADAPTER_UPDATES_TAG"
+ ]
+ },
+ "android/support/v4/view/PagerAdapter": {
+ "androidx/widget/PagerAdapter": [
+ "POSITION_NONE",
+ "POSITION_UNCHANGED"
+ ]
+ },
+ "android/support/compat/BuildConfig": {
+ "androidx/compat/BuildConfig": [
+ "FLAVOR",
+ "APPLICATION_ID",
+ "VERSION_CODE",
+ "DEBUG",
+ "VERSION_NAME",
+ "BUILD_TYPE"
+ ]
+ },
+ "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat": {
+ "androidx/view/accessibility/AccessibilityNodeInfoCompat": [
+ "ACTION_PREVIOUS_HTML_ELEMENT",
+ "ACTION_ARGUMENT_SELECTION_END_INT",
+ "ACTION_SET_SELECTION",
+ "MOVEMENT_GRANULARITY_CHARACTER",
+ "MOVEMENT_GRANULARITY_LINE",
+ "ACTION_SET_TEXT",
+ "MOVEMENT_GRANULARITY_PARAGRAPH",
+ "ACTION_SELECT",
+ "FOCUS_ACCESSIBILITY",
+ "ACTION_DISMISS",
+ "ACTION_EXPAND",
+ "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE",
+ "ACTION_CLEAR_ACCESSIBILITY_FOCUS",
+ "ACTION_CUT",
+ "ACTION_PASTE",
+ "ACTION_ARGUMENT_ROW_INT",
+ "FOCUS_INPUT",
+ "ACTION_ARGUMENT_HTML_ELEMENT_STRING",
+ "MOVEMENT_GRANULARITY_PAGE",
+ "ACTION_ARGUMENT_PROGRESS_VALUE",
+ "ACTION_CLEAR_FOCUS",
+ "MOVEMENT_GRANULARITY_WORD",
+ "ACTION_SCROLL_BACKWARD",
+ "ROLE_DESCRIPTION_KEY",
+ "ACTION_FOCUS",
+ "ACTION_NEXT_HTML_ELEMENT",
+ "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN",
+ "ACTION_CLEAR_SELECTION",
+ "ACTION_ARGUMENT_COLUMN_INT",
+ "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY",
+ "ACTION_NEXT_AT_MOVEMENT_GRANULARITY",
+ "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT",
+ "ACTION_ACCESSIBILITY_FOCUS",
+ "ACTION_CLICK",
+ "ACTION_ARGUMENT_SELECTION_START_INT",
+ "ACTION_SCROLL_FORWARD",
+ "ACTION_COPY",
+ "ACTION_COLLAPSE",
+ "ACTION_LONG_CLICK"
+ ]
+ },
+ "android/support/v7/preference/R$styleable": {
+ "androidx/preference/R$styleable": [
+ "SeekBarPreference",
+ "CheckBoxPreference_summaryOn",
+ "DialogPreference_android_dialogLayout",
+ "Preference_summary",
+ "Preference_widgetLayout",
+ "CheckBoxPreference_android_disableDependentsState",
+ "Preference_android_layout",
+ "Preference_android_selectable",
+ "Preference_android_enabled",
+ "DialogPreference_dialogLayout",
+ "Preference_dependency",
+ "Preference_iconSpaceReserved",
+ "Preference_fragment",
+ "ListPreference_android_entries",
+ "PreferenceGroup",
+ "SeekBarPreference_seekBarIncrement",
+ "Preference_android_iconSpaceReserved",
+ "Preference_selectable",
+ "PreferenceFragmentCompat",
+ "Preference_allowDividerAbove",
+ "PreferenceImageView",
+ "SwitchPreferenceCompat_switchTextOn",
+ "DialogPreference_android_dialogMessage",
+ "Preference",
+ "CheckBoxPreference_summaryOff",
+ "Preference_shouldDisableView",
+ "Preference_title",
+ "Preference_enabled",
+ "SwitchPreferenceCompat_android_switchTextOff",
+ "DialogPreference_android_dialogIcon",
+ "ListPreference_entries",
+ "MultiSelectListPreference",
+ "SeekBarPreference_adjustable",
+ "PreferenceImageView_maxHeight",
+ "SwitchPreferenceCompat_android_summaryOn",
+ "PreferenceFragmentCompat_allowDividerAfterLastItem",
+ "SwitchPreferenceCompat_disableDependentsState",
+ "DialogPreference",
+ "DialogPreference_positiveButtonText",
+ "PreferenceFragmentCompat_android_layout",
+ "Preference_android_icon",
+ "SwitchPreferenceCompat_summaryOff",
+ "DialogPreference_dialogMessage",
+ "DialogPreference_android_negativeButtonText",
+ "MultiSelectListPreference_entries",
+ "ListPreference_android_entryValues",
+ "Preference_defaultValue",
+ "CheckBoxPreference_android_summaryOff",
+ "PreferenceFragmentCompat_android_divider",
+ "Preference_android_shouldDisableView",
+ "SwitchPreferenceCompat_switchTextOff",
+ "SwitchPreferenceCompat",
+ "Preference_allowDividerBelow",
+ "Preference_android_persistent",
+ "BackgroundStyle",
+ "ListPreference",
+ "Preference_android_widgetLayout",
+ "SwitchPreferenceCompat_android_summaryOff",
+ "SwitchPreferenceCompat_android_switchTextOn",
+ "Preference_android_order",
+ "MultiSelectListPreference_android_entries",
+ "Preference_layout",
+ "SwitchPreferenceCompat_android_disableDependentsState",
+ "SwitchPreferenceCompat_summaryOn",
+ "Preference_android_summary",
+ "DialogPreference_dialogTitle",
+ "Preference_android_dependency",
+ "DialogPreference_android_dialogTitle",
+ "Preference_persistent",
+ "MultiSelectListPreference_android_entryValues",
+ "Preference_android_key",
+ "DialogPreference_android_positiveButtonText",
+ "Preference_android_title",
+ "Preference_android_singleLineTitle",
+ "DialogPreference_negativeButtonText",
+ "MultiSelectListPreference_entryValues",
+ "PreferenceFragmentCompat_android_dividerHeight",
+ "CheckBoxPreference_android_summaryOn",
+ "SeekBarPreference_min",
+ "BackgroundStyle_android_selectableItemBackground",
+ "Preference_android_fragment",
+ "DialogPreference_dialogIcon",
+ "Preference_icon",
+ "CheckBoxPreference_disableDependentsState",
+ "Preference_key",
+ "CheckBoxPreference",
+ "SeekBarPreference_android_max",
+ "Preference_singleLineTitle",
+ "SeekBarPreference_showSeekBarValue",
+ "PreferenceImageView_maxWidth",
+ "Preference_android_defaultValue",
+ "ListPreference_entryValues",
+ "PreferenceGroup_orderingFromXml",
+ "Preference_order"
+ ]
+ },
+ "android/support/media/tv/TvContractCompat$RecordedPrograms": {
+ "androidx/media/tv/TvContractCompat$RecordedPrograms": [
+ "CONTENT_URI",
+ "COLUMN_RECORDING_DURATION_MILLIS",
+ "COLUMN_CHANNEL_ID",
+ "COLUMN_BROADCAST_GENRE",
+ "COLUMN_RECORDING_DATA_BYTES",
+ "COLUMN_END_TIME_UTC_MILLIS",
+ "CONTENT_TYPE",
+ "COLUMN_RECORDING_DATA_URI",
+ "COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS",
+ "COLUMN_INPUT_ID",
+ "COLUMN_START_TIME_UTC_MILLIS",
+ "CONTENT_ITEM_TYPE"
+ ]
+ },
+ "android/support/v17/leanback/app/PlaybackSupportFragment": {
+ "androidx/leanback/app/PlaybackSupportFragment": [
+ "IDLE",
+ "ANIMATION_MULTIPLIER",
+ "ANIMATING",
+ "BG_LIGHT",
+ "START_FADE_OUT",
+ "TAG",
+ "BG_DARK",
+ "BG_NONE",
+ "BUNDLE_CONTROL_VISIBLE_ON_CREATEVIEW",
+ "DEBUG"
+ ]
+ },
+ "android/support/v17/leanback/widget/ShadowOverlayHelper$Options": {
+ "androidx/leanback/widget/ShadowOverlayHelper$Options": [
+ "DEFAULT",
+ "roundedCornerRadius",
+ "dynamicShadowUnfocusedZ",
+ "dynamicShadowFocusedZ"
+ ]
+ },
+ "android/support/v17/leanback/widget/ShadowOverlayHelper": {
+ "androidx/leanback/widget/ShadowOverlayHelper": [
+ "SHADOW_NONE",
+ "SHADOW_STATIC",
+ "SHADOW_DYNAMIC"
+ ]
+ },
+ "android/support/v4/media/MediaBrowserServiceCompat": {
+ "androidx/media/MediaBrowserServiceCompat": [
+ "EPSILON",
+ "RESULT_ERROR",
+ "DEBUG",
+ "RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED",
+ "RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED",
+ "KEY_MEDIA_ITEM",
+ "TAG",
+ "SERVICE_INTERFACE",
+ "KEY_SEARCH_RESULTS",
+ "RESULT_OK",
+ "RESULT_PROGRESS_UPDATE",
+ "RESULT_FLAG_OPTION_NOT_HANDLED"
+ ]
+ },
+ "android/support/v13/app/FragmentPagerAdapter": {
+ "androidx/app/FragmentPagerAdapter": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/design/widget/BaseTransientBottomBar$BaseCallback": {
+ "androidx/design/widget/BaseTransientBottomBar$BaseCallback": [
+ "DISMISS_EVENT_MANUAL",
+ "DISMISS_EVENT_SWIPE",
+ "DISMISS_EVENT_TIMEOUT",
+ "DISMISS_EVENT_ACTION",
+ "DISMISS_EVENT_CONSECUTIVE"
+ ]
+ },
+ "android/support/v7/widget/GapWorker": {
+ "androidx/widget/GapWorker": [
+ "sGapWorker",
+ "sTaskComparator"
+ ]
+ },
+ "android/support/v7/preference/PreferenceManager": {
+ "androidx/preference/PreferenceManager": [
+ "STORAGE_DEFAULT",
+ "KEY_HAS_SET_DEFAULT_VALUES",
+ "STORAGE_DEVICE_PROTECTED"
+ ]
+ },
+ "android/support/v4/widget/SlidingPaneLayout$LayoutParams": {
+ "androidx/widget/SlidingPaneLayout$LayoutParams": [
+ "width",
+ "ATTRS",
+ "height",
+ "dimPaint",
+ "leftMargin",
+ "weight",
+ "slideable",
+ "rightMargin",
+ "dimWhenOffset"
+ ]
+ },
+ "android/support/v17/leanback/widget/GuidedAction": {
+ "androidx/leanback/widget/GuidedAction": [
+ "ACTION_ID_CONTINUE",
+ "PF_ENABLED",
+ "ACTION_ID_YES",
+ "ACTION_ID_OK",
+ "ACTION_ID_NO",
+ "PF_INFO_ONLY",
+ "ACTION_ID_FINISH",
+ "TAG",
+ "EDITING_TITLE",
+ "EDITING_DESCRIPTION",
+ "PF_MULTI_lINE_DESCRIPTION",
+ "PF_CHECKED",
+ "DEFAULT_CHECK_SET_ID",
+ "ACTION_ID_CURRENT",
+ "CHECKBOX_CHECK_SET_ID",
+ "EDITING_NONE",
+ "PF_AUTORESTORE",
+ "EDITING_ACTIVATOR_VIEW",
+ "PF_HAS_NEXT",
+ "ACTION_ID_NEXT",
+ "ACTION_ID_CANCEL",
+ "PF_FOCUSABLE",
+ "NO_CHECK_SET"
+ ]
+ },
+ "android/support/media/tv/TvContractCompat$PreviewPrograms": {
+ "androidx/media/tv/TvContractCompat$PreviewPrograms": [
+ "COLUMN_CHANNEL_ID",
+ "CONTENT_ITEM_TYPE",
+ "CONTENT_URI",
+ "CONTENT_TYPE",
+ "COLUMN_WEIGHT"
+ ]
+ },
+ "android/support/v17/leanback/widget/BaseCardView": {
+ "androidx/leanback/widget/BaseCardView": [
+ "CARD_TYPE_INFO_OVER",
+ "CARD_TYPE_INVALID",
+ "DEBUG",
+ "CARD_TYPE_INFO_UNDER",
+ "CARD_TYPE_MAIN_ONLY",
+ "LB_PRESSED_STATE_SET",
+ "CARD_REGION_VISIBLE_ALWAYS",
+ "CARD_REGION_VISIBLE_SELECTED",
+ "TAG",
+ "CARD_TYPE_INFO_UNDER_WITH_EXTRA",
+ "CARD_REGION_VISIBLE_ACTIVATED"
+ ]
+ },
+ "android/support/v7/mediarouter/R$string": {
+ "androidx/mediarouter/R$string": [
+ "mr_user_route_category_name",
+ "mr_controller_no_info_available",
+ "mr_system_route_name",
+ "mr_controller_disconnect",
+ "mr_cast_button_disconnected",
+ "mr_controller_casting_screen",
+ "mr_button_content_description",
+ "mr_controller_no_media_selected",
+ "mr_controller_expand_group",
+ "mr_controller_play",
+ "mr_controller_stop",
+ "mr_cast_button_connected",
+ "mr_controller_pause",
+ "mr_controller_collapse_group",
+ "mr_cast_button_connecting",
+ "mr_controller_stop_casting"
+ ]
+ },
+ "android/support/multidex/BuildConfig": {
+ "androidx/multidex/BuildConfig": [
+ "DEBUG",
+ "APPLICATION_ID",
+ "FLAVOR",
+ "VERSION_NAME",
+ "BUILD_TYPE",
+ "VERSION_CODE"
+ ]
+ },
+ "android/support/v4/text/util/LinkifyCompat$LinkSpec": {
+ "androidx/text/util/LinkifyCompat$LinkSpec": [
+ "end",
+ "url",
+ "frameworkAddedSpan",
+ "start"
+ ]
+ },
+ "android/support/transition/ArcMotion": {
+ "androidx/transition/ArcMotion": [
+ "DEFAULT_MIN_ANGLE_DEGREES",
+ "DEFAULT_MAX_ANGLE_DEGREES",
+ "DEFAULT_MAX_TANGENT"
+ ]
+ },
+ "android/support/v17/leanback/widget/TitleViewAdapter": {
+ "androidx/leanback/widget/TitleViewAdapter": [
+ "BRANDING_VIEW_VISIBLE",
+ "FULL_VIEW_VISIBLE",
+ "SEARCH_VIEW_VISIBLE"
+ ]
+ },
+ "android/support/v17/leanback/app/DetailsFragment": {
+ "androidx/leanback/app/DetailsFragment": [
+ "EVT_ON_CREATE",
+ "EVT_SWITCH_TO_VIDEO",
+ "STATE_ENTRANCE_INIT",
+ "STATE_SWITCH_TO_VIDEO_IN_ON_CREATE",
+ "STATE_START",
+ "EVT_DETAILS_ROW_LOADED",
+ "STATE_ENTER_TRANSITION_INIT",
+ "STATE_ENTER_TRANSITION_CANCEL",
+ "COND_TRANSITION_NOT_SUPPORTED",
+ "STATE_ENTRANCE_ON_PREPARED",
+ "EVT_NO_ENTER_TRANSITION",
+ "EVT_ON_CREATEVIEW",
+ "STATE_ENTER_TRANSITION_PENDING",
+ "EVT_ONSTART",
+ "STATE_ON_SAFE_START",
+ "DEBUG",
+ "EVT_ENTER_TRANSIITON_DONE",
+ "STATE_SET_ENTRANCE_START_STATE",
+ "STATE_ENTRANCE_PERFORM",
+ "STATE_ENTRANCE_COMPLETE",
+ "STATE_ENTER_TRANSITION_COMPLETE",
+ "STATE_ENTER_TRANSITION_ADDLISTENER",
+ "TAG"
+ ]
+ },
+ "android/support/v7/widget/FastScroller": {
+ "androidx/widget/FastScroller": [
+ "ANIMATION_STATE_OUT",
+ "ANIMATION_STATE_IN",
+ "SHOW_DURATION_MS",
+ "STATE_VISIBLE",
+ "DRAG_NONE",
+ "STATE_HIDDEN",
+ "ANIMATION_STATE_FADING_IN",
+ "STATE_DRAGGING",
+ "HIDE_DELAY_AFTER_VISIBLE_MS",
+ "DRAG_X",
+ "DRAG_Y",
+ "HIDE_DELAY_AFTER_DRAGGING_MS",
+ "HIDE_DURATION_MS",
+ "SCROLLBAR_FULL_OPAQUE",
+ "ANIMATION_STATE_FADING_OUT",
+ "PRESSED_STATE_SET",
+ "EMPTY_STATE_SET"
+ ]
+ },
+ "android/support/v7/media/MediaRouteDescriptor": {
+ "androidx/media/MediaRouteDescriptor": [
+ "KEY_VOLUME",
+ "KEY_PLAYBACK_TYPE",
+ "KEY_SETTINGS_INTENT",
+ "KEY_ID",
+ "KEY_ENABLED",
+ "KEY_MAX_CLIENT_VERSION",
+ "KEY_ICON_URI",
+ "KEY_DESCRIPTION",
+ "KEY_PLAYBACK_STREAM",
+ "KEY_GROUP_MEMBER_IDS",
+ "KEY_CONNECTION_STATE",
+ "KEY_EXTRAS",
+ "KEY_VOLUME_HANDLING",
+ "KEY_PRESENTATION_DISPLAY_ID",
+ "KEY_MIN_CLIENT_VERSION",
+ "KEY_CONTROL_FILTERS",
+ "KEY_CAN_DISCONNECT",
+ "KEY_DEVICE_TYPE",
+ "KEY_NAME",
+ "KEY_VOLUME_MAX",
+ "KEY_CONNECTING"
+ ]
+ },
+ "android/support/design/widget/BottomNavigationView": {
+ "androidx/design/widget/BottomNavigationView": [
+ "DISABLED_STATE_SET",
+ "CHECKED_STATE_SET",
+ "EMPTY_STATE_SET",
+ "MENU_PRESENTER_ID"
+ ]
+ },
+ "android/support/multidex/instrumentation/BuildConfig": {
+ "androidx/multidex/instrumentation/BuildConfig": [
+ "VERSION_NAME",
+ "VERSION_CODE",
+ "APPLICATION_ID",
+ "BUILD_TYPE",
+ "FLAVOR",
+ "DEBUG"
+ ]
+ },
+ "android/support/wear/widget/drawer/WearableActionDrawerView": {
+ "androidx/wear/widget/drawer/WearableActionDrawerView": [
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/media/PlaybackBaseControlGlue": {
+ "androidx/leanback/media/PlaybackBaseControlGlue": [
+ "ACTION_FAST_FORWARD",
+ "DEBUG",
+ "ACTION_CUSTOM_LEFT_FIRST",
+ "ACTION_SKIP_TO_PREVIOUS",
+ "TAG",
+ "ACTION_SKIP_TO_NEXT",
+ "ACTION_CUSTOM_RIGHT_FIRST",
+ "ACTION_PLAY_PAUSE",
+ "ACTION_REPEAT",
+ "ACTION_REWIND",
+ "ACTION_SHUFFLE"
+ ]
+ },
+ "android/support/v4/app/AppLaunchChecker": {
+ "androidx/app/AppLaunchChecker": [
+ "KEY_STARTED_FROM_LAUNCHER",
+ "SHARED_PREFS_NAME"
+ ]
+ },
+ "android/support/transition/Styleable$ArcMotion": {
+ "androidx/transition/Styleable$ArcMotion": [
+ "MAXIMUM_ANGLE",
+ "MINIMUM_VERTICAL_ANGLE",
+ "MINIMUM_HORIZONTAL_ANGLE"
+ ]
+ },
+ "android/support/v7/cardview/R$color": {
+ "androidx/cardview/R$color": [
+ "cardview_shadow_end_color",
+ "cardview_light_background",
+ "cardview_dark_background",
+ "cardview_shadow_start_color"
+ ]
+ },
+ "android/support/v17/leanback/app/BrowseFragment": {
+ "androidx/leanback/app/BrowseFragment": [
+ "TAG",
+ "EVT_SCREEN_DATA_READY",
+ "LB_HEADERS_BACKSTACK",
+ "STATE_ENTRANCE_PERFORM",
+ "IS_PAGE_ROW",
+ "ARG_TITLE",
+ "HEADERS_HIDDEN",
+ "HEADER_SHOW",
+ "EVT_MAIN_FRAGMENT_VIEW_CREATED",
+ "CURRENT_SELECTED_POSITION",
+ "DEBUG",
+ "EVT_HEADER_VIEW_CREATED",
+ "STATE_ENTRANCE_ON_PREPARED",
+ "HEADERS_ENABLED",
+ "ARG_HEADERS_STATE",
+ "STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW",
+ "STATE_SET_ENTRANCE_START_STATE",
+ "HEADERS_DISABLED",
+ "HEADER_STACK_INDEX"
+ ]
+ },
+ "android/support/media/tv/TvContractCompat$ProgramColumns": {
+ "androidx/media/tv/TvContractCompat$ProgramColumns": [
+ "COLUMN_SHORT_DESCRIPTION",
+ "COLUMN_SEASON_DISPLAY_NUMBER",
+ "COLUMN_SEASON_TITLE",
+ "COLUMN_VIDEO_WIDTH",
+ "COLUMN_AUDIO_LANGUAGE",
+ "REVIEW_RATING_STYLE_STARS",
+ "COLUMN_EPISODE_TITLE",
+ "REVIEW_RATING_STYLE_THUMBS_UP_DOWN",
+ "COLUMN_INTERNAL_PROVIDER_FLAG2",
+ "COLUMN_INTERNAL_PROVIDER_FLAG3",
+ "COLUMN_INTERNAL_PROVIDER_FLAG4",
+ "COLUMN_INTERNAL_PROVIDER_FLAG1",
+ "COLUMN_TITLE",
+ "COLUMN_POSTER_ART_URI",
+ "COLUMN_VERSION_NUMBER",
+ "COLUMN_THUMBNAIL_URI",
+ "REVIEW_RATING_STYLE_PERCENTAGE",
+ "COLUMN_EPISODE_DISPLAY_NUMBER",
+ "COLUMN_SEARCHABLE",
+ "COLUMN_VIDEO_HEIGHT",
+ "COLUMN_CANONICAL_GENRE",
+ "COLUMN_CONTENT_RATING",
+ "COLUMN_REVIEW_RATING",
+ "COLUMN_REVIEW_RATING_STYLE",
+ "COLUMN_LONG_DESCRIPTION",
+ "COLUMN_INTERNAL_PROVIDER_DATA"
+ ]
+ },
+ "android/support/v4/graphics/PaintCompat": {
+ "androidx/graphics/PaintCompat": [
+ "TOFU_STRING",
+ "sRectThreadLocal",
+ "EM_STRING"
+ ]
+ },
+ "android/support/v4/view/accessibility/AccessibilityEventCompat": {
+ "androidx/view/accessibility/AccessibilityEventCompat": [
+ "CONTENT_CHANGE_TYPE_UNDEFINED",
+ "TYPE_ANNOUNCEMENT",
+ "TYPE_TOUCH_INTERACTION_END",
+ "CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION",
+ "TYPE_TOUCH_INTERACTION_START",
+ "TYPE_TOUCH_EXPLORATION_GESTURE_END",
+ "TYPE_VIEW_HOVER_ENTER",
+ "TYPE_VIEW_ACCESSIBILITY_FOCUSED",
+ "CONTENT_CHANGE_TYPE_TEXT",
+ "TYPE_WINDOW_CONTENT_CHANGED",
+ "TYPES_ALL_MASK",
+ "TYPE_TOUCH_EXPLORATION_GESTURE_START",
+ "TYPE_WINDOWS_CHANGED",
+ "TYPE_VIEW_CONTEXT_CLICKED",
+ "TYPE_VIEW_HOVER_EXIT",
+ "CONTENT_CHANGE_TYPE_SUBTREE",
+ "TYPE_ASSIST_READING_CONTEXT",
+ "TYPE_VIEW_TEXT_SELECTION_CHANGED",
+ "TYPE_GESTURE_DETECTION_START",
+ "TYPE_VIEW_SCROLLED",
+ "TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY",
+ "TYPE_GESTURE_DETECTION_END",
+ "TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED"
+ ]
+ },
+ "android/support/v17/leanback/R$attr": {
+ "androidx/leanback/R$attr": [
+ "guidedActionContentWidthWeightTwoPanels",
+ "onboardingTheme",
+ "playbackProgressPrimaryColor",
+ "guidedActionTitleMaxLines",
+ "guidedActionPressedAnimation",
+ "playbackMediaItemNumberViewFlipperLayout",
+ "imageCardViewStyle",
+ "playbackControlsActionIcons",
+ "browseTitleViewLayout",
+ "playbackControlsIconHighlightColor",
+ "guidedStepTheme",
+ "guidedActionTitleMinLines",
+ "defaultBrandColorDark",
+ "baseCardViewStyle",
+ "browseTitleViewStyle",
+ "guidedActionVerticalPadding",
+ "guidedActionDisabledChevronAlpha",
+ "searchOrbViewStyle",
+ "defaultBrandColor",
+ "guidedStepThemeFlag",
+ "rowHeaderStyle",
+ "guidedActionDescriptionMinLines",
+ "guidedActionUnpressedAnimation",
+ "guidedActionEnabledChevronAlpha"
+ ]
+ },
+ "android/support/media/ExifInterface$ExifTag": {
+ "androidx/media/ExifInterface$ExifTag": [
+ "number",
+ "primaryFormat",
+ "name",
+ "secondaryFormat"
+ ]
+ },
+ "android/support/v4/widget/ContentLoadingProgressBar": {
+ "androidx/widget/ContentLoadingProgressBar": [
+ "MIN_DELAY",
+ "MIN_SHOW_TIME"
+ ]
+ },
+ "android/support/transition/ViewGroupUtilsApi14": {
+ "androidx/transition/ViewGroupUtilsApi14": [
+ "TAG",
+ "LAYOUT_TRANSITION_CHANGING",
+ "sEmptyLayoutTransition",
+ "sCancelMethod",
+ "sLayoutSuppressedField",
+ "sCancelMethodFetched",
+ "sLayoutSuppressedFieldFetched"
+ ]
+ },
+ "android/support/design/internal/NavigationMenuPresenter$NavigationMenuAdapter": {
+ "androidx/design/internal/NavigationMenuPresenter$NavigationMenuAdapter": [
+ "STATE_ACTION_VIEWS",
+ "VIEW_TYPE_SEPARATOR",
+ "VIEW_TYPE_HEADER",
+ "VIEW_TYPE_SUBHEADER",
+ "VIEW_TYPE_NORMAL",
+ "STATE_CHECKED_ITEM"
+ ]
+ },
+ "android/support/v4/os/LocaleListHelper": {
+ "androidx/os/LocaleListHelper": [
+ "EN_LATN",
+ "LOCALE_EN_XA",
+ "sDefaultAdjustedLocaleList",
+ "sLock",
+ "sLastExplicitlySetLocaleList",
+ "sEmptyLocaleList",
+ "sEmptyList",
+ "NUM_PSEUDO_LOCALES",
+ "STRING_AR_XB",
+ "sDefaultLocaleList",
+ "sLastDefaultLocale",
+ "STRING_EN_XA",
+ "LOCALE_AR_XB"
+ ]
+ },
+ "android/support/v4/app/NotificationCompat$CarExtender": {
+ "androidx/app/NotificationCompat$CarExtender": [
+ "KEY_TIMESTAMP",
+ "EXTRA_LARGE_ICON",
+ "KEY_ON_READ",
+ "KEY_PARTICIPANTS",
+ "KEY_ON_REPLY",
+ "KEY_AUTHOR",
+ "KEY_REMOTE_INPUT",
+ "KEY_TEXT",
+ "KEY_MESSAGES",
+ "EXTRA_CAR_EXTENDER",
+ "EXTRA_COLOR",
+ "EXTRA_CONVERSATION"
+ ]
+ },
+ "android/support/wear/R$layout": {
+ "androidx/wear/R$layout": [
+ "ws_navigation_drawer_item_view",
+ "ws_single_page_nav_drawer_7_item",
+ "ws_single_page_nav_drawer_4_item",
+ "ws_action_drawer_item_view",
+ "ws_single_page_nav_drawer_2_item",
+ "ws_navigation_drawer_view",
+ "ws_single_page_nav_drawer_5_item",
+ "ws_wearable_drawer_view",
+ "ws_single_page_nav_drawer_3_item",
+ "ws_single_page_nav_drawer_peek_view",
+ "ws_action_drawer_title_view",
+ "ws_action_drawer_peek_view",
+ "ws_single_page_nav_drawer_1_item",
+ "ws_single_page_nav_drawer_6_item"
+ ]
+ },
+ "android/support/v4/content/pm/ActivityInfoCompat": {
+ "androidx/content/pm/ActivityInfoCompat": [
+ "CONFIG_UI_MODE"
+ ]
+ },
+ "android/support/v7/mediarouter/R$layout": {
+ "androidx/mediarouter/R$layout": [
+ "mr_chooser_dialog",
+ "mr_controller_material_dialog_b",
+ "mr_chooser_list_item",
+ "mr_controller_volume_item"
+ ]
+ },
+ "android/support/v7/app/AppCompatDelegateImplV9$PanelFeatureState": {
+ "androidx/app/AppCompatDelegateImplV9$PanelFeatureState": [
+ "x",
+ "y",
+ "frozenActionViewState",
+ "refreshDecorView",
+ "createdPanelView",
+ "frozenMenuState",
+ "qwertyMode",
+ "featureId",
+ "listPresenterContext",
+ "listMenuPresenter",
+ "decorView",
+ "isPrepared",
+ "wasLastOpen",
+ "isOpen",
+ "gravity",
+ "background",
+ "isHandled",
+ "windowAnimations",
+ "refreshMenuContent",
+ "shownPanelView",
+ "menu"
+ ]
+ },
+ "android/support/v4/graphics/TypefaceCompatBaseImpl": {
+ "androidx/graphics/TypefaceCompatBaseImpl": [
+ "TAG",
+ "CACHE_FILE_PREFIX"
+ ]
+ },
+ "android/support/media/tv/TvContractCompat$PreviewProgramColumns": {
+ "androidx/media/tv/TvContractCompat$PreviewProgramColumns": [
+ "COLUMN_DURATION_MILLIS",
+ "COLUMN_LIVE",
+ "COLUMN_OFFER_PRICE",
+ "AVAILABILITY_PURCHASED",
+ "COLUMN_INTERACTION_COUNT",
+ "INTERACTION_TYPE_FOLLOWERS",
+ "INTERACTION_TYPE_FANS",
+ "COLUMN_GENRE",
+ "INTERACTION_TYPE_LISTENS",
+ "AVAILABILITY_PAID_CONTENT",
+ "COLUMN_START_TIME_UTC_MILLIS",
+ "COLUMN_INTERACTION_TYPE",
+ "TYPE_MOVIE",
+ "TYPE_GAME",
+ "TYPE_ALBUM",
+ "TYPE_TRACK",
+ "COLUMN_POSTER_ART_ASPECT_RATIO",
+ "TYPE_EVENT",
+ "COLUMN_AVAILABILITY",
+ "COLUMN_BROWSABLE",
+ "COLUMN_INTENT_URI",
+ "COLUMN_LOGO_URI",
+ "TYPE_TV_SERIES",
+ "COLUMN_ITEM_COUNT",
+ "INTERACTION_TYPE_VIEWS",
+ "COLUMN_PREVIEW_AUDIO_URI",
+ "AVAILABILITY_FREE_WITH_SUBSCRIPTION",
+ "COLUMN_PREVIEW_VIDEO_URI",
+ "COLUMN_LAST_PLAYBACK_POSITION_MILLIS",
+ "COLUMN_END_TIME_UTC_MILLIS",
+ "ASPECT_RATIO_4_3",
+ "INTERACTION_TYPE_THUMBS",
+ "INTERACTION_TYPE_VIEWERS",
+ "COLUMN_TYPE",
+ "ASPECT_RATIO_3_2",
+ "COLUMN_AUTHOR",
+ "TYPE_TV_EPISODE",
+ "ASPECT_RATIO_1_1",
+ "ASPECT_RATIO_2_3",
+ "COLUMN_INTERNAL_PROVIDER_ID",
+ "ASPECT_RATIO_MOVIE_POSTER",
+ "TYPE_CHANNEL",
+ "COLUMN_LOGO_CONTENT_DESCRIPTION",
+ "AVAILABILITY_FREE",
+ "COLUMN_TRANSIENT",
+ "TYPE_STATION",
+ "INTERACTION_TYPE_LIKES",
+ "TYPE_TV_SEASON",
+ "AVAILABILITY_AVAILABLE",
+ "TYPE_PLAYLIST",
+ "ASPECT_RATIO_16_9",
+ "COLUMN_RELEASE_DATE",
+ "COLUMN_CONTENT_ID",
+ "TYPE_ARTIST",
+ "COLUMN_THUMBNAIL_ASPECT_RATIO",
+ "COLUMN_STARTING_PRICE",
+ "TYPE_CLIP"
+ ]
+ },
+ "android/support/wear/widget/BoxInsetLayout": {
+ "androidx/wear/widget/BoxInsetLayout": [
+ "FACTOR",
+ "DEFAULT_CHILD_GRAVITY"
+ ]
+ },
+ "android/support/v7/graphics/ColorCutQuantizer": {
+ "androidx/graphics/palette/ColorCutQuantizer": [
+ "LOG_TAG",
+ "COMPONENT_GREEN",
+ "VBOX_COMPARATOR_VOLUME",
+ "LOG_TIMINGS",
+ "COMPONENT_RED",
+ "COMPONENT_BLUE",
+ "QUANTIZE_WORD_WIDTH",
+ "QUANTIZE_WORD_MASK"
+ ]
+ },
+ "android/support/text/emoji/flatbuffer/Struct": {
+ "androidx/text/emoji/flatbuffer/Struct": [
+ "bb",
+ "bb_pos"
+ ]
+ },
+ "android/support/media/instantvideo/BuildConfig": {
+ "androidx/media/instantvideo/BuildConfig": [
+ "VERSION_CODE",
+ "DEBUG",
+ "FLAVOR",
+ "APPLICATION_ID",
+ "BUILD_TYPE",
+ "VERSION_NAME"
+ ]
+ },
+ "android/support/v4/media/session/MediaSessionCompat": {
+ "androidx/media/session/MediaSessionCompat": [
+ "TAG",
+ "EXTRA_BINDER",
+ "ARGUMENT_MEDIA_ATTRIBUTE_VALUE",
+ "ACTION_PREPARE_FROM_MEDIA_ID",
+ "ACTION_FLAG_AS_INAPPROPRIATE",
+ "ACTION_SET_CAPTIONING_ENABLED",
+ "MEDIA_ATTRIBUTE_PLAYLIST",
+ "sMaxBitmapSize",
+ "MAX_BITMAP_SIZE_IN_DP",
+ "FLAG_HANDLES_MEDIA_BUTTONS",
+ "ACTION_ARGUMENT_CAPTIONING_ENABLED",
+ "ACTION_SET_SHUFFLE_MODE",
+ "ACTION_ARGUMENT_EXTRAS",
+ "ACTION_SKIP_AD",
+ "ACTION_ARGUMENT_REPEAT_MODE",
+ "FLAG_HANDLES_TRANSPORT_CONTROLS",
+ "ACTION_ARGUMENT_QUERY",
+ "ACTION_ARGUMENT_MEDIA_ID",
+ "ACTION_PREPARE_FROM_SEARCH",
+ "FLAG_HANDLES_QUEUE_COMMANDS",
+ "ACTION_UNFOLLOW",
+ "ACTION_ARGUMENT_RATING",
+ "ACTION_ARGUMENT_URI",
+ "ACTION_PLAY_FROM_URI",
+ "MEDIA_ATTRIBUTE_ALBUM",
+ "ACTION_SET_RATING",
+ "ACTION_SET_REPEAT_MODE",
+ "ACTION_ARGUMENT_SHUFFLE_MODE",
+ "ACTION_FOLLOW",
+ "ACTION_PREPARE_FROM_URI",
+ "ACTION_PREPARE",
+ "ARGUMENT_MEDIA_ATTRIBUTE",
+ "MEDIA_ATTRIBUTE_ARTIST"
+ ]
+ },
+ "android/support/v17/leanback/widget/GridLayoutManager": {
+ "androidx/leanback/widget/GridLayoutManager": [
+ "PREV_ROW",
+ "NEXT_ITEM",
+ "DEBUG",
+ "DEFAULT_MAX_PENDING_MOVES",
+ "TRACE",
+ "MIN_MS_SMOOTH_SCROLL_MAIN_SCREEN",
+ "sTempRect",
+ "NEXT_ROW",
+ "TAG",
+ "PREV_ITEM",
+ "sTwoInts"
+ ]
+ },
+ "android/support/v14/preference/BuildConfig": {
+ "androidx/preference/BuildConfig": [
+ "APPLICATION_ID",
+ "DEBUG",
+ "VERSION_CODE",
+ "FLAVOR",
+ "BUILD_TYPE",
+ "VERSION_NAME"
+ ]
+ },
+ "android/support/v4/util/TimeUtils": {
+ "androidx/util/TimeUtils": [
+ "HUNDRED_DAY_FIELD_LEN",
+ "SECONDS_PER_MINUTE",
+ "sFormatSync",
+ "sFormatStr",
+ "SECONDS_PER_DAY",
+ "SECONDS_PER_HOUR"
+ ]
+ },
+ "android/support/v4/view/accessibility/AccessibilityWindowInfoCompat": {
+ "androidx/view/accessibility/AccessibilityWindowInfoCompat": [
+ "TYPE_APPLICATION",
+ "TYPE_SYSTEM",
+ "TYPE_ACCESSIBILITY_OVERLAY",
+ "TYPE_INPUT_METHOD",
+ "UNDEFINED",
+ "TYPE_SPLIT_SCREEN_DIVIDER"
+ ]
+ },
+ "android/support/v17/leanback/app/VerticalGridFragment": {
+ "androidx/leanback/app/VerticalGridFragment": [
+ "STATE_SET_ENTRANCE_START_STATE",
+ "EVT_ON_CREATEVIEW",
+ "STATE_ENTRANCE_ON_PREPARED",
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/v4/app/FrameMetricsAggregator": {
+ "androidx/app/FrameMetricsAggregator": [
+ "COMMAND_INDEX",
+ "SWAP_DURATION",
+ "SYNC_INDEX",
+ "ANIMATION_INDEX",
+ "LAYOUT_MEASURE_DURATION",
+ "INPUT_INDEX",
+ "TOTAL_INDEX",
+ "LAST_INDEX",
+ "LAYOUT_MEASURE_INDEX",
+ "DELAY_DURATION",
+ "COMMAND_DURATION",
+ "DBG",
+ "INPUT_DURATION",
+ "SWAP_INDEX",
+ "SYNC_DURATION",
+ "TOTAL_DURATION",
+ "TAG",
+ "ANIMATION_DURATION",
+ "DRAW_DURATION",
+ "DRAW_INDEX",
+ "EVERY_DURATION",
+ "DELAY_INDEX"
+ ]
+ },
+ "android/support/design/widget/FloatingActionButtonImpl": {
+ "androidx/design/widget/FloatingActionButtonImpl": [
+ "PRESSED_ENABLED_STATE_SET",
+ "PRESSED_ANIM_DURATION",
+ "PRESSED_ANIM_DELAY",
+ "FOCUSED_ENABLED_STATE_SET",
+ "ANIM_STATE_NONE",
+ "EMPTY_STATE_SET",
+ "ANIM_INTERPOLATOR",
+ "ENABLED_STATE_SET",
+ "ANIM_STATE_SHOWING",
+ "SHOW_HIDE_ANIM_DURATION",
+ "ANIM_STATE_HIDING"
+ ]
+ },
+ "android/support/transition/R$id": {
+ "androidx/transition/R$id": [
+ "transition_transform",
+ "ghost_view",
+ "transition_scene_layoutid_cache",
+ "save_image_matrix",
+ "save_scale_type",
+ "transition_current_scene",
+ "transition_layout_save",
+ "parent_matrix",
+ "transition_position",
+ "save_non_transition_alpha"
+ ]
+ },
+ "android/support/v7/app/ResourcesFlusher": {
+ "androidx/app/ResourcesFlusher": [
+ "sDrawableCacheField",
+ "sThemedResourceCacheClazz",
+ "sResourcesImplFieldFetched",
+ "sDrawableCacheFieldFetched",
+ "TAG",
+ "sThemedResourceCacheClazzFetched",
+ "sResourcesImplField",
+ "sThemedResourceCache_mUnthemedEntriesFieldFetched",
+ "sThemedResourceCache_mUnthemedEntriesField"
+ ]
+ },
+ "android/support/v4/app/RemoteInput": {
+ "androidx/app/RemoteInput": [
+ "EXTRA_RESULTS_DATA",
+ "TAG",
+ "RESULTS_CLIP_LABEL",
+ "EXTRA_DATA_TYPE_RESULTS_DATA"
+ ]
+ },
+ "android/support/media/tv/TvContractCompat$Programs$Genres": {
+ "androidx/media/tv/TvContractCompat$Programs$Genres": [
+ "EDUCATION",
+ "DELIMITER",
+ "LIFE_STYLE",
+ "SPORTS",
+ "GAMING",
+ "TECH_SCIENCE",
+ "DOUBLE_QUOTE",
+ "TRAVEL",
+ "CANONICAL_GENRES",
+ "MOVIES",
+ "FAMILY_KIDS",
+ "NEWS",
+ "ENTERTAINMENT",
+ "PREMIER",
+ "ARTS",
+ "EMPTY_STRING_ARRAY",
+ "DRAMA",
+ "MUSIC",
+ "COMMA",
+ "COMEDY",
+ "SHOPPING",
+ "ANIMAL_WILDLIFE"
+ ]
+ },
+ "android/support/v4/view/GravityCompat": {
+ "androidx/view/GravityCompat": [
+ "START",
+ "END",
+ "RELATIVE_LAYOUT_DIRECTION",
+ "RELATIVE_HORIZONTAL_GRAVITY_MASK"
+ ]
+ },
+ "android/support/design/R$color": {
+ "androidx/design/R$color": [
+ "design_fab_shadow_start_color",
+ "design_bottom_navigation_shadow_color",
+ "design_fab_stroke_end_outer_color",
+ "design_fab_shadow_mid_color",
+ "design_fab_stroke_end_inner_color",
+ "design_fab_shadow_end_color",
+ "design_fab_stroke_top_inner_color",
+ "design_fab_stroke_top_outer_color"
+ ]
+ },
+ "android/support/v4/view/LayoutInflaterCompat": {
+ "androidx/view/LayoutInflaterCompat": [
+ "sLayoutInflaterFactory2Field",
+ "TAG",
+ "sCheckedField",
+ "IMPL"
+ ]
+ },
+ "android/support/v13/view/inputmethod/EditorInfoCompat": {
+ "androidx/view/inputmethod/EditorInfoCompat": [
+ "IMPL",
+ "IME_FLAG_NO_PERSONALIZED_LEARNING",
+ "EMPTY_STRING_ARRAY",
+ "IME_FLAG_FORCE_ASCII"
+ ]
+ },
+ "android/support/v17/leanback/app/OnboardingSupportFragment": {
+ "androidx/leanback/app/OnboardingSupportFragment": [
+ "KEY_ENTER_ANIMATION_FINISHED",
+ "KEY_CURRENT_PAGE_INDEX",
+ "DEBUG",
+ "HEADER_DISAPPEAR_INTERPOLATOR",
+ "sSlideDistance",
+ "LOGO_SPLASH_PAUSE_DURATION_MS",
+ "HEADER_APPEAR_DELAY_MS",
+ "HEADER_ANIMATION_DURATION_MS",
+ "TAG",
+ "HEADER_APPEAR_INTERPOLATOR",
+ "DESCRIPTION_START_DELAY_MS",
+ "SLIDE_DISTANCE",
+ "KEY_LOGO_ANIMATION_FINISHED"
+ ]
+ },
+ "android/support/v4/app/BackStackRecord": {
+ "androidx/app/BackStackRecord": [
+ "TAG",
+ "OP_SET_PRIMARY_NAV",
+ "OP_DETACH",
+ "OP_NULL",
+ "OP_UNSET_PRIMARY_NAV",
+ "OP_REMOVE",
+ "OP_HIDE",
+ "OP_SHOW",
+ "OP_ADD",
+ "OP_REPLACE",
+ "OP_ATTACH"
+ ]
+ },
+ "android/support/v7/util/DiffUtil$DiffResult": {
+ "androidx/util/DiffUtil$DiffResult": [
+ "FLAG_MOVED_CHANGED",
+ "FLAG_IGNORE",
+ "FLAG_MASK",
+ "FLAG_OFFSET",
+ "FLAG_MOVED_NOT_CHANGED",
+ "FLAG_CHANGED",
+ "FLAG_NOT_CHANGED"
+ ]
+ },
+ "android/support/wear/widget/drawer/WearableDrawerView": {
+ "androidx/wear/widget/drawer/WearableDrawerView": [
+ "STATE_DRAGGING",
+ "STATE_SETTLING",
+ "STATE_IDLE"
+ ]
+ },
+ "android/support/wear/R$string": {
+ "androidx/wear/R$string": [
+ "ws_action_drawer_content_description",
+ "ws_navigation_drawer_content_description"
+ ]
+ },
+ "android/support/design/widget/SwipeDismissBehavior": {
+ "androidx/design/widget/SwipeDismissBehavior": [
+ "DEFAULT_ALPHA_START_DISTANCE",
+ "STATE_IDLE",
+ "STATE_DRAGGING",
+ "SWIPE_DIRECTION_START_TO_END",
+ "DEFAULT_ALPHA_END_DISTANCE",
+ "DEFAULT_DRAG_DISMISS_THRESHOLD",
+ "SWIPE_DIRECTION_ANY",
+ "STATE_SETTLING",
+ "SWIPE_DIRECTION_END_TO_START"
+ ]
+ },
+ "android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper": {
+ "androidx/leanback/widget/FullWidthDetailsOverviewSharedElementHelper": [
+ "DEFAULT_TIMEOUT",
+ "TAG",
+ "DEBUG"
+ ]
+ },
+ "android/support/transition/Styleable$TransitionTarget": {
+ "androidx/transition/Styleable$TransitionTarget": [
+ "EXCLUDE_CLASS",
+ "EXCLUDE_ID",
+ "TARGET_CLASS",
+ "EXCLUDE_NAME",
+ "TARGET_ID",
+ "TARGET_NAME"
+ ]
+ },
+ "android/support/v4/media/MediaDescriptionCompat": {
+ "androidx/media/MediaDescriptionCompat": [
+ "BT_FOLDER_TYPE_MIXED",
+ "CREATOR",
+ "STATUS_DOWNLOADED",
+ "STATUS_NOT_DOWNLOADED",
+ "EXTRA_BT_FOLDER_TYPE",
+ "BT_FOLDER_TYPE_GENRES",
+ "EXTRA_DOWNLOAD_STATUS",
+ "DESCRIPTION_KEY_MEDIA_URI",
+ "BT_FOLDER_TYPE_ARTISTS",
+ "DESCRIPTION_KEY_NULL_BUNDLE_FLAG",
+ "BT_FOLDER_TYPE_TITLES",
+ "STATUS_DOWNLOADING",
+ "BT_FOLDER_TYPE_YEARS",
+ "BT_FOLDER_TYPE_PLAYLISTS",
+ "BT_FOLDER_TYPE_ALBUMS"
+ ]
+ },
+ "android/support/v4/graphics/ColorUtils": {
+ "androidx/graphics/ColorUtils": [
+ "MIN_ALPHA_SEARCH_MAX_ITERATIONS",
+ "XYZ_KAPPA",
+ "MIN_ALPHA_SEARCH_PRECISION",
+ "TEMP_ARRAY",
+ "XYZ_WHITE_REFERENCE_Z",
+ "XYZ_WHITE_REFERENCE_Y",
+ "XYZ_WHITE_REFERENCE_X",
+ "XYZ_EPSILON"
+ ]
+ },
+ "android/support/v7/widget/AppCompatTextViewAutoSizeHelper": {
+ "androidx/widget/AppCompatTextViewAutoSizeHelper": [
+ "TAG",
+ "DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX",
+ "UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE",
+ "DEFAULT_AUTO_SIZE_MIN_TEXT_SIZE_IN_SP",
+ "VERY_WIDE",
+ "sTextViewMethodByNameCache",
+ "DEFAULT_AUTO_SIZE_MAX_TEXT_SIZE_IN_SP",
+ "TEMP_RECTF"
+ ]
+ },
+ "android/support/design/R$style": {
+ "androidx/design/R$style": [
+ "Widget_Design_ScrimInsetsFrameLayout",
+ "Widget_Design_TextInputLayout",
+ "Widget_Design_TabLayout",
+ "Widget_Design_CollapsingToolbar",
+ "Widget_Design_NavigationView",
+ "TextAppearance_Design_Tab",
+ "Widget_Design_CoordinatorLayout",
+ "Theme_Design_Light_BottomSheetDialog",
+ "Widget_Design_FloatingActionButton",
+ "Widget_Design_AppBarLayout",
+ "Widget_Design_BottomNavigationView",
+ "TextAppearance_Design_CollapsingToolbar_Expanded"
+ ]
+ },
+ "android/support/v7/widget/GridLayoutManager": {
+ "androidx/widget/GridLayoutManager": [
+ "TAG",
+ "DEFAULT_SPAN_COUNT",
+ "DEBUG"
+ ]
+ },
+ "android/support/v7/appcompat/R$dimen": {
+ "androidx/appcompat/R$dimen": [
+ "tooltip_precise_anchor_extra_offset",
+ "abc_dropdownitem_icon_width",
+ "tooltip_precise_anchor_threshold",
+ "tooltip_y_offset_non_touch",
+ "abc_config_prefDialogWidth",
+ "abc_dropdownitem_text_padding_left",
+ "abc_action_bar_stacked_max_height",
+ "abc_search_view_preferred_height",
+ "abc_cascading_menus_min_smallest_width",
+ "abc_action_bar_stacked_tab_max_width",
+ "tooltip_y_offset_touch",
+ "abc_search_view_preferred_width"
+ ]
+ },
+ "android/support/wear/internal/widget/drawer/SinglePageUi": {
+ "androidx/wear/internal/widget/drawer/SinglePageUi": [
+ "SINGLE_PAGE_LAYOUT_RES",
+ "SINGLE_PAGE_BUTTON_IDS"
+ ]
+ },
+ "android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat": {
+ "androidx/accessibilityservice/AccessibilityServiceInfoCompat": [
+ "FLAG_REQUEST_TOUCH_EXPLORATION_MODE",
+ "CAPABILITY_CAN_FILTER_KEY_EVENTS",
+ "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS",
+ "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY",
+ "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT",
+ "FEEDBACK_BRAILLE",
+ "FEEDBACK_ALL_MASK",
+ "FLAG_REPORT_VIEW_IDS",
+ "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION",
+ "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY",
+ "FLAG_REQUEST_FILTER_KEY_EVENTS"
+ ]
+ },
+ "android/support/graphics/drawable/AnimatorInflaterCompat": {
+ "androidx/graphics/drawable/AnimatorInflaterCompat": [
+ "MAX_NUM_POINTS",
+ "VALUE_TYPE_INT",
+ "VALUE_TYPE_FLOAT",
+ "VALUE_TYPE_COLOR",
+ "TAG",
+ "DBG_ANIMATOR_INFLATER",
+ "VALUE_TYPE_PATH",
+ "TOGETHER",
+ "VALUE_TYPE_UNDEFINED"
+ ]
+ },
+ "android/support/wear/R$id": {
+ "androidx/wear/R$id": [
+ "ws_navigation_drawer_item_icon",
+ "ws_drawer_view_peek_container",
+ "ws_navigation_drawer_item_text",
+ "ws_action_drawer_item_text",
+ "ws_drawer_view_peek_icon",
+ "ws_nav_drawer_icon_4",
+ "ws_nav_drawer_icon_5",
+ "ws_nav_drawer_icon_6",
+ "ws_nav_drawer_icon_0",
+ "ws_nav_drawer_icon_1",
+ "ws_nav_drawer_icon_2",
+ "ws_nav_drawer_icon_3",
+ "ws_navigation_drawer_page_indicator",
+ "ws_navigation_drawer_view_pager",
+ "ws_nav_drawer_text",
+ "ws_action_drawer_expand_icon",
+ "ws_action_drawer_item_icon",
+ "ws_action_drawer_title",
+ "ws_action_drawer_peek_action_icon"
+ ]
+ },
+ "android/support/v4/view/animation/LinearOutSlowInInterpolator": {
+ "androidx/view/animation/LinearOutSlowInInterpolator": [
+ "VALUES"
+ ]
+ },
+ "android/support/v4/graphics/TypefaceCompatApi24Impl": {
+ "androidx/graphics/TypefaceCompatApi24Impl": [
+ "FONT_FAMILY_CLASS",
+ "sFontFamily",
+ "TAG",
+ "sAddFontWeightStyle",
+ "sFontFamilyCtor",
+ "sCreateFromFamiliesWithDefault",
+ "ADD_FONT_WEIGHT_STYLE_METHOD",
+ "CREATE_FROM_FAMILIES_WITH_DEFAULT_METHOD"
+ ]
+ },
+ "android/support/v7/widget/AdapterHelper": {
+ "androidx/widget/AdapterHelper": [
+ "TAG",
+ "POSITION_TYPE_NEW_OR_LAID_OUT",
+ "DEBUG",
+ "POSITION_TYPE_INVISIBLE"
+ ]
+ },
+ "android/support/wear/BuildConfig": {
+ "androidx/wear/BuildConfig": [
+ "VERSION_CODE",
+ "DEBUG",
+ "FLAVOR",
+ "BUILD_TYPE",
+ "APPLICATION_ID",
+ "VERSION_NAME"
+ ]
+ },
+ "android/support/v4/media/session/ParcelableVolumeInfo": {
+ "androidx/media/session/ParcelableVolumeInfo": [
+ "audioStream",
+ "currentVolume",
+ "maxVolume",
+ "volumeType",
+ "CREATOR",
+ "controlType"
+ ]
+ },
+ "android/support/text/emoji/EmojiCompat": {
+ "androidx/text/emoji/EmojiCompat": [
+ "EDITOR_INFO_REPLACE_ALL_KEY",
+ "sInstanceLock",
+ "EMOJI_COUNT_UNLIMITED",
+ "LOAD_STATE_SUCCEEDED",
+ "EDITOR_INFO_METAVERSION_KEY",
+ "sInstance",
+ "REPLACE_STRATEGY_ALL",
+ "LOAD_STATE_FAILED",
+ "REPLACE_STRATEGY_NON_EXISTENT",
+ "LOAD_STATE_LOADING",
+ "REPLACE_STRATEGY_DEFAULT"
+ ]
+ },
+ "android/support/v7/graphics/Target": {
+ "androidx/graphics/palette/Target": [
+ "TARGET_MUTED_SATURATION",
+ "MUTED",
+ "MIN_NORMAL_LUMA",
+ "MAX_DARK_LUMA",
+ "VIBRANT",
+ "TARGET_LIGHT_LUMA",
+ "TARGET_NORMAL_LUMA",
+ "MAX_NORMAL_LUMA",
+ "WEIGHT_LUMA",
+ "INDEX_WEIGHT_LUMA",
+ "TARGET_VIBRANT_SATURATION",
+ "DARK_MUTED",
+ "DARK_VIBRANT",
+ "INDEX_MAX",
+ "INDEX_MIN",
+ "MAX_MUTED_SATURATION",
+ "MIN_LIGHT_LUMA",
+ "LIGHT_VIBRANT",
+ "LIGHT_MUTED",
+ "INDEX_TARGET",
+ "INDEX_WEIGHT_POP",
+ "TARGET_DARK_LUMA",
+ "WEIGHT_POPULATION",
+ "INDEX_WEIGHT_SAT",
+ "WEIGHT_SATURATION",
+ "MIN_VIBRANT_SATURATION"
+ ]
+ },
+ "android/support/v17/leanback/media/PlaybackControlGlue": {
+ "androidx/leanback/media/PlaybackControlGlue": [
+ "MSG_UPDATE_PLAYBACK_STATE",
+ "PLAYBACK_SPEED_INVALID",
+ "ACTION_REWIND",
+ "sHandler",
+ "ACTION_FAST_FORWARD",
+ "PLAYBACK_SPEED_FAST_L2",
+ "PLAYBACK_SPEED_FAST_L3",
+ "PLAYBACK_SPEED_FAST_L4",
+ "PLAYBACK_SPEED_FAST_L0",
+ "PLAYBACK_SPEED_FAST_L1",
+ "DEBUG",
+ "PLAYBACK_SPEED_PAUSED",
+ "UPDATE_PLAYBACK_STATE_DELAY_MS",
+ "PLAYBACK_SPEED_NORMAL",
+ "TAG",
+ "ACTION_SKIP_TO_NEXT",
+ "ACTION_SKIP_TO_PREVIOUS",
+ "ACTION_CUSTOM_LEFT_FIRST",
+ "ACTION_PLAY_PAUSE",
+ "NUMBER_OF_SEEK_SPEEDS",
+ "ACTION_CUSTOM_RIGHT_FIRST"
+ ]
+ },
+ "android/support/v7/widget/GridLayout$LayoutParams": {
+ "androidx/widget/GridLayout$LayoutParams": [
+ "bottomMargin",
+ "DEFAULT_SPAN",
+ "COLUMN_WEIGHT",
+ "leftMargin",
+ "GRAVITY",
+ "ROW_SPAN",
+ "ROW",
+ "COLUMN",
+ "topMargin",
+ "RIGHT_MARGIN",
+ "height",
+ "COLUMN_SPAN",
+ "rightMargin",
+ "width",
+ "ROW_WEIGHT",
+ "BOTTOM_MARGIN",
+ "DEFAULT_SPAN_SIZE",
+ "columnSpec",
+ "DEFAULT_ROW",
+ "DEFAULT_WIDTH",
+ "MARGIN",
+ "rowSpec",
+ "TOP_MARGIN",
+ "DEFAULT_HEIGHT",
+ "LEFT_MARGIN",
+ "DEFAULT_COLUMN",
+ "DEFAULT_MARGIN"
+ ]
+ },
+ "android/support/v17/leanback/app/DetailsSupportFragment": {
+ "androidx/leanback/app/DetailsSupportFragment": [
+ "EVT_ONSTART",
+ "STATE_ENTER_TRANSITION_CANCEL",
+ "DEBUG",
+ "STATE_SWITCH_TO_VIDEO_IN_ON_CREATE",
+ "STATE_ENTRANCE_COMPLETE",
+ "STATE_ENTER_TRANSITION_COMPLETE",
+ "STATE_ENTER_TRANSITION_ADDLISTENER",
+ "STATE_ENTRANCE_INIT",
+ "EVT_SWITCH_TO_VIDEO",
+ "STATE_START",
+ "STATE_ON_SAFE_START",
+ "STATE_ENTRANCE_PERFORM",
+ "EVT_ON_CREATEVIEW",
+ "STATE_SET_ENTRANCE_START_STATE",
+ "COND_TRANSITION_NOT_SUPPORTED",
+ "TAG",
+ "STATE_ENTER_TRANSITION_PENDING",
+ "EVT_ENTER_TRANSIITON_DONE",
+ "STATE_ENTRANCE_ON_PREPARED",
+ "EVT_ON_CREATE",
+ "EVT_DETAILS_ROW_LOADED",
+ "STATE_ENTER_TRANSITION_INIT",
+ "EVT_NO_ENTER_TRANSITION"
+ ]
+ },
+ "android/support/v17/leanback/app/ListRowDataAdapter": {
+ "androidx/leanback/app/ListRowDataAdapter": [
+ "ON_ITEM_RANGE_INSERTED",
+ "ON_ITEM_RANGE_CHANGED",
+ "ON_ITEM_RANGE_REMOVED",
+ "ON_CHANGED"
+ ]
+ },
+ "android/support/percent/PercentLayoutHelper$PercentLayoutInfo": {
+ "androidx/PercentLayoutHelper$PercentLayoutInfo": [
+ "topMarginPercent",
+ "endMarginPercent",
+ "aspectRatio",
+ "rightMarginPercent",
+ "heightPercent",
+ "leftMarginPercent",
+ "startMarginPercent",
+ "bottomMarginPercent",
+ "widthPercent"
+ ]
+ },
+ "android/support/v17/leanback/system/Settings": {
+ "androidx/leanback/system/Settings": [
+ "OUTLINE_CLIPPING_DISABLED",
+ "PREFER_STATIC_SHADOWS",
+ "DEBUG",
+ "sInstance",
+ "ACTION_PARTNER_CUSTOMIZATION",
+ "TAG"
+ ]
+ },
+ "android/support/v4/util/SimpleArrayMap": {
+ "androidx/util/SimpleArrayMap": [
+ "BASE_SIZE",
+ "CONCURRENT_MODIFICATION_EXCEPTIONS",
+ "DEBUG",
+ "TAG",
+ "CACHE_SIZE"
+ ]
+ },
+ "android/support/v4/widget/AutoScrollHelper": {
+ "androidx/widget/AutoScrollHelper": [
+ "EDGE_TYPE_OUTSIDE",
+ "NO_MIN",
+ "NO_MAX",
+ "HORIZONTAL",
+ "EDGE_TYPE_INSIDE_EXTEND",
+ "DEFAULT_MAXIMUM_EDGE",
+ "VERTICAL",
+ "EDGE_TYPE_INSIDE",
+ "RELATIVE_UNSPECIFIED",
+ "DEFAULT_MAXIMUM_VELOCITY_DIPS",
+ "DEFAULT_RAMP_DOWN_DURATION",
+ "DEFAULT_RELATIVE_VELOCITY",
+ "DEFAULT_ACTIVATION_DELAY",
+ "DEFAULT_MINIMUM_VELOCITY_DIPS",
+ "DEFAULT_RAMP_UP_DURATION",
+ "DEFAULT_EDGE_TYPE",
+ "DEFAULT_RELATIVE_EDGE"
+ ]
+ },
+ "android/support/v7/widget/ViewInfoStore$InfoRecord": {
+ "androidx/widget/ViewInfoStore$InfoRecord": [
+ "FLAG_PRE",
+ "postInfo",
+ "FLAG_APPEAR_AND_DISAPPEAR",
+ "FLAG_PRE_AND_POST",
+ "FLAG_DISAPPEARED",
+ "preInfo",
+ "flags",
+ "FLAG_APPEAR",
+ "FLAG_APPEAR_PRE_AND_POST",
+ "FLAG_POST",
+ "sPool"
+ ]
+ },
+ "android/support/design/widget/AnimationUtils": {
+ "androidx/design/widget/AnimationUtils": [
+ "LINEAR_OUT_SLOW_IN_INTERPOLATOR",
+ "LINEAR_INTERPOLATOR",
+ "FAST_OUT_LINEAR_IN_INTERPOLATOR",
+ "FAST_OUT_SLOW_IN_INTERPOLATOR",
+ "DECELERATE_INTERPOLATOR"
+ ]
+ },
+ "android/support/design/widget/SnackbarManager$SnackbarRecord": {
+ "androidx/design/widget/SnackbarManager$SnackbarRecord": [
+ "duration",
+ "callback",
+ "paused"
+ ]
+ },
+ "android/support/transition/ChangeScroll": {
+ "androidx/transition/ChangeScroll": [
+ "PROPNAME_SCROLL_X",
+ "PROPNAME_SCROLL_Y",
+ "PROPERTIES"
+ ]
+ },
+ "android/support/design/widget/FloatingActionButtonLollipop": {
+ "androidx/design/widget/FloatingActionButtonLollipop": [
+ "EMPTY_STATE_SET",
+ "ENABLED_STATE_SET",
+ "PRESSED_ENABLED_STATE_SET",
+ "ANIM_INTERPOLATOR",
+ "FOCUSED_ENABLED_STATE_SET"
+ ]
+ },
+ "android/support/v4/graphics/TypefaceCompat": {
+ "androidx/graphics/TypefaceCompat": [
+ "sTypefaceCompatImpl",
+ "TAG",
+ "sTypefaceCache"
+ ]
+ },
+ "android/support/v7/widget/LinearSmoothScroller": {
+ "androidx/widget/LinearSmoothScroller": [
+ "MILLISECONDS_PER_PX",
+ "SNAP_TO_ANY",
+ "SNAP_TO_END",
+ "DEBUG",
+ "TAG",
+ "MILLISECONDS_PER_INCH",
+ "TARGET_SEEK_SCROLL_DISTANCE_PX",
+ "TARGET_SEEK_EXTRA_SCROLL_RATIO",
+ "SNAP_TO_START"
+ ]
+ },
+ "android/support/transition/Styleable$ChangeTransform": {
+ "androidx/transition/Styleable$ChangeTransform": [
+ "REPARENT_WITH_OVERLAY",
+ "REPARENT"
+ ]
+ },
+ "android/support/animation/DynamicAnimation": {
+ "androidx/animation/DynamicAnimation": [
+ "MIN_VISIBLE_CHANGE_ALPHA",
+ "MIN_VISIBLE_CHANGE_ROTATION_DEGREES",
+ "UNSET",
+ "ROTATION_Y",
+ "ROTATION_X",
+ "ALPHA",
+ "Z",
+ "X",
+ "Y",
+ "SCROLL_Y",
+ "SCROLL_X",
+ "TRANSLATION_Z",
+ "TRANSLATION_X",
+ "TRANSLATION_Y",
+ "THRESHOLD_MULTIPLIER",
+ "ROTATION",
+ "MIN_VISIBLE_CHANGE_SCALE",
+ "SCALE_Y",
+ "SCALE_X",
+ "MIN_VISIBLE_CHANGE_PIXELS"
+ ]
+ },
+ "android/support/constraint/solver/widgets/ConstraintWidget$DimensionBehaviour": {
+ "androidx/constraint/solver/widgets/ConstraintWidget$DimensionBehaviour": [
+ "FIXED",
+ "MATCH_PARENT",
+ "WRAP_CONTENT",
+ "MATCH_CONSTRAINT"
+ ]
+ },
+ "android/support/v17/leanback/media/PlaybackBannerControlGlue": {
+ "androidx/leanback/media/PlaybackBannerControlGlue": [
+ "PLAYBACK_SPEED_PAUSED",
+ "ACTION_SKIP_TO_PREVIOUS",
+ "ACTION_SKIP_TO_NEXT",
+ "ACTION_CUSTOM_LEFT_FIRST",
+ "TAG",
+ "ACTION_PLAY_PAUSE",
+ "PLAYBACK_SPEED_NORMAL",
+ "ACTION_CUSTOM_RIGHT_FIRST",
+ "NUMBER_OF_SEEK_SPEEDS",
+ "ACTION_REWIND",
+ "PLAYBACK_SPEED_INVALID",
+ "PLAYBACK_SPEED_FAST_L1",
+ "PLAYBACK_SPEED_FAST_L0",
+ "PLAYBACK_SPEED_FAST_L4",
+ "PLAYBACK_SPEED_FAST_L3",
+ "PLAYBACK_SPEED_FAST_L2",
+ "ACTION_FAST_FORWARD"
+ ]
+ },
+ "android/support/transition/ChangeTransform": {
+ "androidx/transition/ChangeTransform": [
+ "PROPNAME_PARENT",
+ "TRANSLATIONS_PROPERTY",
+ "PROPNAME_INTERMEDIATE_PARENT_MATRIX",
+ "PROPNAME_TRANSFORMS",
+ "PROPNAME_INTERMEDIATE_MATRIX",
+ "sTransitionProperties",
+ "PROPNAME_MATRIX",
+ "PROPNAME_PARENT_MATRIX",
+ "NON_TRANSLATIONS_PROPERTY",
+ "SUPPORTS_VIEW_REMOVAL_SUPPRESSION"
+ ]
+ },
+ "android/support/v17/leanback/R$fraction": {
+ "androidx/leanback/R$fraction": [
+ "lb_focus_zoom_factor_xsmall",
+ "lb_focus_zoom_factor_medium",
+ "lb_browse_rows_scale",
+ "lb_search_orb_focused_zoom",
+ "lb_view_active_level",
+ "lb_focus_zoom_factor_large",
+ "lb_focus_zoom_factor_small",
+ "lb_browse_header_unselect_alpha",
+ "lb_view_dimmed_level",
+ "lb_search_bar_speech_orb_max_level_zoom"
+ ]
+ },
+ "android/support/v7/widget/LinearLayoutCompat$LayoutParams": {
+ "androidx/widget/LinearLayoutCompat$LayoutParams": [
+ "height",
+ "gravity",
+ "rightMargin",
+ "width",
+ "bottomMargin",
+ "leftMargin",
+ "topMargin",
+ "weight"
+ ]
+ },
+ "android/support/v7/preference/PreferenceViewHolder": {
+ "androidx/preference/PreferenceViewHolder": [
+ "itemView"
+ ]
+ },
+ "android/support/v7/util/MessageThreadUtil$SyncQueueItem": {
+ "androidx/util/MessageThreadUtil$SyncQueueItem": [
+ "sPoolLock",
+ "what",
+ "sPool",
+ "arg2",
+ "arg1",
+ "arg4",
+ "arg3",
+ "arg5",
+ "next",
+ "data"
+ ]
+ },
+ "android/support/v14/preference/PreferenceFragment": {
+ "androidx/preference/PreferenceFragment": [
+ "PREFERENCES_TAG",
+ "DIALOG_FRAGMENT_TAG",
+ "ARG_PREFERENCE_ROOT",
+ "MSG_BIND_PREFERENCES"
+ ]
+ },
+ "android/support/v7/gridlayout/R$styleable": {
+ "androidx/gridlayout/R$styleable": [
+ "GridLayout_Layout_android_layout_margin",
+ "GridLayout_Layout_layout_gravity",
+ "GridLayout_Layout_layout_column",
+ "GridLayout_Layout_layout_columnSpan",
+ "GridLayout_Layout_layout_row",
+ "GridLayout_Layout_layout_columnWeight",
+ "GridLayout_Layout_layout_rowWeight",
+ "GridLayout_Layout",
+ "GridLayout_Layout_android_layout_marginBottom",
+ "GridLayout_rowCount",
+ "GridLayout_columnCount",
+ "GridLayout_Layout_android_layout_marginRight",
+ "GridLayout",
+ "GridLayout_useDefaultMargins",
+ "GridLayout_rowOrderPreserved",
+ "GridLayout_columnOrderPreserved",
+ "GridLayout_Layout_android_layout_marginLeft",
+ "GridLayout_alignmentMode",
+ "GridLayout_Layout_layout_rowSpan",
+ "GridLayout_orientation",
+ "GridLayout_Layout_android_layout_marginTop"
+ ]
+ },
+ "android/support/v17/leanback/app/BackgroundManager": {
+ "androidx/leanback/app/BackgroundManager": [
+ "FULL_ALPHA",
+ "DEBUG",
+ "FRAGMENT_TAG",
+ "FADE_DURATION",
+ "CHANGE_BG_DELAY_MS",
+ "TAG"
+ ]
+ },
+ "android/support/customtabs/ICustomTabsService$Stub": {
+ "androidx/browser/customtabs/ICustomTabsService$Stub": [
+ "TRANSACTION_extraCommand",
+ "TRANSACTION_requestPostMessageChannel",
+ "TRANSACTION_postMessage",
+ "TRANSACTION_validateRelationship",
+ "TRANSACTION_warmup",
+ "TRANSACTION_updateVisuals",
+ "TRANSACTION_mayLaunchUrl",
+ "TRANSACTION_newSession",
+ "DESCRIPTOR"
+ ]
+ },
+ "android/support/v7/widget/Toolbar$SavedState": {
+ "androidx/widget/Toolbar$SavedState": [
+ "isOverflowOpen",
+ "expandedMenuItemId",
+ "CREATOR"
+ ]
+ },
+ "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter": {
+ "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter": [
+ "ALIGN_MODE_START",
+ "sTmpRect",
+ "STATE_HALF",
+ "TAG",
+ "STATE_SMALL",
+ "sHandler",
+ "ALIGN_MODE_MIDDLE",
+ "STATE_FULL",
+ "DEBUG"
+ ]
+ },
+ "android/support/v4/app/FragmentTabHost$SavedState": {
+ "androidx/app/FragmentTabHost$SavedState": [
+ "CREATOR",
+ "curTab"
+ ]
+ },
+ "android/support/recommendation/BuildConfig": {
+ "androidx/recommendation/BuildConfig": [
+ "DEBUG",
+ "APPLICATION_ID",
+ "FLAVOR",
+ "VERSION_NAME",
+ "BUILD_TYPE",
+ "VERSION_CODE"
+ ]
+ },
+ "android/support/v4/app/ActivityOptionsCompat": {
+ "androidx/app/ActivityOptionsCompat": [
+ "EXTRA_USAGE_TIME_REPORT",
+ "EXTRA_USAGE_TIME_REPORT_PACKAGES"
+ ]
+ },
+ "android/support/v4/widget/NestedScrollView": {
+ "androidx/widget/NestedScrollView": [
+ "MAX_SCROLL_FACTOR",
+ "SCROLLVIEW_STYLEABLE",
+ "TAG",
+ "ANIMATED_SCROLL_GAP",
+ "INVALID_POINTER",
+ "ACCESSIBILITY_DELEGATE"
+ ]
+ },
+ "android/support/v4/app/BackStackRecord$Op": {
+ "androidx/app/BackStackRecord$Op": [
+ "enterAnim",
+ "fragment",
+ "popEnterAnim",
+ "exitAnim",
+ "popExitAnim",
+ "cmd"
+ ]
+ },
+ "android/support/v17/leanback/graphics/BoundsRule": {
+ "androidx/leanback/graphics/BoundsRule": [
+ "bottom",
+ "right",
+ "left",
+ "top"
+ ]
+ },
+ "android/support/v17/leanback/app/SearchSupportFragment": {
+ "androidx/leanback/app/SearchSupportFragment": [
+ "SPEECH_RECOGNITION_DELAY_MS",
+ "TAG",
+ "AUDIO_PERMISSION_REQUEST_CODE",
+ "ARG_QUERY",
+ "RESULTS_CHANGED",
+ "ARG_TITLE",
+ "EXTRA_LEANBACK_BADGE_PRESENT",
+ "ARG_PREFIX",
+ "QUERY_COMPLETE",
+ "DEBUG"
+ ]
+ },
+ "android/support/v7/util/SortedList": {
+ "androidx/util/SortedList": [
+ "INSERTION",
+ "DELETION",
+ "MIN_CAPACITY",
+ "INVALID_POSITION",
+ "CAPACITY_GROWTH",
+ "LOOKUP"
+ ]
+ },
+ "android/support/v4/view/ViewCompat": {
+ "androidx/view/ViewCompat": [
+ "IMPL",
+ "SCROLL_AXIS_VERTICAL",
+ "SCROLL_INDICATOR_END",
+ "MEASURED_HEIGHT_STATE_SHIFT",
+ "OVER_SCROLL_ALWAYS",
+ "SCROLL_INDICATOR_RIGHT",
+ "IMPORTANT_FOR_ACCESSIBILITY_AUTO",
+ "SCROLL_INDICATOR_START",
+ "LAYOUT_DIRECTION_LOCALE",
+ "ACCESSIBILITY_LIVE_REGION_ASSERTIVE",
+ "IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS",
+ "SCROLL_INDICATOR_TOP",
+ "MEASURED_STATE_MASK",
+ "SCROLL_INDICATOR_BOTTOM",
+ "LAYOUT_DIRECTION_LTR",
+ "OVER_SCROLL_IF_CONTENT_SCROLLS",
+ "SCROLL_AXIS_NONE",
+ "OVER_SCROLL_NEVER",
+ "ACCESSIBILITY_LIVE_REGION_POLITE",
+ "TYPE_TOUCH",
+ "MEASURED_STATE_TOO_SMALL",
+ "ACCESSIBILITY_LIVE_REGION_NONE",
+ "LAYOUT_DIRECTION_INHERIT",
+ "IMPORTANT_FOR_ACCESSIBILITY_NO",
+ "LAYER_TYPE_NONE",
+ "MEASURED_SIZE_MASK",
+ "SCROLL_INDICATOR_LEFT",
+ "TAG",
+ "SCROLL_AXIS_HORIZONTAL",
+ "TYPE_NON_TOUCH",
+ "LAYER_TYPE_HARDWARE",
+ "LAYER_TYPE_SOFTWARE",
+ "IMPORTANT_FOR_ACCESSIBILITY_YES",
+ "LAYOUT_DIRECTION_RTL"
+ ]
+ },
+ "android/support/v7/media/MediaRouter": {
+ "androidx/media/MediaRouter": [
+ "AVAILABILITY_FLAG_REQUIRE_MATCH",
+ "CALLBACK_FLAG_PERFORM_ACTIVE_SCAN",
+ "CALLBACK_FLAG_FORCE_DISCOVERY",
+ "UNSELECT_REASON_DISCONNECTED",
+ "AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE",
+ "UNSELECT_REASON_ROUTE_CHANGED",
+ "sGlobal",
+ "UNSELECT_REASON_UNKNOWN",
+ "TAG",
+ "CALLBACK_FLAG_REQUEST_DISCOVERY",
+ "DEBUG",
+ "UNSELECT_REASON_STOPPED",
+ "CALLBACK_FLAG_UNFILTERED_EVENTS"
+ ]
+ },
+ "android/support/v17/leanback/graphics/CompositeDrawable$ChildDrawable": {
+ "androidx/leanback/graphics/CompositeDrawable$ChildDrawable": [
+ "adjustedBounds",
+ "BOTTOM_FRACTION",
+ "RIGHT_FRACTION",
+ "BOTTOM_ABSOLUTE",
+ "RIGHT_ABSOLUTE",
+ "LEFT_ABSOLUTE",
+ "LEFT_FRACTION",
+ "TOP_FRACTION",
+ "TOP_ABSOLUTE"
+ ]
+ },
+ "android/support/v17/leanback/widget/PlaybackControlsRow$RepeatAction": {
+ "androidx/leanback/widget/PlaybackControlsRow$RepeatAction": [
+ "INDEX_NONE",
+ "INDEX_ALL",
+ "ALL",
+ "NONE",
+ "ONE",
+ "INDEX_ONE"
+ ]
+ },
+ "android/support/design/R$id": {
+ "androidx/design/R$id": [
+ "touch_outside",
+ "largeLabel",
+ "textinput_error",
+ "textinput_counter",
+ "snackbar_text",
+ "snackbar_action",
+ "icon",
+ "smallLabel",
+ "view_offset_helper",
+ "design_bottom_sheet",
+ "coordinator",
+ "design_menu_item_action_area_stub",
+ "design_menu_item_text"
+ ]
+ },
+ "android/support/v7/widget/ActivityChooserModel$HistoricalRecord": {
+ "androidx/widget/ActivityChooserModel$HistoricalRecord": [
+ "activity",
+ "weight",
+ "time"
+ ]
+ },
+ "android/support/media/tv/TvContractCompat$BaseTvColumns": {
+ "androidx/media/tv/TvContractCompat$BaseTvColumns": [
+ "COLUMN_PACKAGE_NAME"
+ ]
+ },
+ "android/support/v17/leanback/media/MediaPlayerGlue": {
+ "androidx/leanback/media/MediaPlayerGlue": [
+ "FAST_FORWARD_REWIND_STEP",
+ "TAG",
+ "REPEAT_ONE",
+ "FAST_FORWARD_REWIND_REPEAT_DELAY",
+ "NO_REPEAT",
+ "REPEAT_ALL"
+ ]
+ },
+ "android/support/text/emoji/EmojiProcessor$GlyphChecker": {
+ "androidx/text/emoji/EmojiProcessor$GlyphChecker": [
+ "PAINT_TEXT_SIZE",
+ "sStringBuilder"
+ ]
+ },
+ "android/support/v4/app/FragmentManager": {
+ "androidx/app/FragmentManager": [
+ "POP_BACK_STACK_INCLUSIVE"
+ ]
+ },
+ "android/support/v4/content/LocalBroadcastManager$ReceiverRecord": {
+ "androidx/content/LocalBroadcastManager$ReceiverRecord": [
+ "broadcasting",
+ "receiver",
+ "filter",
+ "dead"
+ ]
+ },
+ "android/support/percent/R$styleable": {
+ "androidx/R$styleable": [
+ "PercentLayout_Layout_layout_marginEndPercent",
+ "PercentLayout_Layout",
+ "PercentLayout_Layout_layout_marginBottomPercent",
+ "PercentLayout_Layout_layout_aspectRatio",
+ "PercentLayout_Layout_layout_widthPercent",
+ "PercentLayout_Layout_layout_heightPercent",
+ "PercentLayout_Layout_layout_marginLeftPercent",
+ "PercentLayout_Layout_layout_marginRightPercent",
+ "PercentLayout_Layout_layout_marginStartPercent",
+ "PercentLayout_Layout_layout_marginPercent",
+ "PercentLayout_Layout_layout_marginTopPercent"
+ ]
+ },
+ "android/support/v17/leanback/app/BrowseSupportFragment": {
+ "androidx/leanback/app/BrowseSupportFragment": [
+ "STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW",
+ "STATE_SET_ENTRANCE_START_STATE",
+ "HEADERS_ENABLED",
+ "STATE_ENTRANCE_ON_PREPARED",
+ "HEADERS_HIDDEN",
+ "ARG_HEADERS_STATE",
+ "TAG",
+ "STATE_ENTRANCE_PERFORM",
+ "HEADER_SHOW",
+ "IS_PAGE_ROW",
+ "ARG_TITLE",
+ "LB_HEADERS_BACKSTACK",
+ "DEBUG",
+ "EVT_SCREEN_DATA_READY",
+ "CURRENT_SELECTED_POSITION",
+ "EVT_HEADER_VIEW_CREATED",
+ "EVT_MAIN_FRAGMENT_VIEW_CREATED",
+ "HEADERS_DISABLED",
+ "HEADER_STACK_INDEX"
+ ]
+ },
+ "android/support/v17/leanback/app/SearchFragment": {
+ "androidx/leanback/app/SearchFragment": [
+ "TAG",
+ "QUERY_COMPLETE",
+ "ARG_QUERY",
+ "RESULTS_CHANGED",
+ "ARG_TITLE",
+ "SPEECH_RECOGNITION_DELAY_MS",
+ "EXTRA_LEANBACK_BADGE_PRESENT",
+ "AUDIO_PERMISSION_REQUEST_CODE",
+ "DEBUG",
+ "ARG_PREFIX"
+ ]
+ },
+ "android/support/media/tv/BuildConfig": {
+ "androidx/media/tv/BuildConfig": [
+ "VERSION_NAME",
+ "VERSION_CODE",
+ "BUILD_TYPE",
+ "FLAVOR",
+ "APPLICATION_ID",
+ "DEBUG"
+ ]
+ },
+ "android/support/v4/graphics/drawable/IconCompat": {
+ "androidx/graphics/drawable/IconCompat": [
+ "ADAPTIVE_ICON_INSET_FACTOR",
+ "TYPE_RESOURCE",
+ "TYPE_BITMAP",
+ "ICON_DIAMETER_FACTOR",
+ "KEY_SHADOW_ALPHA",
+ "DEFAULT_VIEW_PORT_SCALE",
+ "AMBIENT_SHADOW_ALPHA",
+ "TYPE_DATA",
+ "BLUR_FACTOR",
+ "TYPE_URI",
+ "KEY_SHADOW_OFFSET_FACTOR",
+ "TYPE_ADAPTIVE_BITMAP"
+ ]
+ },
+ "android/support/v4/internal/view/SupportMenuItem": {
+ "androidx/internal/view/SupportMenuItem": [
+ "SHOW_AS_ACTION_ALWAYS",
+ "SHOW_AS_ACTION_NEVER",
+ "SHOW_AS_ACTION_WITH_TEXT",
+ "SHOW_AS_ACTION_IF_ROOM",
+ "SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW"
+ ]
+ },
+ "android/support/v7/cardview/R$dimen": {
+ "androidx/cardview/R$dimen": [
+ "cardview_compat_inset_shadow"
+ ]
+ },
+ "android/support/v4/widget/CompoundButtonCompat$CompoundButtonCompatBaseImpl": {
+ "androidx/widget/CompoundButtonCompat$CompoundButtonCompatBaseImpl": [
+ "sButtonDrawableField",
+ "sButtonDrawableFieldFetched",
+ "TAG"
+ ]
+ },
+ "android/support/v7/widget/StaggeredGridLayoutManager$LayoutParams": {
+ "androidx/widget/StaggeredGridLayoutManager$LayoutParams": [
+ "width",
+ "leftMargin",
+ "INVALID_SPAN_ID",
+ "bottomMargin",
+ "height",
+ "topMargin",
+ "rightMargin"
+ ]
+ },
+ "android/support/v17/leanback/widget/ItemAlignmentFacetHelper": {
+ "androidx/leanback/widget/ItemAlignmentFacetHelper": [
+ "sRect"
+ ]
+ },
+ "android/support/media/ExifInterface$ExifAttribute": {
+ "androidx/media/ExifInterface$ExifAttribute": [
+ "format",
+ "numberOfComponents",
+ "bytes"
+ ]
+ },
+ "android/support/compat/R$styleable": {
+ "androidx/compat/R$styleable": [
+ "FontFamily_fontProviderCerts",
+ "FontFamily_fontProviderAuthority",
+ "FontFamilyFont_fontWeight",
+ "FontFamilyFont_android_font",
+ "FontFamilyFont_android_fontStyle",
+ "FontFamilyFont_android_fontWeight",
+ "FontFamilyFont_fontStyle",
+ "FontFamilyFont",
+ "FontFamily_fontProviderFetchTimeout",
+ "FontFamily_fontProviderFetchStrategy",
+ "FontFamilyFont_font",
+ "FontFamily_fontProviderQuery",
+ "FontFamily",
+ "FontFamily_fontProviderPackage"
+ ]
+ },
+ "android/support/v7/widget/ButtonBarLayout": {
+ "androidx/widget/ButtonBarLayout": [
+ "PEEK_BUTTON_DP",
+ "ALLOW_STACKING_MIN_HEIGHT_DP"
+ ]
+ },
+ "android/support/v7/app/ActionBarDrawerToggleHoneycomb": {
+ "androidx/app/ActionBarDrawerToggleHoneycomb": [
+ "THEME_ATTRS",
+ "TAG"
+ ]
+ },
+ "android/support/v7/widget/RecyclerView$LayoutParams": {
+ "androidx/widget/RecyclerView$LayoutParams": [
+ "topMargin",
+ "bottomMargin",
+ "width",
+ "height",
+ "rightMargin",
+ "leftMargin"
+ ]
+ },
+ "android/support/v7/util/DiffUtil$Snake": {
+ "androidx/util/DiffUtil$Snake": [
+ "size",
+ "x",
+ "y",
+ "reverse",
+ "removal"
+ ]
+ },
+ "android/support/v4/print/PrintHelper": {
+ "androidx/print/PrintHelper": [
+ "COLOR_MODE_MONOCHROME",
+ "SCALE_MODE_FILL",
+ "ORIENTATION_PORTRAIT",
+ "SCALE_MODE_FIT",
+ "COLOR_MODE_COLOR",
+ "ORIENTATION_LANDSCAPE"
+ ]
+ },
+ "android/support/v4/widget/CompoundButtonCompat": {
+ "androidx/widget/CompoundButtonCompat": [
+ "IMPL"
+ ]
+ },
+ "android/support/v7/widget/DefaultItemAnimator$MoveInfo": {
+ "androidx/widget/DefaultItemAnimator$MoveInfo": [
+ "toY",
+ "toX",
+ "fromY",
+ "fromX",
+ "holder"
+ ]
+ },
+ "android/support/v7/widget/ActionMenuView": {
+ "androidx/widget/ActionMenuView": [
+ "MIN_CELL_SIZE",
+ "TAG",
+ "GENERATED_ITEM_PADDING"
+ ]
+ },
+ "android/support/v7/widget/GapWorker$Task": {
+ "androidx/widget/GapWorker$Task": [
+ "viewVelocity",
+ "position",
+ "view",
+ "immediate",
+ "distanceToItem"
+ ]
+ },
+ "android/support/v7/util/DiffUtil": {
+ "androidx/util/DiffUtil": [
+ "SNAKE_COMPARATOR"
+ ]
+ },
+ "android/support/v4/content/res/ResourcesCompat": {
+ "androidx/content/res/ResourcesCompat": [
+ "TAG"
+ ]
+ },
+ "android/support/v7/widget/ActionMenuView$LayoutParams": {
+ "androidx/widget/ActionMenuView$LayoutParams": [
+ "expandable",
+ "extraPixels",
+ "isOverflowButton",
+ "gravity",
+ "rightMargin",
+ "cellsUsed",
+ "expanded",
+ "leftMargin",
+ "preventEdgeOffset"
+ ]
+ },
+ "android/support/transition/Visibility": {
+ "androidx/transition/Visibility": [
+ "PROPNAME_PARENT",
+ "PROPNAME_VISIBILITY",
+ "MODE_OUT",
+ "PROPNAME_SCREEN_LOCATION",
+ "sTransitionProperties",
+ "MODE_IN"
+ ]
+ },
+ "android/support/v4/view/ViewPager$LayoutParams": {
+ "androidx/view/ViewPager$LayoutParams": [
+ "needsMeasure",
+ "height",
+ "width",
+ "childIndex",
+ "position",
+ "widthFactor",
+ "gravity",
+ "isDecor"
+ ]
+ },
+ "android/support/v17/preference/R$layout": {
+ "androidx/leanback/preference/R$layout": [
+ "leanback_list_preference_item_multi",
+ "leanback_list_preference_fragment",
+ "leanback_settings_fragment",
+ "leanback_list_preference_item_single",
+ "leanback_preferences_list",
+ "leanback_preference_fragment"
+ ]
+ },
+ "android/support/v4/widget/CircularProgressDrawable": {
+ "androidx/widget/CircularProgressDrawable": [
+ "ANIMATION_DURATION",
+ "CENTER_RADIUS",
+ "COLOR_CHANGE_OFFSET",
+ "ARROW_WIDTH",
+ "STROKE_WIDTH",
+ "MAX_PROGRESS_ARC",
+ "GROUP_FULL_ROTATION",
+ "MIN_PROGRESS_ARC",
+ "RING_ROTATION",
+ "DEFAULT",
+ "ARROW_WIDTH_LARGE",
+ "ARROW_HEIGHT_LARGE",
+ "CENTER_RADIUS_LARGE",
+ "COLORS",
+ "STROKE_WIDTH_LARGE",
+ "MATERIAL_INTERPOLATOR",
+ "ARROW_HEIGHT",
+ "SHRINK_OFFSET",
+ "LARGE",
+ "LINEAR_INTERPOLATOR"
+ ]
+ },
+ "android/support/v7/mediarouter/R$integer": {
+ "androidx/mediarouter/R$integer": [
+ "mr_controller_volume_group_list_animation_duration_ms",
+ "mr_controller_volume_group_list_fade_in_duration_ms",
+ "mr_controller_volume_group_list_fade_out_duration_ms"
+ ]
+ },
+ "android/support/v17/leanback/widget/ShadowOverlayContainer": {
+ "androidx/leanback/widget/ShadowOverlayContainer": [
+ "SHADOW_DYNAMIC",
+ "sTempRect",
+ "SHADOW_NONE",
+ "SHADOW_STATIC"
+ ]
+ },
+ "android/support/v4/widget/SwipeRefreshLayout": {
+ "androidx/widget/SwipeRefreshLayout": [
+ "LAYOUT_ATTRS",
+ "CIRCLE_DIAMETER_LARGE",
+ "ALPHA_ANIMATION_DURATION",
+ "MAX_ALPHA",
+ "ANIMATE_TO_START_DURATION",
+ "LOG_TAG",
+ "MAX_PROGRESS_ANGLE",
+ "ANIMATE_TO_TRIGGER_DURATION",
+ "DEFAULT",
+ "SCALE_DOWN_DURATION",
+ "CIRCLE_DIAMETER",
+ "INVALID_POINTER",
+ "DRAG_RATE",
+ "CIRCLE_BG_LIGHT",
+ "DECELERATE_INTERPOLATION_FACTOR",
+ "LARGE",
+ "DEFAULT_CIRCLE_TARGET",
+ "STARTING_PROGRESS_ALPHA"
+ ]
+ },
+ "android/support/annotation/Dimension": {
+ "androidx/annotation/Dimension": [
+ "DP",
+ "SP",
+ "PX"
+ ]
+ },
+ "android/support/v7/widget/AppCompatSpinner": {
+ "androidx/widget/AppCompatSpinner": [
+ "MAX_ITEMS_MEASURED",
+ "MODE_DIALOG",
+ "ATTRS_ANDROID_SPINNERMODE",
+ "TAG",
+ "MODE_THEME",
+ "MODE_DROPDOWN"
+ ]
+ },
+ "android/support/v13/view/inputmethod/InputConnectionCompat$InputContentInfoCompatBaseImpl": {
+ "androidx/view/inputmethod/InputConnectionCompat$InputContentInfoCompatBaseImpl": [
+ "COMMIT_CONTENT_RESULT_RECEIVER",
+ "COMMIT_CONTENT_OPTS_KEY",
+ "COMMIT_CONTENT_FLAGS_KEY",
+ "COMMIT_CONTENT_LINK_URI_KEY",
+ "COMMIT_CONTENT_DESCRIPTION_KEY",
+ "COMMIT_CONTENT_ACTION",
+ "COMMIT_CONTENT_CONTENT_URI_KEY"
+ ]
+ },
+ "android/support/v7/app/TwilightCalculator": {
+ "androidx/app/TwilightCalculator": [
+ "OBLIQUITY",
+ "ALTIDUTE_CORRECTION_CIVIL_TWILIGHT",
+ "UTC_2000",
+ "DEGREES_TO_RADIANS",
+ "NIGHT",
+ "sunrise",
+ "state",
+ "DAY",
+ "J0",
+ "C1",
+ "C2",
+ "C3",
+ "sunset",
+ "sInstance"
+ ]
+ },
+ "android/support/v7/widget/LinearLayoutManager$LayoutState": {
+ "androidx/widget/LinearLayoutManager$LayoutState": [
+ "TAG",
+ "SCROLLING_OFFSET_NaN",
+ "LAYOUT_START",
+ "ITEM_DIRECTION_TAIL",
+ "INVALID_LAYOUT",
+ "LAYOUT_END",
+ "ITEM_DIRECTION_HEAD"
+ ]
+ },
+ "android/support/wear/R$drawable": {
+ "androidx/wear/R$drawable": [
+ "ws_ic_more_horiz_24dp_wht",
+ "ws_ic_more_vert_24dp_wht"
+ ]
+ },
+ "android/support/v17/leanback/widget/ControlBarPresenter$BoundData": {
+ "androidx/leanback/widget/ControlBarPresenter$BoundData": [
+ "adapter",
+ "presenter"
+ ]
+ },
+ "android/support/v4/media/MediaBrowserServiceCompat$ConnectionRecord": {
+ "androidx/media/MediaBrowserServiceCompat$ConnectionRecord": [
+ "callbacks",
+ "pkg",
+ "subscriptions",
+ "rootHints",
+ "root"
+ ]
+ },
+ "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi18": {
+ "androidx/media/session/MediaSessionCompat$MediaSessionImplApi18": [
+ "sIsMbrPendingIntentSupported"
+ ]
+ },
+ "android/support/v4/util/PatternsCompat": {
+ "androidx/util/PatternsCompat": [
+ "TLD_CHAR",
+ "USER_INFO",
+ "WEB_URL",
+ "AUTOLINK_WEB_URL",
+ "LABEL_CHAR",
+ "PATH_AND_QUERY",
+ "PUNYCODE_TLD",
+ "EMAIL_CHAR",
+ "STRICT_DOMAIN_NAME",
+ "STRICT_HOST_NAME",
+ "IP_ADDRESS",
+ "STRICT_TLD",
+ "WEB_URL_WITHOUT_PROTOCOL",
+ "PROTOCOL",
+ "EMAIL_ADDRESS",
+ "EMAIL_ADDRESS_LOCAL_PART",
+ "UCS_CHAR",
+ "TLD",
+ "IRI_LABEL",
+ "WEB_URL_WITH_PROTOCOL",
+ "AUTOLINK_EMAIL_ADDRESS",
+ "PORT_NUMBER",
+ "EMAIL_ADDRESS_DOMAIN",
+ "DOMAIN_NAME",
+ "HOST_NAME",
+ "IANA_TOP_LEVEL_DOMAINS",
+ "RELAXED_DOMAIN_NAME",
+ "WORD_BOUNDARY"
+ ]
+ },
+ "android/support/v17/leanback/widget/PlaybackControlsRow$ClosedCaptioningAction": {
+ "androidx/leanback/widget/PlaybackControlsRow$ClosedCaptioningAction": [
+ "INDEX_OFF",
+ "INDEX_ON",
+ "OFF",
+ "ON"
+ ]
+ },
+ "android/support/v4/widget/ExploreByTouchHelper": {
+ "androidx/widget/ExploreByTouchHelper": [
+ "INVALID_ID",
+ "NODE_ADAPTER",
+ "DEFAULT_CLASS_NAME",
+ "INVALID_PARENT_BOUNDS",
+ "HOST_ID",
+ "SPARSE_VALUES_ADAPTER"
+ ]
+ },
+ "android/support/v7/widget/OrientationHelper": {
+ "androidx/widget/OrientationHelper": [
+ "INVALID_SIZE",
+ "HORIZONTAL",
+ "VERTICAL"
+ ]
+ },
+ "android/support/animation/SpringForce": {
+ "androidx/animation/SpringForce": [
+ "DAMPING_RATIO_NO_BOUNCY",
+ "UNSET",
+ "DAMPING_RATIO_HIGH_BOUNCY",
+ "VELOCITY_THRESHOLD_MULTIPLIER",
+ "STIFFNESS_LOW",
+ "DAMPING_RATIO_LOW_BOUNCY",
+ "STIFFNESS_HIGH",
+ "STIFFNESS_MEDIUM",
+ "DAMPING_RATIO_MEDIUM_BOUNCY",
+ "STIFFNESS_VERY_LOW"
+ ]
+ },
+ "android/support/v7/view/menu/MenuAdapter": {
+ "androidx/view/menu/MenuAdapter": [
+ "ITEM_LAYOUT"
+ ]
+ },
+ "android/support/design/widget/ViewGroupUtils": {
+ "androidx/widget/ViewGroupUtils": [
+ "sMatrix",
+ "sRectF"
+ ]
+ },
+ "android/support/multidex/ZipUtil": {
+ "androidx/multidex/ZipUtil": [
+ "ENDSIG",
+ "ENDHDR",
+ "BUFFER_SIZE"
+ ]
+ },
+ "android/support/v7/media/MediaItemStatus": {
+ "androidx/media/MediaItemStatus": [
+ "KEY_EXTRAS",
+ "PLAYBACK_STATE_PLAYING",
+ "KEY_TIMESTAMP",
+ "KEY_CONTENT_POSITION",
+ "PLAYBACK_STATE_PENDING",
+ "PLAYBACK_STATE_FINISHED",
+ "PLAYBACK_STATE_BUFFERING",
+ "PLAYBACK_STATE_PAUSED",
+ "PLAYBACK_STATE_INVALIDATED",
+ "KEY_CONTENT_DURATION",
+ "PLAYBACK_STATE_ERROR",
+ "PLAYBACK_STATE_CANCELED",
+ "EXTRA_HTTP_RESPONSE_HEADERS",
+ "KEY_PLAYBACK_STATE",
+ "EXTRA_HTTP_STATUS_CODE"
+ ]
+ },
+ "android/support/v7/widget/RecyclerView$Recycler": {
+ "androidx/widget/RecyclerView$Recycler": [
+ "DEFAULT_CACHE_SIZE"
+ ]
+ },
+ "android/support/transition/ViewUtilsApi19": {
+ "androidx/transition/ViewUtilsApi19": [
+ "sSetTransitionAlphaMethod",
+ "sSetTransitionAlphaMethodFetched",
+ "TAG",
+ "sGetTransitionAlphaMethod",
+ "sGetTransitionAlphaMethodFetched"
+ ]
+ },
+ "android/support/v4/media/MediaBrowserCompat": {
+ "androidx/media/MediaBrowserCompat": [
+ "EXTRA_PAGE",
+ "DEBUG",
+ "EXTRA_MEDIA_ID",
+ "EXTRA_PAGE_SIZE",
+ "CUSTOM_ACTION_DOWNLOAD",
+ "CUSTOM_ACTION_REMOVE_DOWNLOADED_FILE",
+ "TAG",
+ "EXTRA_DOWNLOAD_PROGRESS"
+ ]
+ },
+ "android/support/v4/app/FragmentTransition$FragmentContainerTransition": {
+ "androidx/app/FragmentTransition$FragmentContainerTransition": [
+ "lastInTransaction",
+ "lastIn",
+ "lastInIsPop",
+ "firstOut",
+ "firstOutIsPop",
+ "firstOutTransaction"
+ ]
+ },
+ "android/support/v4/text/util/LinkifyCompat": {
+ "androidx/text/util/LinkifyCompat": [
+ "COMPARATOR",
+ "EMPTY_STRING"
+ ]
+ },
+ "android/support/v7/app/TwilightManager$TwilightState": {
+ "androidx/app/TwilightManager$TwilightState": [
+ "todaySunrise",
+ "todaySunset",
+ "yesterdaySunset",
+ "nextUpdate",
+ "tomorrowSunrise",
+ "isNight"
+ ]
+ },
+ "android/support/constraint/BuildConfig": {
+ "androidx/constraint/BuildConfig": [
+ "VERSION_NAME",
+ "DEBUG",
+ "FLAVOR",
+ "VERSION_CODE",
+ "APPLICATION_ID",
+ "BUILD_TYPE"
+ ]
+ },
+ "android/support/v4/content/res/FontResourcesParserCompat": {
+ "androidx/content/res/FontResourcesParserCompat": [
+ "NORMAL_WEIGHT",
+ "FETCH_STRATEGY_ASYNC",
+ "INFINITE_TIMEOUT_VALUE",
+ "DEFAULT_TIMEOUT_MILLIS",
+ "FETCH_STRATEGY_BLOCKING",
+ "ITALIC"
+ ]
+ },
+ "android/support/v7/widget/ListPopupWindow": {
+ "androidx/widget/ListPopupWindow": [
+ "sSetEpicenterBoundsMethod",
+ "WRAP_CONTENT",
+ "MATCH_PARENT",
+ "POSITION_PROMPT_BELOW",
+ "DEBUG",
+ "sGetMaxAvailableHeightMethod",
+ "INPUT_METHOD_FROM_FOCUSABLE",
+ "INPUT_METHOD_NEEDED",
+ "EXPAND_LIST_TIMEOUT",
+ "sClipToWindowEnabledMethod",
+ "POSITION_PROMPT_ABOVE",
+ "TAG",
+ "INPUT_METHOD_NOT_NEEDED"
+ ]
+ },
+ "android/support/v7/media/MediaRouteProviderProtocol": {
+ "androidx/media/MediaRouteProviderProtocol": [
+ "SERVICE_INTERFACE",
+ "CLIENT_MSG_RELEASE_ROUTE_CONTROLLER",
+ "CLIENT_DATA_ROUTE_ID",
+ "CLIENT_VERSION_CURRENT",
+ "CLIENT_VERSION_START",
+ "CLIENT_DATA_ROUTE_LIBRARY_GROUP",
+ "CLIENT_VERSION_1",
+ "CLIENT_VERSION_2",
+ "SERVICE_VERSION_CURRENT",
+ "SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED",
+ "CLIENT_MSG_SELECT_ROUTE",
+ "CLIENT_MSG_UNREGISTER",
+ "CLIENT_MSG_UPDATE_ROUTE_VOLUME",
+ "SERVICE_MSG_REGISTERED",
+ "CLIENT_MSG_CREATE_ROUTE_CONTROLLER",
+ "CLIENT_MSG_ROUTE_CONTROL_REQUEST",
+ "CLIENT_DATA_UNSELECT_REASON",
+ "CLIENT_MSG_SET_DISCOVERY_REQUEST",
+ "SERVICE_MSG_CONTROL_REQUEST_FAILED",
+ "CLIENT_MSG_REGISTER",
+ "CLIENT_MSG_UNSELECT_ROUTE",
+ "SERVICE_MSG_GENERIC_FAILURE",
+ "SERVICE_MSG_GENERIC_SUCCESS",
+ "SERVICE_VERSION_1",
+ "CLIENT_DATA_VOLUME",
+ "SERVICE_DATA_ERROR",
+ "SERVICE_MSG_DESCRIPTOR_CHANGED",
+ "CLIENT_MSG_SET_ROUTE_VOLUME"
+ ]
+ },
+ "android/support/v4/app/Fragment": {
+ "androidx/app/Fragment": [
+ "CREATED",
+ "STARTED",
+ "ACTIVITY_CREATED",
+ "USE_DEFAULT_TRANSITION",
+ "RESUMED",
+ "sClassMap",
+ "INITIALIZING",
+ "STOPPED"
+ ]
+ },
+ "android/support/v7/app/AlertController$ButtonHandler": {
+ "androidx/app/AlertController$ButtonHandler": [
+ "MSG_DISMISS_DIALOG"
+ ]
+ },
+ "android/support/v4/text/BidiFormatter": {
+ "androidx/text/BidiFormatter": [
+ "DIR_LTR",
+ "DIR_UNKNOWN",
+ "DEFAULT_FLAGS",
+ "DEFAULT_LTR_INSTANCE",
+ "PDF",
+ "FLAG_STEREO_RESET",
+ "LRM_STRING",
+ "LRE",
+ "LRM",
+ "DEFAULT_TEXT_DIRECTION_HEURISTIC",
+ "DIR_RTL",
+ "DEFAULT_RTL_INSTANCE",
+ "RLM",
+ "RLE",
+ "EMPTY_STRING",
+ "RLM_STRING"
+ ]
+ },
+ "android/support/v17/leanback/widget/BaseGridView": {
+ "androidx/leanback/widget/BaseGridView": [
+ "WINDOW_ALIGN_NO_EDGE",
+ "SAVE_ALL_CHILD",
+ "WINDOW_ALIGN_BOTH_EDGE",
+ "FOCUS_SCROLL_PAGE",
+ "WINDOW_ALIGN_HIGH_EDGE",
+ "ITEM_ALIGN_OFFSET_PERCENT_DISABLED",
+ "WINDOW_ALIGN_LOW_EDGE",
+ "SAVE_ON_SCREEN_CHILD",
+ "SAVE_NO_CHILD",
+ "FOCUS_SCROLL_ALIGNED",
+ "WINDOW_ALIGN_OFFSET_PERCENT_DISABLED",
+ "FOCUS_SCROLL_ITEM",
+ "SAVE_LIMITED_CHILD"
+ ]
+ },
+ "android/support/v4/app/FragmentActivity": {
+ "androidx/app/FragmentActivity": [
+ "MSG_REALLY_STOPPED",
+ "NEXT_CANDIDATE_REQUEST_INDEX_TAG",
+ "MAX_NUM_PENDING_FRAGMENT_ACTIVITY_RESULTS",
+ "FRAGMENTS_TAG",
+ "TAG",
+ "ALLOCATED_REQUEST_INDICIES_TAG",
+ "MSG_RESUME_PENDING",
+ "REQUEST_FRAGMENT_WHO_TAG"
+ ]
+ },
+ "android/support/v7/gridlayout/R$dimen": {
+ "androidx/gridlayout/R$dimen": [
+ "default_gap"
+ ]
+ },
+ "android/support/content/ContentPager$Stats": {
+ "androidx/content/ContentPager$Stats": [
+ "EXTRA_COMPAT_PAGED",
+ "EXTRA_PROVIDER_PAGED",
+ "EXTRA_RESOLVED_QUERIES",
+ "EXTRA_TOTAL_QUERIES"
+ ]
+ },
+ "android/support/design/widget/BaseTransientBottomBar": {
+ "androidx/design/widget/BaseTransientBottomBar": [
+ "ANIMATION_DURATION",
+ "USE_OFFSET_API",
+ "LENGTH_SHORT",
+ "MSG_SHOW",
+ "MSG_DISMISS",
+ "LENGTH_LONG",
+ "sHandler",
+ "ANIMATION_FADE_DURATION",
+ "LENGTH_INDEFINITE"
+ ]
+ },
+ "android/support/v17/leanback/widget/ArrayObjectAdapter": {
+ "androidx/leanback/widget/ArrayObjectAdapter": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/v4/view/AsyncLayoutInflater$InflateRequest": {
+ "androidx/view/AsyncLayoutInflater$InflateRequest": [
+ "inflater",
+ "callback",
+ "view",
+ "parent",
+ "resid"
+ ]
+ },
+ "android/support/transition/Styleable": {
+ "androidx/transition/Styleable": [
+ "TRANSITION",
+ "VISIBILITY_TRANSITION",
+ "CHANGE_TRANSFORM",
+ "SLIDE",
+ "TRANSITION_MANAGER",
+ "CHANGE_BOUNDS",
+ "TRANSITION_SET",
+ "FADE",
+ "TRANSITION_TARGET",
+ "ARC_MOTION",
+ "PATTERN_PATH_MOTION"
+ ]
+ },
+ "android/support/design/widget/Snackbar$Callback": {
+ "androidx/design/widget/Snackbar$Callback": [
+ "DISMISS_EVENT_ACTION",
+ "DISMISS_EVENT_TIMEOUT",
+ "DISMISS_EVENT_SWIPE",
+ "DISMISS_EVENT_CONSECUTIVE",
+ "DISMISS_EVENT_MANUAL"
+ ]
+ },
+ "android/support/v4/content/ModernAsyncTask$Status": {
+ "androidx/content/ModernAsyncTask$Status": [
+ "PENDING",
+ "FINISHED",
+ "RUNNING"
+ ]
+ },
+ "android/support/wear/widget/drawer/WearableActionDrawerView$ActionListAdapter": {
+ "androidx/wear/widget/drawer/WearableActionDrawerView$ActionListAdapter": [
+ "TYPE_TITLE",
+ "TYPE_ACTION"
+ ]
+ },
+ "android/support/design/widget/AppBarLayout$Behavior": {
+ "androidx/design/widget/AppBarLayout$Behavior": [
+ "INVALID_POSITION",
+ "MAX_OFFSET_ANIMATION_DURATION"
+ ]
+ },
+ "android/support/v17/leanback/app/BaseSupportFragment": {
+ "androidx/leanback/app/BaseSupportFragment": [
+ "STATE_ENTRANCE_INIT",
+ "EVT_PREPARE_ENTRANCE",
+ "EVT_ON_CREATE",
+ "COND_TRANSITION_NOT_SUPPORTED",
+ "STATE_ENTRANCE_PERFORM",
+ "EVT_ENTRANCE_END",
+ "EVT_ON_CREATEVIEW",
+ "STATE_ENTRANCE_ON_PREPARED",
+ "STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW",
+ "EVT_START_ENTRANCE",
+ "STATE_ENTRANCE_ON_ENDED",
+ "STATE_START",
+ "STATE_ENTRANCE_COMPLETE"
+ ]
+ },
+ "android/support/annotation/VisibleForTesting": {
+ "androidx/annotation/VisibleForTesting": [
+ "PROTECTED",
+ "PACKAGE_PRIVATE",
+ "NONE",
+ "PRIVATE"
+ ]
+ },
+ "android/support/v17/leanback/widget/Parallax$IntProperty": {
+ "androidx/leanback/widget/Parallax$IntProperty": [
+ "UNKNOWN_AFTER",
+ "UNKNOWN_BEFORE"
+ ]
+ },
+ "android/support/v7/media/SystemMediaRouteProvider$JellybeanImpl": {
+ "androidx/media/SystemMediaRouteProvider$JellybeanImpl": [
+ "LIVE_AUDIO_CONTROL_FILTERS",
+ "LIVE_VIDEO_CONTROL_FILTERS"
+ ]
+ },
+ "android/support/constraint/ConstraintLayout": {
+ "androidx/constraint/ConstraintLayout": [
+ "VERSION",
+ "ALLOWS_EMBEDDED",
+ "SIMPLE_LAYOUT",
+ "TAG"
+ ]
+ },
+ "android/support/v4/widget/TextViewCompat": {
+ "androidx/widget/TextViewCompat": [
+ "AUTO_SIZE_TEXT_TYPE_UNIFORM",
+ "IMPL",
+ "AUTO_SIZE_TEXT_TYPE_NONE"
+ ]
+ },
+ "android/support/content/ContentPager": {
+ "androidx/content/ContentPager": [
+ "DEBUG",
+ "CURSOR_DISPOSITION",
+ "EXTRA_TOTAL_COUNT",
+ "EXTRA_HONORED_ARGS",
+ "CURSOR_DISPOSITION_REPAGED",
+ "QUERY_ARG_LIMIT",
+ "QUERY_ARG_OFFSET",
+ "EXTRA_SUGGESTED_LIMIT",
+ "EXTRA_REQUESTED_LIMIT",
+ "CURSOR_DISPOSITION_PAGED",
+ "TAG",
+ "CURSOR_DISPOSITION_WRAPPED",
+ "DEFAULT_CURSOR_CACHE_SIZE",
+ "CURSOR_DISPOSITION_COPIED"
+ ]
+ },
+ "android/support/v13/app/FragmentTabHost$SavedState": {
+ "androidx/app/FragmentTabHost$SavedState": [
+ "curTab",
+ "CREATOR"
+ ]
+ },
+ "android/support/design/widget/CollapsingToolbarLayout$LayoutParams": {
+ "androidx/design/widget/CollapsingToolbarLayout$LayoutParams": [
+ "DEFAULT_PARALLAX_MULTIPLIER",
+ "bottomMargin",
+ "COLLAPSE_MODE_PARALLAX",
+ "COLLAPSE_MODE_PIN",
+ "COLLAPSE_MODE_OFF"
+ ]
+ },
+ "android/support/v7/app/WindowDecorActionBar": {
+ "androidx/app/WindowDecorActionBar": [
+ "FADE_OUT_DURATION_MS",
+ "FADE_IN_DURATION_MS",
+ "sShowInterpolator",
+ "INVALID_POSITION",
+ "sHideInterpolator",
+ "TAG"
+ ]
+ },
+ "android/support/v4/view/PointerIconCompat": {
+ "androidx/view/PointerIconCompat": [
+ "TYPE_ZOOM_IN",
+ "TYPE_HELP",
+ "TYPE_WAIT",
+ "TYPE_VERTICAL_TEXT",
+ "TYPE_GRAB",
+ "TYPE_NULL",
+ "TYPE_CELL",
+ "TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW",
+ "TYPE_ARROW",
+ "TYPE_TEXT",
+ "TYPE_HORIZONTAL_DOUBLE_ARROW",
+ "TYPE_HAND",
+ "TYPE_DEFAULT",
+ "TYPE_VERTICAL_DOUBLE_ARROW",
+ "TYPE_NO_DROP",
+ "TYPE_COPY",
+ "TYPE_ALL_SCROLL",
+ "TYPE_GRABBING",
+ "TYPE_ALIAS",
+ "TYPE_CROSSHAIR",
+ "TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW",
+ "TYPE_ZOOM_OUT",
+ "TYPE_CONTEXT_MENU"
+ ]
+ },
+ "android/support/v7/widget/GridLayout$Bounds": {
+ "androidx/widget/GridLayout$Bounds": [
+ "after",
+ "flexibility",
+ "before"
+ ]
+ },
+ "android/support/v4/internal/view/SupportMenu": {
+ "androidx/internal/view/SupportMenu": [
+ "USER_SHIFT",
+ "SUPPORTED_MODIFIERS_MASK",
+ "USER_MASK",
+ "CATEGORY_SHIFT",
+ "FLAG_KEEP_OPEN_ON_SUBMENU_OPENED",
+ "CATEGORY_MASK"
+ ]
+ },
+ "android/support/multidex/ZipUtil$CentralDirectory": {
+ "androidx/multidex/ZipUtil$CentralDirectory": [
+ "offset",
+ "size"
+ ]
+ },
+ "android/support/app/recommendation/ContentRecommendation": {
+ "androidx/app/recommendation/ContentRecommendation": [
+ "CONTENT_TYPE_SERIAL",
+ "CONTENT_TYPE_SPORTS",
+ "CONTENT_TYPE_APP",
+ "CONTENT_MATURITY_LOW",
+ "CONTENT_MATURITY_ALL",
+ "CONTENT_PRICING_PREORDER",
+ "INTENT_TYPE_BROADCAST",
+ "CONTENT_STATUS_AVAILABLE",
+ "CONTENT_PRICING_SUBSCRIPTION",
+ "CONTENT_TYPE_MAGAZINE",
+ "CONTENT_TYPE_VIDEO",
+ "CONTENT_MATURITY_MEDIUM",
+ "CONTENT_PRICING_PURCHASE",
+ "CONTENT_TYPE_RADIO",
+ "CONTENT_TYPE_WEBSITE",
+ "CONTENT_TYPE_MUSIC",
+ "INTENT_TYPE_ACTIVITY",
+ "CONTENT_STATUS_UNAVAILABLE",
+ "CONTENT_PRICING_FREE",
+ "CONTENT_TYPE_TRAILER",
+ "CONTENT_TYPE_GAME",
+ "CONTENT_MATURITY_HIGH",
+ "CONTENT_TYPE_NEWS",
+ "CONTENT_STATUS_READY",
+ "CONTENT_TYPE_MOVIE",
+ "CONTENT_STATUS_PENDING",
+ "INTENT_TYPE_SERVICE",
+ "CONTENT_TYPE_PODCAST",
+ "CONTENT_PRICING_RENTAL",
+ "CONTENT_TYPE_COMIC",
+ "CONTENT_TYPE_BOOK"
+ ]
+ },
+ "android/support/v4/media/app/NotificationCompat$MediaStyle": {
+ "androidx/media/app/NotificationCompat$MediaStyle": [
+ "MAX_MEDIA_BUTTONS",
+ "MAX_MEDIA_BUTTONS_IN_COMPACT"
+ ]
+ },
+ "android/support/v4/media/session/MediaControllerCompat$Callback$MessageHandler": {
+ "androidx/media/session/MediaControllerCompat$Callback$MessageHandler": [
+ "MSG_EVENT",
+ "MSG_UPDATE_QUEUE_TITLE",
+ "MSG_UPDATE_EXTRAS",
+ "MSG_UPDATE_METADATA",
+ "MSG_UPDATE_VOLUME",
+ "MSG_UPDATE_SHUFFLE_MODE",
+ "MSG_DESTROYED",
+ "MSG_SESSION_READY",
+ "MSG_UPDATE_REPEAT_MODE",
+ "MSG_UPDATE_CAPTIONING_ENABLED",
+ "MSG_UPDATE_QUEUE",
+ "MSG_UPDATE_PLAYBACK_STATE"
+ ]
+ },
+ "android/support/v7/widget/LinearLayoutManager": {
+ "androidx/widget/LinearLayoutManager": [
+ "TAG",
+ "MAX_SCROLL_FACTOR",
+ "VERTICAL",
+ "INVALID_OFFSET",
+ "DEBUG",
+ "HORIZONTAL"
+ ]
+ },
+ "android/support/percent/BuildConfig": {
+ "androidx/BuildConfig": [
+ "VERSION_NAME",
+ "BUILD_TYPE",
+ "VERSION_CODE",
+ "APPLICATION_ID",
+ "FLAVOR",
+ "DEBUG"
+ ]
+ },
+ "android/support/graphics/drawable/BuildConfig": {
+ "androidx/graphics/drawable/BuildConfig": [
+ "VERSION_NAME",
+ "DEBUG",
+ "APPLICATION_ID",
+ "BUILD_TYPE",
+ "VERSION_CODE",
+ "FLAVOR"
+ ]
+ },
+ "android/support/v4/view/ViewParentCompat": {
+ "androidx/view/ViewParentCompat": [
+ "IMPL",
+ "TAG"
+ ]
+ },
+ "android/support/v4/widget/DrawerLayout$LayoutParams": {
+ "androidx/widget/DrawerLayout$LayoutParams": [
+ "gravity",
+ "width",
+ "FLAG_IS_OPENED",
+ "openState",
+ "onScreen",
+ "isPeeking",
+ "leftMargin",
+ "bottomMargin",
+ "FLAG_IS_OPENING",
+ "topMargin",
+ "FLAG_IS_CLOSING",
+ "height",
+ "rightMargin"
+ ]
+ },
+ "android/support/v4/graphics/drawable/DrawableWrapperApi14": {
+ "androidx/graphics/drawable/DrawableWrapperApi14": [
+ "DEFAULT_TINT_MODE"
+ ]
+ },
+ "android/support/v7/widget/GridLayoutManager$LayoutParams": {
+ "androidx/widget/GridLayoutManager$LayoutParams": [
+ "bottomMargin",
+ "rightMargin",
+ "height",
+ "topMargin",
+ "width",
+ "INVALID_SPAN_ID",
+ "leftMargin"
+ ]
+ },
+ "android/support/v4/app/NotificationManagerCompat$SideChannelManager$ListenerRecord": {
+ "androidx/app/NotificationManagerCompat$SideChannelManager$ListenerRecord": [
+ "taskQueue",
+ "service",
+ "componentName",
+ "retryCount",
+ "bound"
+ ]
+ },
+ "android/support/v17/leanback/widget/picker/DatePicker": {
+ "androidx/leanback/widget/picker/DatePicker": [
+ "DATE_FORMAT",
+ "LOG_TAG",
+ "DATE_FIELDS"
+ ]
+ },
+ "android/support/v7/widget/DrawableUtils": {
+ "androidx/widget/DrawableUtils": [
+ "INSETS_NONE",
+ "VECTOR_DRAWABLE_CLAZZ_NAME",
+ "TAG",
+ "sInsetsClazz"
+ ]
+ },
+ "android/support/v4/media/session/MediaControllerCompat$PlaybackInfo": {
+ "androidx/media/session/MediaControllerCompat$PlaybackInfo": [
+ "PLAYBACK_TYPE_LOCAL",
+ "PLAYBACK_TYPE_REMOTE"
+ ]
+ },
+ "android/support/v17/leanback/widget/SearchOrbView$Colors": {
+ "androidx/leanback/widget/SearchOrbView$Colors": [
+ "sBrightnessAlpha",
+ "brightColor",
+ "iconColor",
+ "color"
+ ]
+ },
+ "android/support/v7/widget/LayoutState": {
+ "androidx/widget/LayoutState": [
+ "TAG",
+ "LAYOUT_END",
+ "INVALID_LAYOUT",
+ "ITEM_DIRECTION_HEAD",
+ "ITEM_DIRECTION_TAIL",
+ "LAYOUT_START"
+ ]
+ },
+ "android/support/v17/leanback/app/BaseFragment": {
+ "androidx/leanback/app/BaseFragment": [
+ "STATE_ENTRANCE_COMPLETE",
+ "EVT_ON_CREATEVIEW",
+ "COND_TRANSITION_NOT_SUPPORTED",
+ "STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW",
+ "STATE_ENTRANCE_ON_ENDED",
+ "EVT_START_ENTRANCE",
+ "EVT_PREPARE_ENTRANCE",
+ "STATE_ENTRANCE_INIT",
+ "STATE_START",
+ "STATE_ENTRANCE_ON_PREPARED",
+ "EVT_ENTRANCE_END",
+ "STATE_ENTRANCE_PERFORM",
+ "EVT_ON_CREATE"
+ ]
+ },
+ "android/support/v7/widget/ActivityChooserView": {
+ "androidx/widget/ActivityChooserView": [
+ "LOG_TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/picker/PickerUtility$TimeConstant": {
+ "androidx/leanback/widget/picker/PickerUtility$TimeConstant": [
+ "ampm",
+ "minutes",
+ "locale",
+ "hours12",
+ "hours24"
+ ]
+ },
+ "android/support/design/widget/DrawableUtils": {
+ "androidx/design/widget/DrawableUtils": [
+ "LOG_TAG",
+ "sSetConstantStateMethod",
+ "sSetConstantStateMethodFetched"
+ ]
+ },
+ "android/support/v7/util/AsyncListUtil": {
+ "androidx/util/AsyncListUtil": [
+ "TAG",
+ "DEBUG"
+ ]
+ },
+ "android/support/v7/widget/ActivityChooserView$ActivityChooserViewAdapter": {
+ "androidx/widget/ActivityChooserView$ActivityChooserViewAdapter": [
+ "ITEM_VIEW_TYPE_COUNT",
+ "MAX_ACTIVITY_COUNT_DEFAULT",
+ "ITEM_VIEW_TYPE_ACTIVITY",
+ "ITEM_VIEW_TYPE_FOOTER",
+ "MAX_ACTIVITY_COUNT_UNLIMITED"
+ ]
+ },
+ "android/support/v17/leanback/widget/ControlBarPresenter": {
+ "androidx/leanback/widget/ControlBarPresenter": [
+ "sChildMarginDefault",
+ "MAX_CONTROLS",
+ "sControlIconWidth"
+ ]
+ },
+ "android/support/v4/app/FragmentTransaction": {
+ "androidx/app/FragmentTransaction": [
+ "TRANSIT_FRAGMENT_CLOSE",
+ "TRANSIT_EXIT_MASK",
+ "TRANSIT_FRAGMENT_OPEN",
+ "TRANSIT_UNSET",
+ "TRANSIT_FRAGMENT_FADE",
+ "TRANSIT_NONE",
+ "TRANSIT_ENTER_MASK"
+ ]
+ },
+ "android/support/design/widget/BottomSheetBehavior": {
+ "androidx/design/widget/BottomSheetBehavior": [
+ "STATE_COLLAPSED",
+ "HIDE_THRESHOLD",
+ "STATE_SETTLING",
+ "STATE_HIDDEN",
+ "STATE_DRAGGING",
+ "HIDE_FRICTION",
+ "STATE_EXPANDED",
+ "PEEK_HEIGHT_AUTO"
+ ]
+ },
+ "android/support/v17/leanback/app/VerticalGridSupportFragment": {
+ "androidx/leanback/app/VerticalGridSupportFragment": [
+ "DEBUG",
+ "STATE_ENTRANCE_ON_PREPARED",
+ "EVT_ON_CREATEVIEW",
+ "STATE_SET_ENTRANCE_START_STATE",
+ "TAG"
+ ]
+ },
+ "android/support/v7/media/MediaItemMetadata": {
+ "androidx/media/MediaItemMetadata": [
+ "KEY_ALBUM_TITLE",
+ "KEY_DURATION",
+ "KEY_YEAR",
+ "KEY_TRACK_NUMBER",
+ "KEY_AUTHOR",
+ "KEY_DISC_NUMBER",
+ "KEY_ALBUM_ARTIST",
+ "KEY_COMPOSER",
+ "KEY_ARTIST",
+ "KEY_ARTWORK_URI",
+ "KEY_TITLE"
+ ]
+ },
+ "android/support/v7/appcompat/R$bool": {
+ "androidx/appcompat/R$bool": [
+ "abc_config_showMenuShortcutsWhenKeyboardPresent",
+ "abc_action_bar_embed_tabs"
+ ]
+ },
+ "android/support/transition/ViewUtilsApi21": {
+ "androidx/transition/ViewUtilsApi21": [
+ "sTransformMatrixToGlobalMethodFetched",
+ "sTransformMatrixToLocalMethodFetched",
+ "TAG",
+ "sSetAnimationMatrixMethod",
+ "sTransformMatrixToGlobalMethod",
+ "sTransformMatrixToLocalMethod",
+ "sSetAnimationMatrixMethodFetched"
+ ]
+ },
+ "android/support/v4/util/Pair": {
+ "androidx/util/Pair": [
+ "first",
+ "second"
+ ]
+ },
+ "android/support/v7/preference/SeekBarPreference$SavedState": {
+ "androidx/preference/SeekBarPreference$SavedState": [
+ "min",
+ "max",
+ "CREATOR",
+ "seekBarValue"
+ ]
+ },
+ "android/support/v7/mediarouter/R$attr": {
+ "androidx/mediarouter/R$attr": [
+ "mediaRouteTheme",
+ "mediaRouteTvIconDrawable",
+ "mediaRouteButtonStyle",
+ "mediaRouteStopDrawable",
+ "mediaRoutePauseDrawable",
+ "mediaRouteSpeakerGroupIconDrawable",
+ "mediaRouteSpeakerIconDrawable",
+ "mediaRouteDefaultIconDrawable",
+ "mediaRoutePlayDrawable"
+ ]
+ },
+ "android/support/v7/view/SupportMenuInflater": {
+ "androidx/view/SupportMenuInflater": [
+ "XML_ITEM",
+ "XML_GROUP",
+ "LOG_TAG",
+ "ACTION_VIEW_CONSTRUCTOR_SIGNATURE",
+ "XML_MENU",
+ "ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE",
+ "NO_ID"
+ ]
+ },
+ "android/support/v4/view/AsyncLayoutInflater$InflateThread": {
+ "androidx/view/AsyncLayoutInflater$InflateThread": [
+ "sInstance"
+ ]
+ },
+ "android/support/design/widget/CollapsingTextHelper": {
+ "androidx/design/widget/CollapsingTextHelper": [
+ "DEBUG_DRAW",
+ "USE_SCALING_TEXTURE",
+ "DEBUG_DRAW_PAINT"
+ ]
+ },
+ "android/support/v4/app/FragmentTabHost$TabInfo": {
+ "androidx/app/FragmentTabHost$TabInfo": [
+ "tag",
+ "fragment",
+ "args",
+ "clss"
+ ]
+ },
+ "android/support/v17/leanback/app/VideoFragment": {
+ "androidx/leanback/app/VideoFragment": [
+ "SURFACE_NOT_CREATED",
+ "SURFACE_CREATED"
+ ]
+ },
+ "android/support/text/emoji/bundled/BundledEmojiCompatConfig$InitRunnable": {
+ "androidx/text/emoji/bundled/BundledEmojiCompatConfig$InitRunnable": [
+ "FONT_NAME"
+ ]
+ },
+ "android/support/mediacompat/R$layout": {
+ "androidx/mediacompat/R$layout": [
+ "notification_template_big_media_custom",
+ "notification_template_media",
+ "notification_media_action",
+ "notification_template_big_media_narrow_custom",
+ "notification_template_media_custom",
+ "notification_template_big_media",
+ "notification_template_big_media_narrow"
+ ]
+ },
+ "android/support/v4/app/NotificationCompat$MessagingStyle$Message": {
+ "androidx/app/NotificationCompat$MessagingStyle$Message": [
+ "KEY_DATA_URI",
+ "KEY_EXTRAS_BUNDLE",
+ "KEY_DATA_MIME_TYPE",
+ "KEY_TIMESTAMP",
+ "KEY_SENDER",
+ "KEY_TEXT"
+ ]
+ },
+ "android/support/v4/media/session/MediaControllerCompat": {
+ "androidx/media/session/MediaControllerCompat": [
+ "COMMAND_GET_EXTRA_BINDER",
+ "COMMAND_REMOVE_QUEUE_ITEM_AT",
+ "COMMAND_ARGUMENT_INDEX",
+ "COMMAND_ARGUMENT_MEDIA_DESCRIPTION",
+ "COMMAND_ADD_QUEUE_ITEM_AT",
+ "COMMAND_ADD_QUEUE_ITEM",
+ "COMMAND_REMOVE_QUEUE_ITEM",
+ "TAG"
+ ]
+ },
+ "android/support/v4/text/TextDirectionHeuristicsCompat$AnyStrong": {
+ "androidx/text/TextDirectionHeuristicsCompat$AnyStrong": [
+ "INSTANCE_RTL",
+ "INSTANCE_LTR"
+ ]
+ },
+ "android/support/wear/widget/ProgressDrawable": {
+ "androidx/wear/widget/ProgressDrawable": [
+ "FULL_CIRCLE",
+ "LEVEL",
+ "CORRECTION_ANGLE",
+ "GROW_SHRINK_RATIO",
+ "MAX_LEVEL",
+ "sInterpolator",
+ "NUMBER_OF_SEGMENTS",
+ "STARTING_ANGLE",
+ "MAX_SWEEP",
+ "ANIMATION_DURATION",
+ "LEVELS_PER_SEGMENT"
+ ]
+ },
+ "android/support/v7/app/MediaRouteControllerDialog$FetchArtTask": {
+ "androidx/app/MediaRouteControllerDialog$FetchArtTask": [
+ "SHOW_ANIM_TIME_THRESHOLD_MILLIS"
+ ]
+ },
+ "android/support/v17/leanback/transition/SlideKitkat": {
+ "androidx/leanback/transition/SlideKitkat": [
+ "sCalculateRight",
+ "sCalculateStart",
+ "sAccelerate",
+ "sDecelerate",
+ "sCalculateTop",
+ "sCalculateEnd",
+ "sCalculateLeft",
+ "sCalculateBottom",
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/ImageCardView": {
+ "androidx/leanback/widget/ImageCardView": [
+ "CARD_TYPE_FLAG_CONTENT",
+ "ALPHA",
+ "CARD_TYPE_FLAG_ICON_RIGHT",
+ "CARD_TYPE_FLAG_TITLE",
+ "CARD_TYPE_FLAG_IMAGE_ONLY",
+ "CARD_TYPE_FLAG_ICON_LEFT"
+ ]
+ },
+ "android/support/v17/leanback/app/VideoSupportFragment": {
+ "androidx/leanback/app/VideoSupportFragment": [
+ "SURFACE_NOT_CREATED",
+ "SURFACE_CREATED"
+ ]
+ },
+ "android/support/v17/leanback/widget/PlaybackControlsRow$PlayPauseAction": {
+ "androidx/leanback/widget/PlaybackControlsRow$PlayPauseAction": [
+ "INDEX_PAUSE",
+ "PLAY",
+ "INDEX_PLAY",
+ "PAUSE"
+ ]
+ },
+ "android/support/v7/widget/SearchView$AutoCompleteTextViewReflector": {
+ "androidx/widget/SearchView$AutoCompleteTextViewReflector": [
+ "showSoftInputUnchecked",
+ "doAfterTextChanged",
+ "ensureImeVisible",
+ "doBeforeTextChanged"
+ ]
+ },
+ "android/support/text/emoji/R$styleable": {
+ "androidx/text/emoji/R$styleable": [
+ "EmojiExtractTextLayout",
+ "EmojiEditText_maxEmojiCount",
+ "EmojiExtractTextLayout_emojiReplaceStrategy",
+ "EmojiEditText"
+ ]
+ },
+ "android/support/v4/view/animation/PathInterpolatorApi14": {
+ "androidx/view/animation/PathInterpolatorApi14": [
+ "PRECISION"
+ ]
+ },
+ "android/support/v4/app/FragmentTransition": {
+ "androidx/app/FragmentTransition": [
+ "PLATFORM_IMPL",
+ "INVERSE_OPS",
+ "SUPPORT_IMPL"
+ ]
+ },
+ "android/support/v7/widget/GridLayout$Spec": {
+ "androidx/widget/GridLayout$Spec": [
+ "weight",
+ "alignment",
+ "UNDEFINED",
+ "startDefined",
+ "span",
+ "DEFAULT_WEIGHT"
+ ]
+ },
+ "android/support/v4/BuildConfig": {
+ "androidx/BuildConfig": [
+ "BUILD_TYPE",
+ "DEBUG",
+ "APPLICATION_ID",
+ "FLAVOR",
+ "VERSION_CODE",
+ "VERSION_NAME"
+ ]
+ },
+ "android/support/v4/app/INotificationSideChannel$Stub": {
+ "androidx/app/INotificationSideChannel$Stub": [
+ "TRANSACTION_notify",
+ "TRANSACTION_cancel",
+ "TRANSACTION_cancelAll",
+ "DESCRIPTOR"
+ ]
+ },
+ "android/support/v4/app/FragmentManagerImpl": {
+ "androidx/app/FragmentManagerImpl": [
+ "sAnimationListenerField",
+ "TAG",
+ "ANIM_DUR",
+ "ANIM_STYLE_FADE_EXIT",
+ "DEBUG",
+ "ACCELERATE_QUINT",
+ "TARGET_REQUEST_CODE_STATE_TAG",
+ "ANIM_STYLE_OPEN_EXIT",
+ "ANIM_STYLE_OPEN_ENTER",
+ "TARGET_STATE_TAG",
+ "USER_VISIBLE_HINT_TAG",
+ "ANIM_STYLE_FADE_ENTER",
+ "VIEW_STATE_TAG",
+ "DECELERATE_QUINT",
+ "DECELERATE_CUBIC",
+ "ANIM_STYLE_CLOSE_ENTER",
+ "ACCELERATE_CUBIC",
+ "ANIM_STYLE_CLOSE_EXIT"
+ ]
+ },
+ "android/support/v7/app/MediaRouteButton": {
+ "androidx/app/MediaRouteButton": [
+ "TAG",
+ "sRemoteIndicatorCache",
+ "CHECKED_STATE_SET",
+ "CHECKABLE_STATE_SET",
+ "CONTROLLER_FRAGMENT_TAG",
+ "CHOOSER_FRAGMENT_TAG"
+ ]
+ },
+ "android/support/v7/widget/VectorEnabledTintResources": {
+ "androidx/widget/VectorEnabledTintResources": [
+ "MAX_SDK_WHERE_REQUIRED"
+ ]
+ },
+ "android/support/v7/view/menu/MenuItemImpl": {
+ "androidx/view/menu/MenuItemImpl": [
+ "NO_ICON",
+ "HIDDEN",
+ "sEnterShortcutLabel",
+ "CHECKABLE",
+ "SHOW_AS_ACTION_MASK",
+ "sSpaceShortcutLabel",
+ "EXCLUSIVE",
+ "CHECKED",
+ "TAG",
+ "sDeleteShortcutLabel",
+ "IS_ACTION",
+ "ENABLED",
+ "sPrependShortcutLabel"
+ ]
+ },
+ "android/support/content/InMemoryCursor": {
+ "androidx/content/InMemoryCursor": [
+ "NUM_TYPES"
+ ]
+ },
+ "android/support/v4/app/FragmentPagerAdapter": {
+ "androidx/app/FragmentPagerAdapter": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/v4/text/ICUCompat": {
+ "androidx/text/ICUCompat": [
+ "TAG",
+ "sAddLikelySubtagsMethod",
+ "sGetScriptMethod"
+ ]
+ },
+ "android/support/v4/media/session/MediaControllerCompatApi21$PlaybackInfo": {
+ "androidx/media/session/MediaControllerCompatApi21$PlaybackInfo": [
+ "FLAG_SCO",
+ "STREAM_BLUETOOTH_SCO",
+ "STREAM_SYSTEM_ENFORCED"
+ ]
+ },
+ "android/support/text/emoji/R$id": {
+ "androidx/text/emoji/R$id": [
+ "inputExtractAccessories",
+ "inputExtractAction"
+ ]
+ },
+ "android/support/v17/leanback/R$animator": {
+ "androidx/leanback/R$animator": [
+ "lb_onboarding_page_indicator_fade_in",
+ "lb_onboarding_page_indicator_fade_out",
+ "lb_onboarding_start_button_fade_in",
+ "lb_playback_controls_fade_in",
+ "lb_playback_controls_fade_out",
+ "lb_onboarding_logo_enter",
+ "lb_onboarding_start_button_fade_out",
+ "lb_onboarding_page_indicator_enter",
+ "lb_playback_bg_fade_out",
+ "lb_onboarding_title_enter",
+ "lb_onboarding_description_enter",
+ "lb_playback_bg_fade_in",
+ "lb_onboarding_logo_exit"
+ ]
+ },
+ "android/support/transition/TransitionInflater": {
+ "androidx/transition/TransitionInflater": [
+ "CONSTRUCTOR_SIGNATURE",
+ "CONSTRUCTORS"
+ ]
+ },
+ "android/support/v4/media/RatingCompat": {
+ "androidx/media/RatingCompat": [
+ "RATING_THUMB_UP_DOWN",
+ "RATING_5_STARS",
+ "RATING_HEART",
+ "RATING_PERCENTAGE",
+ "CREATOR",
+ "RATING_4_STARS",
+ "RATING_NONE",
+ "RATING_NOT_RATED",
+ "TAG",
+ "RATING_3_STARS"
+ ]
+ },
+ "android/support/v17/leanback/transition/FadeAndShortSlide": {
+ "androidx/leanback/transition/FadeAndShortSlide": [
+ "sCalculateTopBottom",
+ "sCalculateStartEnd",
+ "sCalculateEnd",
+ "sCalculateBottom",
+ "PROPNAME_SCREEN_POSITION",
+ "sDecelerate",
+ "sCalculateStart",
+ "sCalculateTop"
+ ]
+ },
+ "android/support/design/R$attr": {
+ "androidx/design/R$attr": [
+ "state_collapsible",
+ "state_collapsed",
+ "bottomSheetDialogTheme"
+ ]
+ },
+ "android/support/graphics/drawable/PathInterpolatorCompat": {
+ "androidx/graphics/drawable/PathInterpolatorCompat": [
+ "EPSILON",
+ "PRECISION",
+ "MAX_NUM_POINTS"
+ ]
+ },
+ "android/support/animation/SpringAnimation": {
+ "androidx/animation/SpringAnimation": [
+ "UNSET"
+ ]
+ },
+ "android/support/v7/app/AppCompatDelegateImplV9$PanelFeatureState$SavedState": {
+ "androidx/app/AppCompatDelegateImplV9$PanelFeatureState$SavedState": [
+ "featureId",
+ "menuState",
+ "CREATOR",
+ "isOpen"
+ ]
+ },
+ "android/support/v7/view/menu/MenuBuilder": {
+ "androidx/view/menu/MenuBuilder": [
+ "EXPANDED_ACTION_VIEW_ID",
+ "TAG",
+ "PRESENTER_KEY",
+ "ACTION_VIEW_STATES_KEY",
+ "sCategoryToOrder"
+ ]
+ },
+ "android/support/v4/view/ViewGroupCompat": {
+ "androidx/view/ViewGroupCompat": [
+ "LAYOUT_MODE_OPTICAL_BOUNDS",
+ "LAYOUT_MODE_CLIP_BOUNDS",
+ "IMPL"
+ ]
+ },
+ "android/support/v14/preference/MultiSelectListPreferenceDialogFragment": {
+ "androidx/preference/MultiSelectListPreferenceDialogFragment": [
+ "SAVE_STATE_ENTRY_VALUES",
+ "SAVE_STATE_VALUES",
+ "SAVE_STATE_ENTRIES",
+ "SAVE_STATE_CHANGED"
+ ]
+ },
+ "android/support/exifinterface/BuildConfig": {
+ "androidx/exifinterface/BuildConfig": [
+ "VERSION_NAME",
+ "DEBUG",
+ "APPLICATION_ID",
+ "BUILD_TYPE",
+ "VERSION_CODE",
+ "FLAVOR"
+ ]
+ },
+ "android/support/v4/print/PrintHelper$PrintHelperApi19": {
+ "androidx/print/PrintHelper$PrintHelperApi19": [
+ "MAX_PRINT_SIZE",
+ "LOG_TAG"
+ ]
+ },
+ "android/support/v7/preference/R$layout": {
+ "androidx/preference/R$layout": [
+ "preference_list_fragment",
+ "preference_recyclerview",
+ "preference"
+ ]
+ },
+ "android/support/v7/widget/AdapterHelper$UpdateOp": {
+ "androidx/widget/AdapterHelper$UpdateOp": [
+ "positionStart",
+ "payload",
+ "MOVE",
+ "REMOVE",
+ "ADD",
+ "UPDATE",
+ "cmd",
+ "POOL_SIZE",
+ "itemCount"
+ ]
+ },
+ "android/support/v17/leanback/app/BrowseFragment$SetSelectionRunnable": {
+ "androidx/leanback/app/BrowseFragment$SetSelectionRunnable": [
+ "TYPE_INTERNAL_SYNC",
+ "TYPE_USER_REQUEST",
+ "TYPE_INVALID"
+ ]
+ },
+ "android/support/v17/leanback/app/BrowseSupportFragment$ExpandPreLayout": {
+ "androidx/leanback/app/BrowseSupportFragment$ExpandPreLayout": [
+ "STATE_SECOND_DRAW",
+ "STATE_INIT",
+ "STATE_FIRST_DRAW",
+ "mainFragmentAdapter"
+ ]
+ },
+ "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatBaseImpl": {
+ "androidx/widget/PopupWindowCompat$PopupWindowCompatBaseImpl": [
+ "sGetWindowLayoutTypeMethodAttempted",
+ "sGetWindowLayoutTypeMethod",
+ "sSetWindowLayoutTypeMethod",
+ "sSetWindowLayoutTypeMethodAttempted"
+ ]
+ },
+ "android/support/v7/widget/SwitchCompat": {
+ "androidx/widget/SwitchCompat": [
+ "MONOSPACE",
+ "CHECKED_STATE_SET",
+ "TOUCH_MODE_DRAGGING",
+ "TOUCH_MODE_DOWN",
+ "THUMB_POS",
+ "TOUCH_MODE_IDLE",
+ "SERIF",
+ "THUMB_ANIMATION_DURATION",
+ "ACCESSIBILITY_EVENT_CLASS_NAME",
+ "SANS"
+ ]
+ },
+ "android/support/v7/widget/RecyclerView$LayoutManager$Properties": {
+ "androidx/widget/RecyclerView$LayoutManager$Properties": [
+ "reverseLayout",
+ "stackFromEnd",
+ "spanCount",
+ "orientation"
+ ]
+ },
+ "android/support/v4/app/NotificationManagerCompat$SideChannelManager": {
+ "androidx/app/NotificationManagerCompat$SideChannelManager": [
+ "MSG_QUEUE_TASK",
+ "MSG_RETRY_LISTENER_QUEUE",
+ "MSG_SERVICE_CONNECTED",
+ "MSG_SERVICE_DISCONNECTED"
+ ]
+ },
+ "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentAdapterRegistry": {
+ "androidx/leanback/app/BrowseSupportFragment$MainFragmentAdapterRegistry": [
+ "sDefaultFragmentFactory"
+ ]
+ },
+ "android/support/v7/preference/PreferenceFragmentCompat": {
+ "androidx/preference/PreferenceFragmentCompat": [
+ "MSG_BIND_PREFERENCES",
+ "PREFERENCES_TAG",
+ "ARG_PREFERENCE_ROOT",
+ "DIALOG_FRAGMENT_TAG"
+ ]
+ },
+ "android/support/v7/widget/SearchView": {
+ "androidx/widget/SearchView": [
+ "ENABLED_STATE_SET",
+ "EMPTY_STATE_SET",
+ "FOCUSED_STATE_SET",
+ "DBG",
+ "IME_OPTION_NO_MICROPHONE",
+ "LOG_TAG",
+ "HIDDEN_METHOD_INVOKER"
+ ]
+ },
+ "android/support/v4/view/AsyncLayoutInflater$BasicInflater": {
+ "androidx/view/AsyncLayoutInflater$BasicInflater": [
+ "sClassPrefixList"
+ ]
+ },
+ "android/support/v7/widget/DividerItemDecoration": {
+ "androidx/widget/DividerItemDecoration": [
+ "VERTICAL",
+ "HORIZONTAL",
+ "ATTRS",
+ "TAG"
+ ]
+ },
+ "android/support/wear/widget/SwipeDismissFrameLayout": {
+ "androidx/wear/widget/SwipeDismissFrameLayout": [
+ "DEFAULT_INTERPOLATION_FACTOR",
+ "TRANSLATION_MIN_ALPHA",
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/app/HeadersFragment": {
+ "androidx/leanback/app/HeadersFragment": [
+ "sHeaderPresenter",
+ "sLayoutChangeListener"
+ ]
+ },
+ "android/support/customtabs/CustomTabsService": {
+ "androidx/browser/customtabs/CustomTabsService": [
+ "RESULT_FAILURE_MESSAGING_ERROR",
+ "RESULT_SUCCESS",
+ "RESULT_FAILURE_REMOTE_ERROR",
+ "ACTION_CUSTOM_TABS_CONNECTION",
+ "KEY_URL",
+ "RESULT_FAILURE_DISALLOWED",
+ "RELATION_HANDLE_ALL_URLS",
+ "RELATION_USE_AS_ORIGIN"
+ ]
+ },
+ "android/support/v17/leanback/app/GuidedStepFragment": {
+ "androidx/leanback/app/GuidedStepFragment": [
+ "IS_FRAMEWORK_FRAGMENT",
+ "entranceTransitionType",
+ "ENTRY_NAME_ENTRANCE",
+ "TAG_LEAN_BACK_ACTIONS_FRAGMENT",
+ "UI_STYLE_REPLACE",
+ "EXTRA_BUTTON_ACTION_PREFIX",
+ "UI_STYLE_DEFAULT",
+ "DEBUG",
+ "SLIDE_FROM_BOTTOM",
+ "UI_STYLE_ENTRANCE",
+ "SLIDE_FROM_SIDE",
+ "TAG",
+ "EXTRA_UI_STYLE",
+ "EXTRA_ACTION_PREFIX",
+ "ENTRY_NAME_REPLACE",
+ "UI_STYLE_ACTIVITY_ROOT"
+ ]
+ },
+ "android/support/v17/leanback/util/StateMachine": {
+ "androidx/leanback/util/StateMachine": [
+ "STATUS_ZERO",
+ "STATUS_INVOKED",
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/compat/R$drawable": {
+ "androidx/compat/R$drawable": [
+ "notification_template_icon_bg",
+ "notification_bg",
+ "notification_icon_background",
+ "notification_template_icon_low_bg",
+ "notification_bg_low"
+ ]
+ },
+ "android/support/v4/provider/DocumentsContractApi19": {
+ "androidx/provider/DocumentsContractApi19": [
+ "TAG",
+ "FLAG_VIRTUAL_DOCUMENT"
+ ]
+ },
+ "android/support/v4/app/JobIntentService": {
+ "androidx/app/JobIntentService": [
+ "TAG",
+ "sClassWorkEnqueuer",
+ "DEBUG",
+ "sLock"
+ ]
+ },
+ "android/support/v4/graphics/TypefaceCompatUtil": {
+ "androidx/graphics/TypefaceCompatUtil": [
+ "CACHE_FILE_PREFIX",
+ "TAG"
+ ]
+ },
+ "android/support/transition/Explode": {
+ "androidx/transition/Explode": [
+ "PROPNAME_SCREEN_BOUNDS",
+ "sDecelerate",
+ "sAccelerate"
+ ]
+ },
+ "android/support/v4/view/AccessibilityDelegateCompat": {
+ "androidx/view/AccessibilityDelegateCompat": [
+ "DEFAULT_DELEGATE",
+ "IMPL"
+ ]
+ },
+ "android/support/v4/view/MenuItemCompat": {
+ "androidx/view/MenuItemCompat": [
+ "IMPL",
+ "SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW",
+ "SHOW_AS_ACTION_WITH_TEXT",
+ "SHOW_AS_ACTION_NEVER",
+ "SHOW_AS_ACTION_ALWAYS",
+ "SHOW_AS_ACTION_IF_ROOM",
+ "TAG"
+ ]
+ },
+ "android/support/v4/widget/CircleImageView": {
+ "androidx/widget/CircleImageView": [
+ "SHADOW_RADIUS",
+ "Y_OFFSET",
+ "X_OFFSET",
+ "KEY_SHADOW_COLOR",
+ "SHADOW_ELEVATION",
+ "FILL_SHADOW_COLOR"
+ ]
+ },
+ "android/support/v7/widget/SuggestionsAdapter": {
+ "androidx/widget/SuggestionsAdapter": [
+ "REFINE_NONE",
+ "LOG_TAG",
+ "REFINE_ALL",
+ "INVALID_INDEX",
+ "DBG",
+ "QUERY_LIMIT",
+ "REFINE_BY_ENTRY"
+ ]
+ },
+ "android/support/wear/widget/drawer/WearableActionDrawerView$ActionItemViewHolder": {
+ "androidx/wear/widget/drawer/WearableActionDrawerView$ActionItemViewHolder": [
+ "view",
+ "iconView",
+ "textView"
+ ]
+ },
+ "android/support/v14/preference/PreferenceDialogFragment": {
+ "androidx/preference/PreferenceDialogFragment": [
+ "SAVE_STATE_POSITIVE_TEXT",
+ "SAVE_STATE_TITLE",
+ "SAVE_STATE_ICON",
+ "ARG_KEY",
+ "SAVE_STATE_MESSAGE",
+ "SAVE_STATE_NEGATIVE_TEXT",
+ "SAVE_STATE_LAYOUT"
+ ]
+ },
+ "android/support/v4/media/session/IMediaControllerCallback$Stub": {
+ "androidx/media/session/IMediaControllerCallback$Stub": [
+ "TRANSACTION_onSessionDestroyed",
+ "TRANSACTION_onMetadataChanged",
+ "TRANSACTION_onEvent",
+ "TRANSACTION_onQueueChanged",
+ "TRANSACTION_onSessionReady",
+ "TRANSACTION_onCaptioningEnabledChanged",
+ "TRANSACTION_onVolumeInfoChanged",
+ "TRANSACTION_onShuffleModeChangedRemoved",
+ "TRANSACTION_onRepeatModeChanged",
+ "TRANSACTION_onPlaybackStateChanged",
+ "TRANSACTION_onQueueTitleChanged",
+ "TRANSACTION_onShuffleModeChanged",
+ "DESCRIPTOR",
+ "TRANSACTION_onExtrasChanged"
+ ]
+ },
+ "android/support/v7/preference/EditTextPreference$SavedState": {
+ "androidx/preference/EditTextPreference$SavedState": [
+ "text",
+ "CREATOR"
+ ]
+ },
+ "android/support/v17/leanback/widget/PagingIndicator$Dot": {
+ "androidx/leanback/widget/PagingIndicator$Dot": [
+ "LEFT",
+ "LTR",
+ "RIGHT",
+ "RTL"
+ ]
+ },
+ "android/support/v7/widget/ScrollingTabContainerView$TabView": {
+ "androidx/widget/ScrollingTabContainerView$TabView": [
+ "BG_ATTRS"
+ ]
+ },
+ "android/support/wear/ambient/SharedLibraryVersion$PresenceHolder": {
+ "androidx/wear/ambient/SharedLibraryVersion$PresenceHolder": [
+ "PRESENT"
+ ]
+ },
+ "android/support/v4/graphics/BitmapCompat": {
+ "androidx/graphics/BitmapCompat": [
+ "IMPL"
+ ]
+ },
+ "android/support/wear/R$fraction": {
+ "androidx/wear/R$fraction": [
+ "ws_action_drawer_item_right_padding",
+ "ws_action_drawer_item_last_item_bottom_padding",
+ "ws_action_drawer_item_left_padding",
+ "ws_action_drawer_item_first_item_top_padding"
+ ]
+ },
+ "android/support/v7/media/MediaSessionStatus": {
+ "androidx/media/MediaSessionStatus": [
+ "KEY_TIMESTAMP",
+ "SESSION_STATE_INVALIDATED",
+ "KEY_EXTRAS",
+ "KEY_QUEUE_PAUSED",
+ "KEY_SESSION_STATE",
+ "SESSION_STATE_ENDED",
+ "SESSION_STATE_ACTIVE"
+ ]
+ },
+ "android/support/v4/app/NotificationManagerCompat$CancelTask": {
+ "androidx/app/NotificationManagerCompat$CancelTask": [
+ "tag",
+ "all",
+ "id",
+ "packageName"
+ ]
+ },
+ "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase": {
+ "androidx/media/MediaBrowserCompat$MediaBrowserImplBase": [
+ "CONNECT_STATE_DISCONNECTED",
+ "CONNECT_STATE_CONNECTED",
+ "CONNECT_STATE_CONNECTING",
+ "CONNECT_STATE_SUSPENDED",
+ "CONNECT_STATE_DISCONNECTING"
+ ]
+ },
+ "android/support/wear/widget/WearableRecyclerView": {
+ "androidx/wear/widget/WearableRecyclerView": [
+ "TAG",
+ "NO_VALUE"
+ ]
+ },
+ "android/support/app/recommendation/RecommendationExtender": {
+ "androidx/app/recommendation/RecommendationExtender": [
+ "KEY_CONTENT_RUN_LENGTH",
+ "KEY_CONTENT_GENRES",
+ "KEY_CONTENT_TYPE",
+ "TAG",
+ "EXTRA_CONTENT_INFO_EXTENDER",
+ "KEY_CONTENT_MATURITY_RATING",
+ "KEY_CONTENT_STATUS",
+ "KEY_CONTENT_PRICING_VALUE",
+ "KEY_CONTENT_PRICING_TYPE"
+ ]
+ },
+ "android/support/v7/widget/ThemeUtils": {
+ "androidx/widget/ThemeUtils": [
+ "TEMP_ARRAY",
+ "DISABLED_STATE_SET",
+ "ACTIVATED_STATE_SET",
+ "NOT_PRESSED_OR_FOCUSED_STATE_SET",
+ "FOCUSED_STATE_SET",
+ "SELECTED_STATE_SET",
+ "CHECKED_STATE_SET",
+ "PRESSED_STATE_SET",
+ "EMPTY_STATE_SET",
+ "TL_TYPED_VALUE"
+ ]
+ },
+ "android/support/media/ExifInterface$ByteOrderedDataInputStream": {
+ "androidx/media/ExifInterface$ByteOrderedDataInputStream": [
+ "BIG_ENDIAN",
+ "LITTLE_ENDIAN"
+ ]
+ },
+ "android/support/v7/widget/helper/ItemTouchHelper$Callback": {
+ "androidx/widget/helper/ItemTouchHelper$Callback": [
+ "ABS_HORIZONTAL_DIR_FLAGS",
+ "sDragScrollInterpolator",
+ "DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS",
+ "DEFAULT_DRAG_ANIMATION_DURATION",
+ "RELATIVE_DIR_FLAGS",
+ "DEFAULT_SWIPE_ANIMATION_DURATION",
+ "sDragViewScrollCapInterpolator",
+ "sUICallback"
+ ]
+ },
+ "android/support/v4/media/MediaBrowserServiceCompat$BrowserRoot": {
+ "androidx/media/MediaBrowserServiceCompat$BrowserRoot": [
+ "EXTRA_SUGGESTION_KEYWORDS",
+ "EXTRA_SUGGESTED",
+ "EXTRA_OFFLINE",
+ "EXTRA_RECENT"
+ ]
+ },
+ "android/support/v17/leanback/widget/PlaybackControlsPresenter": {
+ "androidx/leanback/widget/PlaybackControlsPresenter": [
+ "sChildMarginBigger",
+ "sChildMarginBiggest"
+ ]
+ },
+ "android/support/v7/preference/PreferenceDialogFragmentCompat": {
+ "androidx/preference/PreferenceDialogFragmentCompat": [
+ "SAVE_STATE_LAYOUT",
+ "ARG_KEY",
+ "SAVE_STATE_ICON",
+ "SAVE_STATE_MESSAGE",
+ "SAVE_STATE_TITLE",
+ "SAVE_STATE_NEGATIVE_TEXT",
+ "SAVE_STATE_POSITIVE_TEXT"
+ ]
+ },
+ "android/support/v7/app/TwilightManager": {
+ "androidx/app/TwilightManager": [
+ "SUNRISE",
+ "SUNSET",
+ "TAG",
+ "sInstance"
+ ]
+ },
+ "android/support/v4/graphics/drawable/DrawableCompat": {
+ "androidx/graphics/drawable/DrawableCompat": [
+ "sSetLayoutDirectionMethod",
+ "sGetLayoutDirectionMethodFetched",
+ "sGetLayoutDirectionMethod",
+ "TAG",
+ "sSetLayoutDirectionMethodFetched"
+ ]
+ },
+ "android/support/coreutils/BuildConfig": {
+ "androidx/coreutils/BuildConfig": [
+ "FLAVOR",
+ "APPLICATION_ID",
+ "VERSION_NAME",
+ "BUILD_TYPE",
+ "VERSION_CODE",
+ "DEBUG"
+ ]
+ },
+ "android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory": {
+ "androidx/graphics/drawable/RoundedBitmapDrawableFactory": [
+ "TAG"
+ ]
+ },
+ "android/support/transition/GhostViewApi21": {
+ "androidx/transition/GhostViewApi21": [
+ "sAddGhostMethod",
+ "TAG",
+ "sRemoveGhostMethod",
+ "sAddGhostMethodFetched",
+ "sRemoveGhostMethodFetched",
+ "sGhostViewClassFetched",
+ "sGhostViewClass"
+ ]
+ },
+ "android/support/v7/app/ActionBar": {
+ "androidx/app/ActionBar": [
+ "NAVIGATION_MODE_TABS",
+ "NAVIGATION_MODE_LIST",
+ "DISPLAY_SHOW_TITLE",
+ "DISPLAY_SHOW_CUSTOM",
+ "DISPLAY_USE_LOGO",
+ "NAVIGATION_MODE_STANDARD",
+ "DISPLAY_HOME_AS_UP",
+ "DISPLAY_SHOW_HOME"
+ ]
+ },
+ "android/support/media/tv/TvContractCompat$WatchNextPrograms": {
+ "androidx/media/tv/TvContractCompat$WatchNextPrograms": [
+ "WATCH_NEXT_TYPE_WATCHLIST",
+ "WATCH_NEXT_TYPE_CONTINUE",
+ "WATCH_NEXT_TYPE_NEXT",
+ "COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS",
+ "CONTENT_URI",
+ "WATCH_NEXT_TYPE_NEW",
+ "CONTENT_TYPE",
+ "COLUMN_WATCH_NEXT_TYPE",
+ "CONTENT_ITEM_TYPE"
+ ]
+ },
+ "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$CollectionInfoCompat": {
+ "androidx/view/accessibility/AccessibilityNodeInfoCompat$CollectionInfoCompat": [
+ "SELECTION_MODE_MULTIPLE",
+ "SELECTION_MODE_SINGLE",
+ "SELECTION_MODE_NONE"
+ ]
+ },
+ "android/support/v17/preference/R$id": {
+ "androidx/leanback/preference/R$id": [
+ "button",
+ "settings_preference_fragment_container",
+ "main_frame",
+ "container",
+ "decor_title",
+ "settings_dialog_container"
+ ]
+ },
+ "android/support/wear/R$style": {
+ "androidx/wear/R$style": [
+ "Widget_Wear_WearableDrawerView",
+ "WsPageIndicatorViewStyle"
+ ]
+ },
+ "android/support/v17/leanback/widget/GuidedActionAdapterGroup": {
+ "androidx/leanback/widget/GuidedActionAdapterGroup": [
+ "TAG_EDIT",
+ "DEBUG_EDIT"
+ ]
+ },
+ "android/support/v7/widget/GridLayout$PackedMap": {
+ "androidx/widget/GridLayout$PackedMap": [
+ "values",
+ "index",
+ "keys"
+ ]
+ },
+ "android/support/v7/widget/ActionBarOverlayLayout": {
+ "androidx/widget/ActionBarOverlayLayout": [
+ "TAG",
+ "ATTRS",
+ "ACTION_BAR_ANIMATE_DELAY"
+ ]
+ },
+ "android/support/fragment/BuildConfig": {
+ "androidx/fragment/BuildConfig": [
+ "VERSION_NAME",
+ "BUILD_TYPE",
+ "VERSION_CODE",
+ "DEBUG",
+ "APPLICATION_ID",
+ "FLAVOR"
+ ]
+ },
+ "android/support/v4/app/NavUtils": {
+ "androidx/app/NavUtils": [
+ "TAG",
+ "PARENT_ACTIVITY"
+ ]
+ },
+ "android/support/v7/media/RemotePlaybackClient$ActionReceiver": {
+ "androidx/media/RemotePlaybackClient$ActionReceiver": [
+ "ACTION_ITEM_STATUS_CHANGED",
+ "ACTION_MESSAGE_RECEIVED",
+ "ACTION_SESSION_STATUS_CHANGED"
+ ]
+ },
+ "android/support/v4/app/JobIntentService$JobServiceEngineImpl": {
+ "androidx/app/JobIntentService$JobServiceEngineImpl": [
+ "TAG",
+ "DEBUG"
+ ]
+ },
+ "android/support/v4/app/FragmentActivity$NonConfigurationInstances": {
+ "androidx/app/FragmentActivity$NonConfigurationInstances": [
+ "custom",
+ "fragments",
+ "loaders"
+ ]
+ },
+ "android/support/text/emoji/flatbuffer/FlatBufferBuilder": {
+ "androidx/text/emoji/flatbuffer/FlatBufferBuilder": [
+ "encoder",
+ "vtable_in_use",
+ "minalign",
+ "vtables",
+ "num_vtables",
+ "force_defaults",
+ "space",
+ "bb",
+ "object_start",
+ "vtable",
+ "dst",
+ "vector_num_elems",
+ "nested",
+ "finished",
+ "utf8charset"
+ ]
+ },
+ "android/support/v7/mediarouter/R$interpolator": {
+ "androidx/mediarouter/R$interpolator": [
+ "mr_fast_out_slow_in",
+ "mr_linear_out_slow_in"
+ ]
+ },
+ "android/support/v7/recyclerview/R$dimen": {
+ "androidx/recyclerview/R$dimen": [
+ "item_touch_helper_max_drag_scroll_per_frame",
+ "fastscroll_minimum_range",
+ "item_touch_helper_swipe_escape_max_velocity",
+ "fastscroll_default_thickness",
+ "item_touch_helper_swipe_escape_velocity",
+ "fastscroll_margin"
+ ]
+ },
+ "android/support/v4/app/ShareCompat": {
+ "androidx/app/ShareCompat": [
+ "EXTRA_CALLING_PACKAGE",
+ "HISTORY_FILENAME_PREFIX",
+ "EXTRA_CALLING_ACTIVITY"
+ ]
+ },
+ "android/support/v4/media/AudioAttributesCompatApi21": {
+ "androidx/media/AudioAttributesCompatApi21": [
+ "TAG",
+ "sAudioAttributesToLegacyStreamType"
+ ]
+ },
+ "android/support/customtabs/CustomTabsCallback": {
+ "androidx/browser/customtabs/CustomTabsCallback": [
+ "NAVIGATION_FINISHED",
+ "NAVIGATION_ABORTED",
+ "NAVIGATION_FAILED",
+ "NAVIGATION_STARTED",
+ "TAB_HIDDEN",
+ "TAB_SHOWN"
+ ]
+ },
+ "android/support/wear/widget/CircularProgressLayout": {
+ "androidx/wear/widget/CircularProgressLayout": [
+ "DEFAULT_ROTATION",
+ "DEFAULT_UPDATE_INTERVAL"
+ ]
+ },
+ "android/support/v17/leanback/widget/ListRowPresenter": {
+ "androidx/leanback/widget/ListRowPresenter": [
+ "DEBUG",
+ "TAG",
+ "sExpandedSelectedRowTopPadding",
+ "DEFAULT_RECYCLED_POOL_SIZE",
+ "sExpandedRowNoHovercardBottomPadding",
+ "sSelectedRowTopPadding"
+ ]
+ },
+ "android/support/v7/preference/PreferenceGroupAdapter$PreferenceLayout": {
+ "androidx/preference/PreferenceGroupAdapter$PreferenceLayout": [
+ "widgetResId",
+ "resId",
+ "name"
+ ]
+ },
+ "android/support/transition/BuildConfig": {
+ "androidx/transition/BuildConfig": [
+ "FLAVOR",
+ "DEBUG",
+ "BUILD_TYPE",
+ "VERSION_CODE",
+ "APPLICATION_ID",
+ "VERSION_NAME"
+ ]
+ },
+ "android/support/transition/Styleable$Transition": {
+ "androidx/transition/Styleable$Transition": [
+ "MATCH_ORDER",
+ "START_DELAY",
+ "DURATION",
+ "INTERPOLATOR"
+ ]
+ },
+ "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$RangeInfoCompat": {
+ "androidx/view/accessibility/AccessibilityNodeInfoCompat$RangeInfoCompat": [
+ "RANGE_TYPE_PERCENT",
+ "RANGE_TYPE_INT",
+ "RANGE_TYPE_FLOAT"
+ ]
+ },
+ "android/support/transition/Styleable$Fade": {
+ "androidx/transition/Styleable$Fade": [
+ "FADING_MODE"
+ ]
+ },
+ "android/support/v4/app/SharedElementCallback": {
+ "androidx/app/SharedElementCallback": [
+ "BUNDLE_SNAPSHOT_BITMAP",
+ "BUNDLE_SNAPSHOT_IMAGE_MATRIX",
+ "BUNDLE_SNAPSHOT_IMAGE_SCALETYPE",
+ "MAX_IMAGE_SIZE"
+ ]
+ },
+ "android/support/design/widget/ThemeUtils": {
+ "androidx/design/widget/ThemeUtils": [
+ "APPCOMPAT_CHECK_ATTRS"
+ ]
+ },
+ "android/support/media/tv/TvContractCompat$Programs": {
+ "androidx/media/tv/TvContractCompat$Programs": [
+ "COLUMN_BROADCAST_GENRE",
+ "COLUMN_CHANNEL_ID",
+ "COLUMN_START_TIME_UTC_MILLIS",
+ "CONTENT_ITEM_TYPE",
+ "CONTENT_TYPE",
+ "COLUMN_EPISODE_NUMBER",
+ "COLUMN_END_TIME_UTC_MILLIS",
+ "COLUMN_RECORDING_PROHIBITED",
+ "CONTENT_URI",
+ "COLUMN_SEASON_NUMBER"
+ ]
+ },
+ "android/support/v17/leanback/R$integer": {
+ "androidx/leanback/R$integer": [
+ "lb_details_description_body_min_lines",
+ "lb_search_orb_pulse_duration_ms",
+ "lb_search_bar_speech_mode_background_alpha",
+ "lb_search_bar_text_mode_background_alpha",
+ "lb_details_description_body_max_lines",
+ "lb_card_activated_animation_duration",
+ "lb_card_selected_animation_duration",
+ "lb_search_orb_scale_duration_ms",
+ "lb_browse_rows_anim_duration",
+ "lb_playback_controls_show_time_ms",
+ "lb_card_selected_animation_delay"
+ ]
+ },
+ "android/support/mediacompat/R$id": {
+ "androidx/mediacompat/R$id": [
+ "action0",
+ "media_actions",
+ "cancel_action",
+ "status_bar_latest_event_content",
+ "end_padder"
+ ]
+ },
+ "android/support/v17/leanback/widget/Row": {
+ "androidx/leanback/widget/Row": [
+ "FLAG_ID_USE_HEADER",
+ "FLAG_ID_USE_ID",
+ "FLAG_ID_USE_MASK"
+ ]
+ },
+ "android/support/compat/R$layout": {
+ "androidx/compat/R$layout": [
+ "notification_action_tombstone",
+ "notification_template_custom_big",
+ "notification_action"
+ ]
+ },
+ "android/support/v4/app/FragmentManagerImpl$AnimationOrAnimator": {
+ "androidx/app/FragmentManagerImpl$AnimationOrAnimator": [
+ "animator",
+ "animation"
+ ]
+ },
+ "android/support/transition/VisibilityPropagation": {
+ "androidx/transition/VisibilityPropagation": [
+ "PROPNAME_VISIBILITY",
+ "PROPNAME_VIEW_CENTER",
+ "VISIBILITY_PROPAGATION_VALUES"
+ ]
+ },
+ "android/support/v13/BuildConfig": {
+ "androidx/BuildConfig": [
+ "VERSION_NAME",
+ "BUILD_TYPE",
+ "VERSION_CODE",
+ "DEBUG",
+ "APPLICATION_ID",
+ "FLAVOR"
+ ]
+ },
+ "android/support/v4/app/NotificationCompat$Action$WearableExtender": {
+ "androidx/app/NotificationCompat$Action$WearableExtender": [
+ "KEY_FLAGS",
+ "KEY_CONFIRM_LABEL",
+ "KEY_CANCEL_LABEL",
+ "FLAG_HINT_LAUNCHES_ACTIVITY",
+ "KEY_IN_PROGRESS_LABEL",
+ "EXTRA_WEARABLE_EXTENSIONS",
+ "FLAG_AVAILABLE_OFFLINE",
+ "FLAG_HINT_DISPLAY_INLINE",
+ "DEFAULT_FLAGS"
+ ]
+ },
+ "android/support/v4/view/ViewPager$ItemInfo": {
+ "androidx/view/ViewPager$ItemInfo": [
+ "offset",
+ "object",
+ "position",
+ "widthFactor",
+ "scrolling"
+ ]
+ },
+ "android/support/v17/leanback/transition/TransitionHelper": {
+ "androidx/leanback/transition/TransitionHelper": [
+ "SLIDE_RIGHT",
+ "sImpl",
+ "SLIDE_BOTTOM",
+ "FADE_OUT",
+ "SLIDE_TOP",
+ "FADE_IN",
+ "SLIDE_LEFT"
+ ]
+ },
+ "android/support/v4/widget/AutoSizeableTextView": {
+ "androidx/widget/AutoSizeableTextView": [
+ "PLATFORM_SUPPORTS_AUTOSIZE"
+ ]
+ },
+ "android/support/v7/widget/SimpleItemAnimator": {
+ "androidx/widget/SimpleItemAnimator": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/transition/TransitionManager": {
+ "androidx/transition/TransitionManager": [
+ "sPendingTransitions",
+ "sRunningTransitions",
+ "sDefaultTransition",
+ "LOG_TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/WindowAlignment$Axis": {
+ "androidx/leanback/widget/WindowAlignment$Axis": [
+ "PF_KEYLINE_OVER_HIGH_EDGE",
+ "PF_KEYLINE_OVER_LOW_EDGE"
+ ]
+ },
+ "android/support/v7/widget/AppCompatPopupWindow": {
+ "androidx/widget/AppCompatPopupWindow": [
+ "COMPAT_OVERLAP_ANCHOR"
+ ]
+ },
+ "android/support/constraint/solver/widgets/ConstraintAnchor$Type": {
+ "androidx/constraint/solver/widgets/ConstraintAnchor$Type": [
+ "RIGHT",
+ "TOP",
+ "BOTTOM",
+ "LEFT",
+ "BASELINE"
+ ]
+ },
+ "android/support/wear/widget/drawer/WearableDrawerLayout": {
+ "androidx/wear/widget/drawer/WearableDrawerLayout": [
+ "TAG",
+ "UP",
+ "OPENED_PERCENT_THRESHOLD",
+ "NESTED_SCROLL_SLOP_DP",
+ "GRAVITY_UNDEFINED",
+ "DOWN",
+ "PEEK_FADE_DURATION_MS",
+ "PEEK_AUTO_CLOSE_DELAY_MS"
+ ]
+ },
+ "android/support/v17/leanback/widget/ShadowOverlayHelper$Builder": {
+ "androidx/leanback/widget/ShadowOverlayHelper$Builder": [
+ "options",
+ "needsRoundedCorner",
+ "keepForegroundDrawable",
+ "preferZOrder",
+ "needsOverlay",
+ "needsShadow"
+ ]
+ },
+ "android/support/v7/media/MediaRouteProvider": {
+ "androidx/media/MediaRouteProvider": [
+ "MSG_DELIVER_DESCRIPTOR_CHANGED",
+ "MSG_DELIVER_DISCOVERY_REQUEST_CHANGED"
+ ]
+ },
+ "android/support/design/widget/AppBarLayout$LayoutParams": {
+ "androidx/design/widget/AppBarLayout$LayoutParams": [
+ "SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED",
+ "bottomMargin",
+ "topMargin",
+ "SCROLL_FLAG_EXIT_UNTIL_COLLAPSED",
+ "SCROLL_FLAG_SCROLL",
+ "COLLAPSIBLE_FLAGS",
+ "FLAG_SNAP",
+ "SCROLL_FLAG_SNAP",
+ "FLAG_QUICK_RETURN",
+ "SCROLL_FLAG_ENTER_ALWAYS"
+ ]
+ },
+ "android/support/v7/media/MediaRouterJellybean": {
+ "androidx/media/MediaRouterJellybean": [
+ "TAG",
+ "DEVICE_OUT_BLUETOOTH",
+ "ROUTE_TYPE_LIVE_AUDIO",
+ "ROUTE_TYPE_USER",
+ "ROUTE_TYPE_LIVE_VIDEO",
+ "ALL_ROUTE_TYPES"
+ ]
+ },
+ "android/support/content/LoaderQueryRunner": {
+ "androidx/content/LoaderQueryRunner": [
+ "TAG",
+ "CONTENT_URI_KEY",
+ "DEBUG"
+ ]
+ },
+ "android/support/v17/preference/BuildConfig": {
+ "androidx/leanback/preference/BuildConfig": [
+ "BUILD_TYPE",
+ "VERSION_NAME",
+ "FLAVOR",
+ "DEBUG",
+ "VERSION_CODE",
+ "APPLICATION_ID"
+ ]
+ },
+ "android/support/v17/leanback/app/BackgroundManager$BackgroundContinuityService": {
+ "androidx/leanback/app/BackgroundManager$BackgroundContinuityService": [
+ "DEBUG",
+ "TAG",
+ "sService"
+ ]
+ },
+ "android/support/design/internal/NavigationMenuPresenter": {
+ "androidx/design/internal/NavigationMenuPresenter": [
+ "STATE_HEADER",
+ "STATE_ADAPTER",
+ "STATE_HIERARCHY"
+ ]
+ },
+ "android/support/v17/leanback/widget/RowPresenter$ViewHolder": {
+ "androidx/leanback/widget/RowPresenter$ViewHolder": [
+ "ACTIVATED_NOT_ASSIGNED",
+ "NOT_ACTIVATED",
+ "ACTIVATED",
+ "view"
+ ]
+ },
+ "android/support/v7/widget/AppCompatCheckedTextView": {
+ "androidx/widget/AppCompatCheckedTextView": [
+ "TINT_ATTRS"
+ ]
+ },
+ "android/support/transition/ChangeImageTransform": {
+ "androidx/transition/ChangeImageTransform": [
+ "PROPNAME_BOUNDS",
+ "NULL_MATRIX_EVALUATOR",
+ "ANIMATED_TRANSFORM_PROPERTY",
+ "sTransitionProperties",
+ "PROPNAME_MATRIX"
+ ]
+ },
+ "android/support/design/widget/AppBarLayout$Behavior$SavedState": {
+ "androidx/design/widget/AppBarLayout$Behavior$SavedState": [
+ "firstVisibleChildIndex",
+ "firstVisibleChildPercentageShown",
+ "firstVisibleChildAtMinimumHeight",
+ "CREATOR"
+ ]
+ },
+ "android/support/design/widget/Snackbar": {
+ "androidx/design/widget/Snackbar": [
+ "LENGTH_SHORT",
+ "LENGTH_INDEFINITE",
+ "LENGTH_LONG"
+ ]
+ },
+ "android/support/v7/app/ActionBarDrawerToggleHoneycomb$SetIndicatorInfo": {
+ "androidx/app/ActionBarDrawerToggleHoneycomb$SetIndicatorInfo": [
+ "setHomeActionContentDescription",
+ "setHomeAsUpIndicator",
+ "upIndicatorView"
+ ]
+ },
+ "android/support/v17/leanback/widget/Grid": {
+ "androidx/leanback/widget/Grid": [
+ "START_DEFAULT"
+ ]
+ },
+ "android/support/media/tv/WatchNextProgram": {
+ "androidx/media/tv/WatchNextProgram": [
+ "PROJECTION",
+ "INVALID_INT_VALUE",
+ "INVALID_LONG_VALUE"
+ ]
+ },
+ "android/support/v7/widget/TintContextWrapper": {
+ "androidx/widget/TintContextWrapper": [
+ "CACHE_LOCK",
+ "sCache"
+ ]
+ },
+ "android/support/text/emoji/flatbuffer/Constants": {
+ "androidx/text/emoji/flatbuffer/Constants": [
+ "SIZEOF_INT",
+ "SIZEOF_FLOAT",
+ "SIZEOF_LONG",
+ "FILE_IDENTIFIER_LENGTH",
+ "SIZEOF_SHORT",
+ "SIZEOF_BYTE",
+ "SIZEOF_DOUBLE"
+ ]
+ },
+ "android/support/wear/widget/CurvingLayoutCallback": {
+ "androidx/wear/widget/CurvingLayoutCallback": [
+ "EPSILON"
+ ]
+ },
+ "android/support/v4/app/AppOpsManagerCompat": {
+ "androidx/app/AppOpsManagerCompat": [
+ "MODE_IGNORED",
+ "MODE_DEFAULT",
+ "MODE_ALLOWED"
+ ]
+ },
+ "android/support/v4/widget/CursorAdapter": {
+ "androidx/widget/CursorAdapter": [
+ "FLAG_AUTO_REQUERY",
+ "FLAG_REGISTER_CONTENT_OBSERVER"
+ ]
+ },
+ "android/support/v17/leanback/app/DetailsBackgroundVideoHelper": {
+ "androidx/leanback/app/DetailsBackgroundVideoHelper": [
+ "NO_VIDEO",
+ "CROSSFADE_DELAY",
+ "INITIAL",
+ "BACKGROUND_CROSS_FADE_DURATION",
+ "PLAY_VIDEO"
+ ]
+ },
+ "android/support/transition/ChangeBounds": {
+ "androidx/transition/ChangeBounds": [
+ "PROPNAME_BOUNDS",
+ "POSITION_PROPERTY",
+ "sRectEvaluator",
+ "BOTTOM_RIGHT_PROPERTY",
+ "BOTTOM_RIGHT_ONLY_PROPERTY",
+ "DRAWABLE_ORIGIN_PROPERTY",
+ "sTransitionProperties",
+ "TOP_LEFT_ONLY_PROPERTY",
+ "PROPNAME_PARENT",
+ "TOP_LEFT_PROPERTY",
+ "PROPNAME_CLIP",
+ "PROPNAME_WINDOW_X",
+ "PROPNAME_WINDOW_Y"
+ ]
+ },
+ "android/support/v4/widget/SwipeProgressBar": {
+ "androidx/widget/SwipeProgressBar": [
+ "INTERPOLATOR",
+ "ANIMATION_DURATION_MS",
+ "FINISH_ANIMATION_DURATION_MS",
+ "COLOR2",
+ "COLOR1",
+ "COLOR4",
+ "COLOR3"
+ ]
+ },
+ "android/support/v17/leanback/media/PlaybackTransportControlGlue": {
+ "androidx/leanback/media/PlaybackTransportControlGlue": [
+ "UPDATE_PLAYBACK_STATE_DELAY_MS",
+ "sHandler",
+ "TAG",
+ "DEBUG",
+ "MSG_UPDATE_PLAYBACK_STATE"
+ ]
+ },
+ "android/support/media/tv/BasePreviewProgram": {
+ "androidx/media/tv/BasePreviewProgram": [
+ "IS_LIVE",
+ "IS_TRANSIENT",
+ "PROJECTION",
+ "INVALID_LONG_VALUE",
+ "INVALID_INT_VALUE",
+ "IS_BROWSABLE"
+ ]
+ },
+ "android/support/v4/widget/TextViewCompat$TextViewCompatBaseImpl": {
+ "androidx/widget/TextViewCompat$TextViewCompatBaseImpl": [
+ "sMaxModeFieldFetched",
+ "sMinimumFieldFetched",
+ "sMinModeField",
+ "sMaximumField",
+ "sMinModeFieldFetched",
+ "sMaxModeField",
+ "sMinimumField",
+ "LOG_TAG",
+ "sMaximumFieldFetched",
+ "LINES"
+ ]
+ },
+ "android/support/v7/media/SystemMediaRouteProvider$LegacyImpl$VolumeChangeReceiver": {
+ "androidx/media/SystemMediaRouteProvider$LegacyImpl$VolumeChangeReceiver": [
+ "EXTRA_VOLUME_STREAM_TYPE",
+ "VOLUME_CHANGED_ACTION",
+ "EXTRA_VOLUME_STREAM_VALUE"
+ ]
+ },
+ "android/support/transition/Styleable$ChangeBounds": {
+ "androidx/transition/Styleable$ChangeBounds": [
+ "RESIZE_CLIP"
+ ]
+ },
+ "android/support/v7/widget/ActivityChooserModel": {
+ "androidx/widget/ActivityChooserModel": [
+ "DEFAULT_ACTIVITY_INFLATION",
+ "ATTRIBUTE_TIME",
+ "TAG_HISTORICAL_RECORD",
+ "DEFAULT_HISTORY_FILE_NAME",
+ "HISTORY_FILE_EXTENSION",
+ "TAG_HISTORICAL_RECORDS",
+ "ATTRIBUTE_ACTIVITY",
+ "ATTRIBUTE_WEIGHT",
+ "DEBUG",
+ "INVALID_INDEX",
+ "DEFAULT_HISTORICAL_RECORD_WEIGHT",
+ "sDataModelRegistry",
+ "sRegistryLock",
+ "DEFAULT_HISTORY_MAX_LENGTH",
+ "LOG_TAG"
+ ]
+ },
+ "android/support/v7/widget/ViewUtils": {
+ "androidx/widget/ViewUtils": [
+ "TAG",
+ "sComputeFitSystemWindowsMethod"
+ ]
+ },
+ "android/support/v14/preference/ListPreferenceDialogFragment": {
+ "androidx/preference/ListPreferenceDialogFragment": [
+ "SAVE_STATE_ENTRIES",
+ "SAVE_STATE_INDEX",
+ "SAVE_STATE_ENTRY_VALUES"
+ ]
+ },
+ "android/support/v17/leanback/widget/RoundedRectHelper": {
+ "androidx/leanback/widget/RoundedRectHelper": [
+ "sInstance"
+ ]
+ },
+ "android/support/transition/Styleable$TransitionManager": {
+ "androidx/transition/Styleable$TransitionManager": [
+ "FROM_SCENE",
+ "TRANSITION",
+ "TO_SCENE"
+ ]
+ },
+ "android/support/v17/leanback/R$style": {
+ "androidx/leanback/R$style": [
+ "TextAppearance_Leanback_SearchTextEdit",
+ "Widget_Leanback_ImageCardView"
+ ]
+ },
+ "android/support/v7/widget/ShareActionProvider": {
+ "androidx/widget/ShareActionProvider": [
+ "DEFAULT_SHARE_HISTORY_FILE_NAME",
+ "DEFAULT_INITIAL_ACTIVITY_COUNT"
+ ]
+ },
+ "android/support/v4/app/ListFragment": {
+ "androidx/app/ListFragment": [
+ "INTERNAL_EMPTY_ID",
+ "INTERNAL_PROGRESS_CONTAINER_ID",
+ "INTERNAL_LIST_CONTAINER_ID"
+ ]
+ },
+ "android/support/design/widget/BottomSheetBehavior$SavedState": {
+ "androidx/design/widget/BottomSheetBehavior$SavedState": [
+ "state",
+ "CREATOR"
+ ]
+ },
+ "android/support/v7/appcompat/R$color": {
+ "androidx/appcompat/R$color": [
+ "abc_tint_switch_track",
+ "abc_tint_edittext",
+ "abc_tint_btn_checkable",
+ "abc_tint_default",
+ "abc_tint_spinner",
+ "abc_tint_seek_thumb",
+ "error_color_material",
+ "abc_input_method_navigation_guard"
+ ]
+ },
+ "android/support/v17/leanback/R$raw": {
+ "androidx/leanback/R$raw": [
+ "lb_voice_no_input",
+ "lb_voice_failure",
+ "lb_voice_success",
+ "lb_voice_open"
+ ]
+ },
+ "android/support/v7/util/DiffUtil$PostponedUpdate": {
+ "androidx/util/DiffUtil$PostponedUpdate": [
+ "posInOwnerList",
+ "removal",
+ "currentPos"
+ ]
+ },
+ "android/support/v7/graphics/drawable/DrawerArrowDrawable": {
+ "androidx/graphics/drawable/DrawerArrowDrawable": [
+ "ARROW_DIRECTION_LEFT",
+ "ARROW_HEAD_ANGLE",
+ "ARROW_DIRECTION_RIGHT",
+ "ARROW_DIRECTION_END",
+ "ARROW_DIRECTION_START"
+ ]
+ },
+ "android/support/v4/os/IResultReceiver$Stub": {
+ "androidx/os/IResultReceiver$Stub": [
+ "TRANSACTION_send",
+ "DESCRIPTOR"
+ ]
+ },
+ "android/support/v7/util/DiffUtil$Range": {
+ "androidx/util/DiffUtil$Range": [
+ "newListEnd",
+ "oldListEnd",
+ "newListStart",
+ "oldListStart"
+ ]
+ },
+ "android/support/v7/widget/ActionMenuPresenter$SavedState": {
+ "androidx/widget/ActionMenuPresenter$SavedState": [
+ "CREATOR",
+ "openSubMenuId"
+ ]
+ },
+ "android/support/v17/leanback/widget/GuidedActionAdapter": {
+ "androidx/leanback/widget/GuidedActionAdapter": [
+ "DEBUG",
+ "DEBUG_EDIT",
+ "TAG_EDIT",
+ "TAG"
+ ]
+ },
+ "android/support/v7/widget/AppCompatMultiAutoCompleteTextView": {
+ "androidx/widget/AppCompatMultiAutoCompleteTextView": [
+ "TINT_ATTRS"
+ ]
+ },
+ "android/support/compat/R$dimen": {
+ "androidx/compat/R$dimen": [
+ "notification_small_icon_background_padding",
+ "notification_top_pad_large_text",
+ "notification_large_icon_width",
+ "notification_small_icon_size_as_large",
+ "notification_big_circle_margin",
+ "notification_subtext_size",
+ "notification_top_pad",
+ "notification_right_icon_size"
+ ]
+ },
+ "android/support/customtabs/CustomTabsSessionToken": {
+ "androidx/browser/customtabs/CustomTabsSessionToken": [
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/StaggeredGrid$Location": {
+ "androidx/leanback/widget/StaggeredGrid$Location": [
+ "row",
+ "offset",
+ "size"
+ ]
+ },
+ "android/support/compat/R$color": {
+ "androidx/compat/R$color": [
+ "notification_action_color_filter"
+ ]
+ },
+ "android/support/v7/widget/DefaultItemAnimator$ChangeInfo": {
+ "androidx/widget/DefaultItemAnimator$ChangeInfo": [
+ "toY",
+ "toX",
+ "oldHolder",
+ "newHolder",
+ "fromY",
+ "fromX"
+ ]
+ },
+ "android/support/v17/leanback/widget/PlaybackControlsPresenter$ViewHolder": {
+ "androidx/leanback/widget/PlaybackControlsPresenter$ViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/v4/app/DialogFragment": {
+ "androidx/app/DialogFragment": [
+ "SAVED_SHOWS_DIALOG",
+ "STYLE_NORMAL",
+ "STYLE_NO_INPUT",
+ "SAVED_CANCELABLE",
+ "SAVED_THEME",
+ "SAVED_DIALOG_STATE_TAG",
+ "STYLE_NO_TITLE",
+ "SAVED_BACK_STACK_ID",
+ "STYLE_NO_FRAME",
+ "SAVED_STYLE"
+ ]
+ },
+ "android/support/v7/palette/BuildConfig": {
+ "androidx/palette/BuildConfig": [
+ "VERSION_CODE",
+ "DEBUG",
+ "FLAVOR",
+ "BUILD_TYPE",
+ "APPLICATION_ID",
+ "VERSION_NAME"
+ ]
+ },
+ "android/support/v7/preference/R$attr": {
+ "androidx/preference/R$attr": [
+ "dialogPreferenceStyle",
+ "dropdownPreferenceStyle",
+ "preferenceScreenStyle",
+ "editTextPreferenceStyle",
+ "preferenceTheme",
+ "preferenceCategoryStyle",
+ "seekBarPreferenceStyle",
+ "switchPreferenceStyle",
+ "preferenceStyle",
+ "preferenceFragmentStyle",
+ "switchPreferenceCompatStyle",
+ "checkBoxPreferenceStyle",
+ "preferenceFragmentCompatStyle"
+ ]
+ },
+ "android/support/v17/leanback/widget/BaseCardView$LayoutParams": {
+ "androidx/leanback/widget/BaseCardView$LayoutParams": [
+ "VIEW_TYPE_INFO",
+ "VIEW_TYPE_MAIN",
+ "VIEW_TYPE_EXTRA",
+ "viewType"
+ ]
+ },
+ "android/support/wear/ambient/WearableControllerProvider": {
+ "androidx/wear/ambient/WearableControllerProvider": [
+ "TAG",
+ "sAmbientCallbacksVerifiedPresent"
+ ]
+ },
+ "android/support/design/R$anim": {
+ "androidx/design/R$anim": [
+ "design_snackbar_out",
+ "design_snackbar_in"
+ ]
+ },
+ "android/support/wear/ambient/AmbientMode": {
+ "androidx/wear/ambient/AmbientMode": [
+ "FRAGMENT_TAG",
+ "EXTRA_BURN_IN_PROTECTION",
+ "EXTRA_LOWBIT_AMBIENT"
+ ]
+ },
+ "android/support/text/emoji/flatbuffer/MetadataItem": {
+ "androidx/text/emoji/flatbuffer/MetadataItem": [
+ "bb_pos",
+ "bb"
+ ]
+ },
+ "android/support/v13/app/FragmentStatePagerAdapter": {
+ "androidx/app/FragmentStatePagerAdapter": [
+ "TAG",
+ "DEBUG"
+ ]
+ },
+ "android/support/v17/leanback/transition/LeanbackTransitionHelper": {
+ "androidx/leanback/transition/LeanbackTransitionHelper": [
+ "sImpl"
+ ]
+ },
+ "android/support/v7/view/menu/MenuItemWrapperICS": {
+ "androidx/view/menu/MenuItemWrapperICS": [
+ "LOG_TAG"
+ ]
+ },
+ "android/support/v4/content/IntentCompat": {
+ "androidx/content/IntentCompat": [
+ "EXTRA_HTML_TEXT",
+ "CATEGORY_LEANBACK_LAUNCHER",
+ "EXTRA_START_PLAYBACK"
+ ]
+ },
+ "android/support/graphics/drawable/AnimatedVectorDrawableCompat": {
+ "androidx/graphics/drawable/AnimatedVectorDrawableCompat": [
+ "LOGTAG",
+ "TARGET",
+ "ANIMATED_VECTOR",
+ "DBG_ANIMATION_VECTOR_DRAWABLE"
+ ]
+ },
+ "android/support/v7/appcompat/R$style": {
+ "androidx/appcompat/R$style": [
+ "Base_Widget_AppCompat_DrawerArrowToggle",
+ "Theme_AppCompat_Light",
+ "TextAppearance_AppCompat_Caption",
+ "Theme_AppCompat_CompactMenu",
+ "TextAppearance_AppCompat_Widget_ActionBar_Title",
+ "Animation_AppCompat_Tooltip"
+ ]
+ },
+ "android/support/media/instantvideo/widget/InstantVideoView": {
+ "androidx/media/instantvideo/widget/InstantVideoView": [
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/transition/Scale": {
+ "androidx/leanback/transition/Scale": [
+ "PROPNAME_SCALE"
+ ]
+ },
+ "android/support/v4/content/WakefulBroadcastReceiver": {
+ "androidx/content/WakefulBroadcastReceiver": [
+ "EXTRA_WAKE_LOCK_ID",
+ "sActiveWakeLocks"
+ ]
+ },
+ "android/support/v17/leanback/widget/VerticalGridPresenter": {
+ "androidx/leanback/widget/VerticalGridPresenter": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/PersistentFocusWrapper": {
+ "androidx/leanback/widget/PersistentFocusWrapper": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/v4/provider/SelfDestructiveThread": {
+ "androidx/provider/SelfDestructiveThread": [
+ "MSG_DESTRUCTION",
+ "MSG_INVOKE_RUNNABLE"
+ ]
+ },
+ "android/support/customtabs/TrustedWebUtils": {
+ "androidx/browser/customtabs/TrustedWebUtils": [
+ "EXTRA_LAUNCH_AS_TRUSTED_WEB_ACTIVITY"
+ ]
+ },
+ "android/support/v17/leanback/app/RowsSupportFragment": {
+ "androidx/leanback/app/RowsSupportFragment": [
+ "TAG",
+ "ALIGN_TOP_NOT_SET",
+ "DEBUG"
+ ]
+ },
+ "android/support/v17/leanback/widget/ScaleFrameLayout": {
+ "androidx/leanback/widget/ScaleFrameLayout": [
+ "DEFAULT_CHILD_GRAVITY"
+ ]
+ },
+ "android/support/v4/media/MediaBrowserCompat$MediaItem": {
+ "androidx/media/MediaBrowserCompat$MediaItem": [
+ "CREATOR",
+ "FLAG_PLAYABLE",
+ "FLAG_BROWSABLE"
+ ]
+ },
+ "android/support/v4/provider/FontsContractCompat$FontRequestCallback": {
+ "androidx/provider/FontsContractCompat$FontRequestCallback": [
+ "FAIL_REASON_WRONG_CERTIFICATES",
+ "FAIL_REASON_FONT_UNAVAILABLE",
+ "FAIL_REASON_MALFORMED_QUERY",
+ "FAIL_REASON_SECURITY_VIOLATION",
+ "FAIL_REASON_FONT_LOAD_ERROR",
+ "RESULT_OK",
+ "FAIL_REASON_FONT_NOT_FOUND",
+ "FAIL_REASON_PROVIDER_NOT_FOUND"
+ ]
+ },
+ "android/support/dynamicanimation/BuildConfig": {
+ "androidx/dynamicanimation/BuildConfig": [
+ "BUILD_TYPE",
+ "VERSION_NAME",
+ "FLAVOR",
+ "APPLICATION_ID",
+ "VERSION_CODE",
+ "DEBUG"
+ ]
+ },
+ "android/support/v4/widget/NestedScrollView$SavedState": {
+ "androidx/widget/NestedScrollView$SavedState": [
+ "CREATOR",
+ "scrollPosition"
+ ]
+ },
+ "android/support/text/emoji/R$layout": {
+ "androidx/text/emoji/R$layout": [
+ "input_method_extract_view"
+ ]
+ },
+ "android/support/v4/app/FragmentManagerImpl$FragmentTag": {
+ "androidx/app/FragmentManagerImpl$FragmentTag": [
+ "Fragment",
+ "Fragment_tag",
+ "Fragment_name",
+ "Fragment_id"
+ ]
+ },
+ "android/support/v7/widget/GridLayout$Assoc": {
+ "androidx/widget/GridLayout$Assoc": [
+ "keyType",
+ "valueType"
+ ]
+ },
+ "android/support/text/emoji/bundled/BuildConfig": {
+ "androidx/text/emoji/bundled/BuildConfig": [
+ "BUILD_TYPE",
+ "VERSION_NAME",
+ "APPLICATION_ID",
+ "DEBUG",
+ "VERSION_CODE",
+ "FLAVOR"
+ ]
+ },
+ "android/support/v4/app/LoaderManagerImpl": {
+ "androidx/app/LoaderManagerImpl": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/v7/appcompat/R$string": {
+ "androidx/appcompat/R$string": [
+ "abc_action_bar_up_description",
+ "abc_searchview_description_search",
+ "abc_activity_chooser_view_see_all",
+ "abc_shareactionprovider_share_with",
+ "abc_shareactionprovider_share_with_application",
+ "abc_activitychooserview_choose_application"
+ ]
+ },
+ "android/support/v7/widget/AppCompatAutoCompleteTextView": {
+ "androidx/widget/AppCompatAutoCompleteTextView": [
+ "TINT_ATTRS"
+ ]
+ },
+ "android/support/graphics/drawable/animated/BuildConfig": {
+ "androidx/graphics/drawable/animated/BuildConfig": [
+ "BUILD_TYPE",
+ "FLAVOR",
+ "VERSION_NAME",
+ "APPLICATION_ID",
+ "VERSION_CODE",
+ "DEBUG"
+ ]
+ },
+ "android/support/v7/widget/ChildHelper": {
+ "androidx/widget/ChildHelper": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/wear/ambient/SharedLibraryVersion$VersionHolder": {
+ "androidx/wear/ambient/SharedLibraryVersion$VersionHolder": [
+ "VERSION"
+ ]
+ },
+ "android/support/media/tv/BaseProgram": {
+ "androidx/media/tv/BaseProgram": [
+ "INVALID_LONG_VALUE",
+ "PROJECTION",
+ "IS_SEARCHABLE",
+ "INVALID_INT_VALUE"
+ ]
+ },
+ "android/support/transition/TransitionUtils": {
+ "androidx/transition/TransitionUtils": [
+ "MAX_IMAGE_SIZE"
+ ]
+ },
+ "android/support/v17/leanback/widget/ItemAlignment": {
+ "androidx/leanback/widget/ItemAlignment": [
+ "horizontal",
+ "vertical"
+ ]
+ },
+ "android/support/design/widget/NavigationView$SavedState": {
+ "androidx/design/widget/NavigationView$SavedState": [
+ "CREATOR",
+ "menuState"
+ ]
+ },
+ "android/support/v17/leanback/widget/WindowAlignment": {
+ "androidx/leanback/widget/WindowAlignment": [
+ "horizontal",
+ "vertical"
+ ]
+ },
+ "android/support/design/internal/BottomNavigationMenuView": {
+ "androidx/design/internal/BottomNavigationMenuView": [
+ "ACTIVE_ANIMATION_DURATION_MS"
+ ]
+ },
+ "android/support/transition/Slide": {
+ "androidx/transition/Slide": [
+ "sDecelerate",
+ "PROPNAME_SCREEN_POSITION",
+ "sCalculateTop",
+ "sCalculateBottom",
+ "sCalculateRight",
+ "sAccelerate",
+ "sCalculateStart",
+ "sCalculateEnd",
+ "sCalculateLeft"
+ ]
+ },
+ "android/support/text/emoji/MetadataRepo": {
+ "androidx/text/emoji/MetadataRepo": [
+ "DEFAULT_ROOT_SIZE"
+ ]
+ },
+ "android/support/v7/app/AppCompatDelegateImplBase": {
+ "androidx/app/AppCompatDelegateImplBase": [
+ "EXCEPTION_HANDLER_MESSAGE_SUFFIX",
+ "sInstalledExceptionHandler",
+ "sWindowBackgroundStyleable",
+ "DEBUG",
+ "SHOULD_INSTALL_EXCEPTION_HANDLER"
+ ]
+ },
+ "android/support/v7/widget/StaggeredGridLayoutManager$LazySpanLookup$FullSpanItem": {
+ "androidx/widget/StaggeredGridLayoutManager$LazySpanLookup$FullSpanItem": [
+ "CREATOR"
+ ]
+ },
+ "android/support/v17/leanback/R$anim": {
+ "androidx/leanback/R$anim": [
+ "lb_decelerator_4"
+ ]
+ },
+ "android/support/v17/leanback/widget/PagingIndicator": {
+ "androidx/leanback/widget/PagingIndicator": [
+ "DURATION_DIAMETER",
+ "DURATION_TRANSLATION_X",
+ "DECELERATE_INTERPOLATOR",
+ "DOT_DIAMETER",
+ "DURATION_ALPHA",
+ "DOT_TRANSLATION_X",
+ "DOT_ALPHA"
+ ]
+ },
+ "android/support/v7/widget/ScrollingTabContainerView": {
+ "androidx/widget/ScrollingTabContainerView": [
+ "sAlphaInterpolator",
+ "TAG",
+ "FADE_DURATION"
+ ]
+ },
+ "android/support/v4/text/TextDirectionHeuristicsCompat$FirstStrong": {
+ "androidx/text/TextDirectionHeuristicsCompat$FirstStrong": [
+ "INSTANCE"
+ ]
+ },
+ "android/support/design/internal/NavigationMenuPresenter$NavigationMenuTextItem": {
+ "androidx/design/internal/NavigationMenuPresenter$NavigationMenuTextItem": [
+ "needsEmptyIcon"
+ ]
+ },
+ "android/support/v17/leanback/widget/Presenter$ViewHolder": {
+ "androidx/leanback/widget/Presenter$ViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/customtabs/IPostMessageService$Stub": {
+ "androidx/browser/customtabs/IPostMessageService$Stub": [
+ "TRANSACTION_onPostMessage",
+ "DESCRIPTOR",
+ "TRANSACTION_onMessageChannelReady"
+ ]
+ },
+ "android/support/v4/view/ViewPropertyAnimatorCompat": {
+ "androidx/view/ViewPropertyAnimatorCompat": [
+ "LISTENER_TAG_ID",
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/AbstractMediaItemPresenter": {
+ "androidx/leanback/widget/AbstractMediaItemPresenter": [
+ "PLAY_STATE_PLAYING",
+ "PLAY_STATE_PAUSED",
+ "sTempRect",
+ "PLAY_STATE_INITIAL"
+ ]
+ },
+ "android/support/text/emoji/BuildConfig": {
+ "androidx/text/emoji/BuildConfig": [
+ "APPLICATION_ID",
+ "VERSION_NAME",
+ "BUILD_TYPE",
+ "VERSION_CODE",
+ "DEBUG",
+ "FLAVOR"
+ ]
+ },
+ "android/support/v4/media/session/MediaControllerCompat$TransportControls": {
+ "androidx/media/session/MediaControllerCompat$TransportControls": [
+ "EXTRA_LEGACY_STREAM_TYPE"
+ ]
+ },
+ "android/support/v4/view/WindowCompat": {
+ "androidx/view/WindowCompat": [
+ "FEATURE_ACTION_MODE_OVERLAY",
+ "FEATURE_ACTION_BAR",
+ "FEATURE_ACTION_BAR_OVERLAY"
+ ]
+ },
+ "android/support/v4/content/PermissionChecker": {
+ "androidx/content/PermissionChecker": [
+ "PERMISSION_GRANTED",
+ "PERMISSION_DENIED",
+ "PERMISSION_DENIED_APP_OP"
+ ]
+ },
+ "android/support/v4/text/TextUtilsCompat": {
+ "androidx/text/TextUtilsCompat": [
+ "ROOT",
+ "ARAB_SCRIPT_SUBTAG",
+ "HEBR_SCRIPT_SUBTAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/DetailsOverviewRowPresenter": {
+ "androidx/leanback/widget/DetailsOverviewRowPresenter": [
+ "MORE_ACTIONS_FADE_MS",
+ "DEBUG",
+ "TAG",
+ "DEFAULT_TIMEOUT"
+ ]
+ },
+ "android/support/design/widget/TextInputLayout": {
+ "androidx/design/widget/TextInputLayout": [
+ "LOG_TAG",
+ "INVALID_MAX_LENGTH",
+ "ANIMATION_DURATION"
+ ]
+ },
+ "android/support/v7/media/RemotePlaybackClient": {
+ "androidx/media/RemotePlaybackClient": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/ListRowPresenter$ViewHolder": {
+ "androidx/leanback/widget/ListRowPresenter$ViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/v7/content/res/AppCompatColorStateListInflater": {
+ "androidx/content/res/AppCompatColorStateListInflater": [
+ "DEFAULT_COLOR"
+ ]
+ },
+ "android/support/v7/view/menu/ExpandedMenuView": {
+ "androidx/view/menu/ExpandedMenuView": [
+ "TINT_ATTRS"
+ ]
+ },
+ "android/support/v7/widget/PositionMap$ContainerHelpers": {
+ "androidx/widget/PositionMap$ContainerHelpers": [
+ "EMPTY_BOOLEANS",
+ "EMPTY_INTS",
+ "EMPTY_OBJECTS",
+ "EMPTY_LONGS"
+ ]
+ },
+ "android/support/design/widget/TextInputLayout$SavedState": {
+ "androidx/design/widget/TextInputLayout$SavedState": [
+ "error",
+ "isPasswordToggledVisible",
+ "CREATOR"
+ ]
+ },
+ "android/support/v17/leanback/BuildConfig": {
+ "androidx/leanback/BuildConfig": [
+ "DEBUG",
+ "VERSION_CODE",
+ "VERSION_NAME",
+ "BUILD_TYPE",
+ "APPLICATION_ID",
+ "FLAVOR"
+ ]
+ },
+ "android/support/v7/widget/GridLayout$MutableInt": {
+ "androidx/widget/GridLayout$MutableInt": [
+ "value"
+ ]
+ },
+ "android/support/wear/R$dimen": {
+ "androidx/wear/R$dimen": [
+ "ws_action_drawer_item_icon_right_margin",
+ "ws_action_drawer_item_bottom_padding",
+ "ws_wearable_drawer_view_elevation",
+ "circular_progress_layout_stroke_width",
+ "ws_wrv_curve_default_x_offset",
+ "ws_action_drawer_item_top_padding"
+ ]
+ },
+ "android/support/wear/widget/drawer/WearableNavigationDrawerView": {
+ "androidx/wear/widget/drawer/WearableNavigationDrawerView": [
+ "MULTI_PAGE",
+ "SINGLE_PAGE",
+ "AUTO_CLOSE_DRAWER_DELAY_MS",
+ "TAG",
+ "DEFAULT_STYLE"
+ ]
+ },
+ "android/support/v7/graphics/Palette": {
+ "androidx/graphics/palette/Palette": [
+ "DEFAULT_CALCULATE_NUMBER_COLORS",
+ "MIN_CONTRAST_BODY_TEXT",
+ "LOG_TIMINGS",
+ "DEFAULT_FILTER",
+ "LOG_TAG",
+ "MIN_CONTRAST_TITLE_TEXT",
+ "DEFAULT_RESIZE_BITMAP_AREA"
+ ]
+ },
+ "android/support/v7/widget/RecyclerView$State": {
+ "androidx/widget/RecyclerView$State": [
+ "STEP_ANIMATIONS",
+ "STEP_LAYOUT",
+ "STEP_START"
+ ]
+ },
+ "android/support/design/widget/AppBarLayout": {
+ "androidx/design/widget/AppBarLayout": [
+ "PENDING_ACTION_FORCE",
+ "PENDING_ACTION_NONE",
+ "PENDING_ACTION_COLLAPSED",
+ "INVALID_SCROLL_RANGE",
+ "PENDING_ACTION_EXPANDED",
+ "PENDING_ACTION_ANIMATE_ENABLED"
+ ]
+ },
+ "android/support/design/widget/ViewUtilsLollipop": {
+ "androidx/design/widget/ViewUtilsLollipop": [
+ "STATE_LIST_ANIM_ATTRS"
+ ]
+ },
+ "android/support/v4/provider/FontsContractCompat": {
+ "androidx/provider/FontsContractCompat": [
+ "sByteArrayComparator",
+ "sBackgroundThread",
+ "BACKGROUND_THREAD_KEEP_ALIVE_DURATION_MS",
+ "sTypefaceCache",
+ "RESULT_CODE_WRONG_CERTIFICATES",
+ "RESULT_CODE_PROVIDER_NOT_FOUND",
+ "PARCEL_FONT_RESULTS",
+ "sPendingReplies",
+ "TAG",
+ "sLock"
+ ]
+ },
+ "android/support/media/tv/TvContractUtils": {
+ "androidx/media/tv/TvContractUtils": [
+ "DEBUG",
+ "EMPTY",
+ "TAG",
+ "DELIMITER"
+ ]
+ },
+ "android/support/v17/leanback/widget/RoundedRectHelperApi21": {
+ "androidx/leanback/widget/RoundedRectHelperApi21": [
+ "sRoundedRectProvider",
+ "MAX_CACHED_PROVIDER"
+ ]
+ },
+ "android/support/v17/leanback/app/BrowseFragment$MainFragmentAdapterRegistry": {
+ "androidx/leanback/app/BrowseFragment$MainFragmentAdapterRegistry": [
+ "sDefaultFragmentFactory"
+ ]
+ },
+ "android/support/v7/util/BatchingListUpdateCallback": {
+ "androidx/util/BatchingListUpdateCallback": [
+ "TYPE_CHANGE",
+ "TYPE_REMOVE",
+ "TYPE_NONE",
+ "TYPE_ADD"
+ ]
+ },
+ "android/support/v4/widget/DrawerLayout$SavedState": {
+ "androidx/widget/DrawerLayout$SavedState": [
+ "lockModeLeft",
+ "lockModeEnd",
+ "CREATOR",
+ "lockModeStart",
+ "openDrawerGravity",
+ "lockModeRight"
+ ]
+ },
+ "android/support/design/internal/NavigationMenuItemView": {
+ "androidx/design/internal/NavigationMenuItemView": [
+ "CHECKED_STATE_SET",
+ "EMPTY_STATE_SET"
+ ]
+ },
+ "android/support/customtabs/BuildConfig": {
+ "androidx/browser/customtabs/BuildConfig": [
+ "FLAVOR",
+ "VERSION_CODE",
+ "DEBUG",
+ "VERSION_NAME",
+ "BUILD_TYPE",
+ "APPLICATION_ID"
+ ]
+ },
+ "android/support/text/emoji/EmojiProcessor$ProcessorSm": {
+ "androidx/text/emoji/EmojiProcessor$ProcessorSm": [
+ "STATE_DEFAULT",
+ "STATE_WALKING"
+ ]
+ },
+ "android/support/v7/widget/ActivityChooserModel$DefaultSorter": {
+ "androidx/widget/ActivityChooserModel$DefaultSorter": [
+ "WEIGHT_DECAY_COEFFICIENT"
+ ]
+ },
+ "android/support/design/BuildConfig": {
+ "androidx/design/BuildConfig": [
+ "APPLICATION_ID",
+ "FLAVOR",
+ "VERSION_NAME",
+ "BUILD_TYPE",
+ "VERSION_CODE",
+ "DEBUG"
+ ]
+ },
+ "android/support/v4/content/pm/ShortcutManagerCompat": {
+ "androidx/content/pm/ShortcutManagerCompat": [
+ "ACTION_INSTALL_SHORTCUT",
+ "INSTALL_SHORTCUT_PERMISSION"
+ ]
+ },
+ "android/support/media/tv/TvContractCompat$Channels$Logo": {
+ "androidx/media/tv/TvContractCompat$Channels$Logo": [
+ "CONTENT_DIRECTORY"
+ ]
+ },
+ "android/support/v4/view/ViewCompat$ViewCompatBaseImpl": {
+ "androidx/view/ViewCompat$ViewCompatBaseImpl": [
+ "sChildrenDrawingOrderMethod",
+ "sMinHeightField",
+ "sMinHeightFieldFetched",
+ "sTransitionNameMap",
+ "sAccessibilityDelegateCheckFailed",
+ "sMinWidthField",
+ "sMinWidthFieldFetched",
+ "sAccessibilityDelegateField"
+ ]
+ },
+ "android/support/v4/content/res/TypedArrayUtils": {
+ "androidx/content/res/TypedArrayUtils": [
+ "NAMESPACE"
+ ]
+ },
+ "android/support/annotation/RestrictTo$Scope": {
+ "androidx/annotation/RestrictTo$Scope": [
+ "GROUP_ID",
+ "TESTS",
+ "LIBRARY",
+ "SUBCLASSES",
+ "LIBRARY_GROUP"
+ ]
+ },
+ "android/support/media/tv/ChannelLogoUtils": {
+ "androidx/media/tv/ChannelLogoUtils": [
+ "TAG",
+ "CONNECTION_TIMEOUT_MS_FOR_URLCONNECTION",
+ "READ_TIMEOUT_MS_FOR_URLCONNECTION"
+ ]
+ },
+ "android/support/text/emoji/EmojiProcessor": {
+ "androidx/text/emoji/EmojiProcessor": [
+ "ACTION_FLUSH",
+ "ACTION_ADVANCE_BOTH",
+ "ACTION_ADVANCE_END"
+ ]
+ },
+ "android/support/design/R$layout": {
+ "androidx/design/R$layout": [
+ "design_navigation_item",
+ "design_navigation_menu_item",
+ "design_navigation_item_separator",
+ "design_navigation_item_subheader",
+ "design_navigation_item_header",
+ "design_bottom_navigation_item",
+ "design_text_input_password_icon",
+ "design_layout_snackbar_include",
+ "design_layout_tab_text",
+ "design_layout_snackbar",
+ "design_bottom_sheet_dialog",
+ "design_layout_tab_icon",
+ "design_navigation_menu"
+ ]
+ },
+ "android/support/v4/app/NotificationCompatExtras": {
+ "androidx/app/NotificationCompatExtras": [
+ "EXTRA_ACTION_EXTRAS",
+ "EXTRA_GROUP_KEY",
+ "EXTRA_SORT_KEY",
+ "EXTRA_REMOTE_INPUTS",
+ "EXTRA_LOCAL_ONLY",
+ "EXTRA_GROUP_SUMMARY"
+ ]
+ },
+ "android/support/v17/leanback/widget/GridLayoutManager$SavedState": {
+ "androidx/leanback/widget/GridLayoutManager$SavedState": [
+ "CREATOR",
+ "index",
+ "childStates"
+ ]
+ },
+ "android/support/v7/widget/RecyclerView$ItemAnimator": {
+ "androidx/widget/RecyclerView$ItemAnimator": [
+ "FLAG_CHANGED",
+ "FLAG_REMOVED",
+ "FLAG_APPEARED_IN_PRE_LAYOUT",
+ "FLAG_INVALIDATED",
+ "FLAG_MOVED"
+ ]
+ },
+ "android/support/v17/leanback/widget/Grid$Location": {
+ "androidx/leanback/widget/Grid$Location": [
+ "row"
+ ]
+ },
+ "android/support/v17/leanback/media/MediaControllerGlue": {
+ "androidx/leanback/media/MediaControllerGlue": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/v17/preference/LeanbackListPreferenceDialogFragment": {
+ "androidx/leanback/preference/LeanbackListPreferenceDialogFragment": [
+ "SAVE_STATE_ENTRY_VALUES",
+ "SAVE_STATE_TITLE",
+ "SAVE_STATE_INITIAL_SELECTIONS",
+ "SAVE_STATE_IS_MULTI",
+ "SAVE_STATE_ENTRIES",
+ "SAVE_STATE_INITIAL_SELECTION",
+ "SAVE_STATE_MESSAGE"
+ ]
+ },
+ "android/support/v4/app/ServiceCompat": {
+ "androidx/app/ServiceCompat": [
+ "STOP_FOREGROUND_DETACH",
+ "START_STICKY",
+ "STOP_FOREGROUND_REMOVE"
+ ]
+ },
+ "android/support/wear/widget/SwipeDismissLayout": {
+ "androidx/wear/widget/SwipeDismissLayout": [
+ "TAG",
+ "DEFAULT_DISMISS_DRAG_WIDTH_RATIO",
+ "EDGE_SWIPE_THRESHOLD"
+ ]
+ },
+ "android/support/v4/os/LocaleListCompat": {
+ "androidx/os/LocaleListCompat": [
+ "sEmptyLocaleList",
+ "IMPL"
+ ]
+ },
+ "android/support/v7/preference/Preference$BaseSavedState": {
+ "androidx/preference/Preference$BaseSavedState": [
+ "CREATOR",
+ "EMPTY_STATE"
+ ]
+ },
+ "android/support/v7/media/MediaRouteProviderService": {
+ "androidx/media/MediaRouteProviderService": [
+ "TAG",
+ "SERVICE_INTERFACE",
+ "DEBUG",
+ "PRIVATE_MSG_CLIENT_DIED"
+ ]
+ },
+ "android/support/v7/view/menu/CascadingMenuPopup$CascadingMenuInfo": {
+ "androidx/view/menu/CascadingMenuPopup$CascadingMenuInfo": [
+ "position",
+ "menu",
+ "window"
+ ]
+ },
+ "android/support/v7/widget/ToolbarWidgetWrapper": {
+ "androidx/widget/ToolbarWidgetWrapper": [
+ "DEFAULT_FADE_DURATION_MS",
+ "AFFECTS_LOGO_MASK",
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$ViewHolder": {
+ "androidx/leanback/widget/PlaybackTransportRowPresenter$ViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/v7/widget/DefaultItemAnimator": {
+ "androidx/widget/DefaultItemAnimator": [
+ "DEBUG",
+ "sDefaultInterpolator"
+ ]
+ },
+ "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatApi21Impl": {
+ "androidx/widget/PopupWindowCompat$PopupWindowCompatApi21Impl": [
+ "sOverlapAnchorField",
+ "TAG"
+ ]
+ },
+ "android/support/v17/preference/LeanbackSettingsFragment": {
+ "androidx/leanback/preference/LeanbackSettingsFragment": [
+ "PREFERENCE_FRAGMENT_TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/ParallaxTarget$PropertyValuesHolderTarget": {
+ "androidx/leanback/widget/ParallaxTarget$PropertyValuesHolderTarget": [
+ "PSEUDO_DURATION"
+ ]
+ },
+ "android/support/design/widget/SnackbarManager": {
+ "androidx/design/widget/SnackbarManager": [
+ "MSG_TIMEOUT",
+ "sSnackbarManager",
+ "LONG_DURATION_MS",
+ "SHORT_DURATION_MS"
+ ]
+ },
+ "android/support/v17/leanback/app/BaseRowSupportFragment": {
+ "androidx/leanback/app/BaseRowSupportFragment": [
+ "CURRENT_SELECTED_POSITION"
+ ]
+ },
+ "android/support/v7/app/MediaRouteVolumeSlider": {
+ "androidx/app/MediaRouteVolumeSlider": [
+ "TAG"
+ ]
+ },
+ "android/support/v7/util/AsyncListUtil$ViewCallback": {
+ "androidx/util/AsyncListUtil$ViewCallback": [
+ "HINT_SCROLL_DESC",
+ "HINT_SCROLL_NONE",
+ "HINT_SCROLL_ASC"
+ ]
+ },
+ "android/support/multidex/MultiDexExtractor$ExtractedDex": {
+ "androidx/multidex/MultiDexExtractor$ExtractedDex": [
+ "crc"
+ ]
+ },
+ "android/support/transition/AnimatorUtils": {
+ "androidx/transition/AnimatorUtils": [
+ "IMPL"
+ ]
+ },
+ "android/support/v7/app/AppCompatDelegateImplV14": {
+ "androidx/app/AppCompatDelegateImplV14": [
+ "KEY_LOCAL_NIGHT_MODE"
+ ]
+ },
+ "android/support/transition/Styleable$PatternPathMotion": {
+ "androidx/transition/Styleable$PatternPathMotion": [
+ "PATTERN_PATH_DATA"
+ ]
+ },
+ "android/support/v7/media/SystemMediaRouteProvider": {
+ "androidx/media/SystemMediaRouteProvider": [
+ "TAG",
+ "DEFAULT_ROUTE_ID",
+ "PACKAGE_NAME"
+ ]
+ },
+ "android/support/design/internal/BottomNavigationItemView": {
+ "androidx/design/internal/BottomNavigationItemView": [
+ "CHECKED_STATE_SET",
+ "INVALID_ITEM_POSITION"
+ ]
+ },
+ "android/support/wear/widget/ScrollManager": {
+ "androidx/wear/widget/ScrollManager": [
+ "ONE_SEC_IN_MS",
+ "FLING_EDGE_RATIO",
+ "VELOCITY_MULTIPLIER"
+ ]
+ },
+ "android/support/v7/widget/AppCompatTextHelper": {
+ "androidx/widget/AppCompatTextHelper": [
+ "MONOSPACE",
+ "SANS",
+ "SERIF"
+ ]
+ },
+ "android/support/v17/leanback/app/DetailsSupportFragment$WaitEnterTransitionTimeout": {
+ "androidx/leanback/app/DetailsSupportFragment$WaitEnterTransitionTimeout": [
+ "WAIT_ENTERTRANSITION_START"
+ ]
+ },
+ "android/support/v7/media/MediaRouteProviderDescriptor": {
+ "androidx/media/MediaRouteProviderDescriptor": [
+ "KEY_ROUTES"
+ ]
+ },
+ "android/support/v17/leanback/widget/TitleView": {
+ "androidx/leanback/widget/TitleView": [
+ "flags"
+ ]
+ },
+ "android/support/v4/media/session/MediaSessionCompat$QueueItem": {
+ "androidx/media/session/MediaSessionCompat$QueueItem": [
+ "CREATOR",
+ "UNKNOWN_ID"
+ ]
+ },
+ "android/support/v7/mediarouter/R$styleable": {
+ "androidx/mediarouter/R$styleable": [
+ "MediaRouteButton_android_minHeight",
+ "MediaRouteButton_mediaRouteButtonTint",
+ "MediaRouteButton_android_minWidth",
+ "MediaRouteButton_externalRouteEnabledDrawable",
+ "MediaRouteButton"
+ ]
+ },
+ "android/support/v7/view/menu/ActionMenuItemView": {
+ "androidx/view/menu/ActionMenuItemView": [
+ "TAG",
+ "MAX_ICON_SIZE"
+ ]
+ },
+ "android/support/v4/app/FragmentStatePagerAdapter": {
+ "androidx/app/FragmentStatePagerAdapter": [
+ "TAG",
+ "DEBUG"
+ ]
+ },
+ "android/support/wear/widget/drawer/ScrollViewFlingWatcher": {
+ "androidx/wear/widget/drawer/ScrollViewFlingWatcher": [
+ "MAX_WAIT_TIME_MS"
+ ]
+ },
+ "android/support/transition/MatrixUtils": {
+ "androidx/transition/MatrixUtils": [
+ "IDENTITY_MATRIX"
+ ]
+ },
+ "android/support/v4/app/NotificationCompat$Action": {
+ "androidx/app/NotificationCompat$Action": [
+ "icon",
+ "title",
+ "actionIntent"
+ ]
+ },
+ "android/support/v4/os/ResultReceiver": {
+ "androidx/os/ResultReceiver": [
+ "CREATOR"
+ ]
+ },
+ "android/support/v7/widget/AppCompatTextView": {
+ "androidx/widget/AppCompatTextView": [
+ "PLATFORM_SUPPORTS_AUTOSIZE"
+ ]
+ },
+ "android/support/v7/widget/StaggeredGridLayoutManager": {
+ "androidx/widget/StaggeredGridLayoutManager": [
+ "GAP_HANDLING_LAZY",
+ "GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS",
+ "TAG",
+ "VERTICAL",
+ "INVALID_OFFSET",
+ "MAX_SCROLL_FACTOR",
+ "GAP_HANDLING_NONE",
+ "DEBUG",
+ "HORIZONTAL"
+ ]
+ },
+ "android/support/design/widget/BottomNavigationView$SavedState": {
+ "androidx/design/widget/BottomNavigationView$SavedState": [
+ "CREATOR",
+ "menuPresenterState"
+ ]
+ },
+ "android/support/v7/widget/RoundRectDrawableWithShadow": {
+ "androidx/widget/RoundRectDrawableWithShadow": [
+ "sRoundRectHelper",
+ "COS_45",
+ "SHADOW_MULTIPLIER"
+ ]
+ },
+ "android/support/v7/preference/PreferenceCategory": {
+ "androidx/preference/PreferenceCategory": [
+ "TAG"
+ ]
+ },
+ "android/support/v7/widget/RecyclerView$ItemAnimator$ItemHolderInfo": {
+ "androidx/widget/RecyclerView$ItemAnimator$ItemHolderInfo": [
+ "left",
+ "changeFlags",
+ "top",
+ "right",
+ "bottom"
+ ]
+ },
+ "android/support/v7/preference/ListPreference$SavedState": {
+ "androidx/preference/ListPreference$SavedState": [
+ "CREATOR",
+ "value"
+ ]
+ },
+ "android/support/v7/widget/TooltipPopup": {
+ "androidx/widget/TooltipPopup": [
+ "TAG"
+ ]
+ },
+ "android/support/v4/net/ConnectivityManagerCompat": {
+ "androidx/net/ConnectivityManagerCompat": [
+ "RESTRICT_BACKGROUND_STATUS_ENABLED",
+ "RESTRICT_BACKGROUND_STATUS_WHITELISTED",
+ "RESTRICT_BACKGROUND_STATUS_DISABLED"
+ ]
+ },
+ "android/support/v7/widget/MenuPopupWindow": {
+ "androidx/widget/MenuPopupWindow": [
+ "sSetTouchModalMethod",
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/app/RowsFragment": {
+ "androidx/leanback/app/RowsFragment": [
+ "TAG",
+ "ALIGN_TOP_NOT_SET",
+ "DEBUG"
+ ]
+ },
+ "android/support/v17/leanback/app/ProgressBarManager": {
+ "androidx/leanback/app/ProgressBarManager": [
+ "runnable",
+ "rootView",
+ "DEFAULT_PROGRESS_BAR_DELAY"
+ ]
+ },
+ "android/support/v7/media/RegisteredMediaRouteProvider": {
+ "androidx/media/RegisteredMediaRouteProvider": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/design/widget/CheckableImageButton": {
+ "androidx/design/widget/CheckableImageButton": [
+ "DRAWABLE_STATE_CHECKED"
+ ]
+ },
+ "android/support/transition/ImageViewUtils": {
+ "androidx/transition/ImageViewUtils": [
+ "IMPL"
+ ]
+ },
+ "android/support/v17/leanback/widget/PlaybackControlsRow$HighQualityAction": {
+ "androidx/leanback/widget/PlaybackControlsRow$HighQualityAction": [
+ "INDEX_OFF",
+ "INDEX_ON",
+ "OFF",
+ "ON"
+ ]
+ },
+ "android/support/wear/widget/drawer/PageIndicatorView": {
+ "androidx/wear/widget/drawer/PageIndicatorView": [
+ "TAG"
+ ]
+ },
+ "android/support/transition/TransitionValues": {
+ "androidx/transition/TransitionValues": [
+ "view",
+ "values"
+ ]
+ },
+ "android/support/v17/leanback/app/BaseRowFragment": {
+ "androidx/leanback/app/BaseRowFragment": [
+ "CURRENT_SELECTED_POSITION"
+ ]
+ },
+ "android/support/v7/mediarouter/R$drawable": {
+ "androidx/mediarouter/R$drawable": [
+ "mr_group_collapse",
+ "mr_group_expand"
+ ]
+ },
+ "android/support/transition/ViewUtils": {
+ "androidx/transition/ViewUtils": [
+ "sViewFlagsField",
+ "TRANSITION_ALPHA",
+ "IMPL",
+ "sViewFlagsFieldFetched",
+ "TAG",
+ "CLIP_BOUNDS",
+ "VISIBILITY_MASK"
+ ]
+ },
+ "android/support/v7/preference/AndroidResources": {
+ "androidx/preference/AndroidResources": [
+ "ANDROID_R_ICON_FRAME",
+ "ANDROID_R_SWITCH_WIDGET",
+ "ANDROID_R_PREFERENCE_FRAGMENT_STYLE",
+ "ANDROID_R_LIST_CONTAINER",
+ "ANDROID_R_EDITTEXT_PREFERENCE_STYLE"
+ ]
+ },
+ "android/support/v4/net/DatagramSocketWrapper$DatagramSocketImplWrapper": {
+ "androidx/net/DatagramSocketWrapper$DatagramSocketImplWrapper": [
+ "localport",
+ "fd"
+ ]
+ },
+ "android/support/v17/leanback/widget/PlaybackControlsRowPresenter$BoundData": {
+ "androidx/leanback/widget/PlaybackControlsRowPresenter$BoundData": [
+ "secondaryActionsAdapter",
+ "presenter",
+ "adapter"
+ ]
+ },
+ "android/support/v17/leanback/widget/PlaybackControlsRowPresenter$ViewHolder": {
+ "androidx/leanback/widget/PlaybackControlsRowPresenter$ViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/v17/leanback/widget/Parallax$FloatProperty": {
+ "androidx/leanback/widget/Parallax$FloatProperty": [
+ "UNKNOWN_AFTER",
+ "UNKNOWN_BEFORE"
+ ]
+ },
+ "android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter$ViewHolder": {
+ "androidx/leanback/widget/AbstractDetailsDescriptionPresenter$ViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/design/R$string": {
+ "androidx/design/R$string": [
+ "character_counter_pattern"
+ ]
+ },
+ "android/support/wear/ambient/AmbientDelegate": {
+ "androidx/wear/ambient/AmbientDelegate": [
+ "TAG",
+ "sInitAutoResumeEnabledMethod",
+ "sHasAutoResumeEnabledMethod"
+ ]
+ },
+ "android/support/v17/leanback/app/PlaybackFragment": {
+ "androidx/leanback/app/PlaybackFragment": [
+ "ANIMATION_MULTIPLIER",
+ "BG_DARK",
+ "BG_NONE",
+ "DEBUG",
+ "BUNDLE_CONTROL_VISIBLE_ON_CREATEVIEW",
+ "BG_LIGHT",
+ "TAG",
+ "ANIMATING",
+ "IDLE",
+ "START_FADE_OUT"
+ ]
+ },
+ "android/support/v7/widget/ActionBarOverlayLayout$LayoutParams": {
+ "androidx/widget/ActionBarOverlayLayout$LayoutParams": [
+ "topMargin",
+ "rightMargin",
+ "bottomMargin",
+ "leftMargin"
+ ]
+ },
+ "android/support/v4/os/EnvironmentCompat": {
+ "androidx/os/EnvironmentCompat": [
+ "MEDIA_UNKNOWN",
+ "TAG"
+ ]
+ },
+ "android/support/compat/R$string": {
+ "androidx/compat/R$string": [
+ "status_bar_notification_info_overflow"
+ ]
+ },
+ "android/support/v7/widget/PositionMap": {
+ "androidx/widget/PositionMap": [
+ "DELETED"
+ ]
+ },
+ "android/support/media/tv/Program": {
+ "androidx/media/tv/Program": [
+ "INVALID_LONG_VALUE",
+ "PROJECTION",
+ "IS_RECORDING_PROHIBITED"
+ ]
+ },
+ "android/support/v7/widget/ActionBarContextView": {
+ "androidx/widget/ActionBarContextView": [
+ "TAG"
+ ]
+ },
+ "android/support/v4/media/VolumeProviderCompat": {
+ "androidx/media/VolumeProviderCompat": [
+ "VOLUME_CONTROL_RELATIVE",
+ "VOLUME_CONTROL_FIXED",
+ "VOLUME_CONTROL_ABSOLUTE"
+ ]
+ },
+ "android/support/v7/view/menu/CascadingMenuPopup": {
+ "androidx/view/menu/CascadingMenuPopup": [
+ "SUBMENU_TIMEOUT_MS",
+ "HORIZ_POSITION_LEFT",
+ "HORIZ_POSITION_RIGHT"
+ ]
+ },
+ "android/support/v4/app/NotificationManagerCompat$ServiceConnectedEvent": {
+ "androidx/app/NotificationManagerCompat$ServiceConnectedEvent": [
+ "componentName",
+ "iBinder"
+ ]
+ },
+ "android/support/v7/app/AlertDialog": {
+ "androidx/app/AlertDialog": [
+ "LAYOUT_HINT_NONE",
+ "LAYOUT_HINT_SIDE"
+ ]
+ },
+ "android/support/v17/leanback/widget/picker/PickerUtility$DateConstant": {
+ "androidx/leanback/widget/picker/PickerUtility$DateConstant": [
+ "months",
+ "days",
+ "locale"
+ ]
+ },
+ "android/support/v7/app/MediaRouteChooserDialogFragment": {
+ "androidx/app/MediaRouteChooserDialogFragment": [
+ "ARGUMENT_SELECTOR"
+ ]
+ },
+ "android/support/design/widget/CoordinatorLayout$SavedState": {
+ "androidx/design/widget/CoordinatorLayout$SavedState": [
+ "behaviorStates",
+ "CREATOR"
+ ]
+ },
+ "android/support/v7/media/MediaRouteDiscoveryRequest": {
+ "androidx/media/MediaRouteDiscoveryRequest": [
+ "KEY_ACTIVE_SCAN",
+ "KEY_SELECTOR"
+ ]
+ },
+ "android/support/v17/leanback/widget/StaticShadowHelper": {
+ "androidx/leanback/widget/StaticShadowHelper": [
+ "sInstance"
+ ]
+ },
+ "android/support/design/widget/ShadowDrawableWrapper": {
+ "androidx/design/widget/ShadowDrawableWrapper": [
+ "SHADOW_MULTIPLIER",
+ "SHADOW_TOP_SCALE",
+ "COS_45",
+ "SHADOW_HORIZ_SCALE",
+ "SHADOW_BOTTOM_SCALE"
+ ]
+ },
+ "android/support/v13/app/FragmentCompat": {
+ "androidx/app/FragmentCompat": [
+ "sDelegate",
+ "IMPL"
+ ]
+ },
+ "android/support/v7/widget/GridLayout$Arc": {
+ "androidx/widget/GridLayout$Arc": [
+ "span",
+ "valid",
+ "value"
+ ]
+ },
+ "android/support/v4/content/AsyncTaskLoader": {
+ "androidx/content/AsyncTaskLoader": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/v7/gridlayout/BuildConfig": {
+ "androidx/gridlayout/BuildConfig": [
+ "DEBUG",
+ "VERSION_CODE",
+ "BUILD_TYPE",
+ "VERSION_NAME",
+ "FLAVOR",
+ "APPLICATION_ID"
+ ]
+ },
+ "android/support/text/emoji/flatbuffer/MetadataList": {
+ "androidx/text/emoji/flatbuffer/MetadataList": [
+ "bb_pos",
+ "bb"
+ ]
+ },
+ "android/support/text/emoji/widget/EditTextAttributeHelper": {
+ "androidx/text/emoji/widget/EditTextAttributeHelper": [
+ "MAX_EMOJI_COUNT"
+ ]
+ },
+ "android/support/v7/widget/ChildHelper$Bucket": {
+ "androidx/widget/ChildHelper$Bucket": [
+ "LAST_BIT",
+ "BITS_PER_WORD"
+ ]
+ },
+ "android/support/v4/content/LocalBroadcastManager": {
+ "androidx/content/LocalBroadcastManager": [
+ "DEBUG",
+ "MSG_EXEC_PENDING_BROADCASTS",
+ "TAG"
+ ]
+ },
+ "android/support/v7/widget/TooltipCompat": {
+ "androidx/widget/TooltipCompat": [
+ "IMPL"
+ ]
+ },
+ "android/support/media/tv/PreviewProgram": {
+ "androidx/media/tv/PreviewProgram": [
+ "INVALID_INT_VALUE",
+ "PROJECTION",
+ "INVALID_LONG_VALUE"
+ ]
+ },
+ "android/support/v7/preference/ListPreferenceDialogFragmentCompat": {
+ "androidx/preference/ListPreferenceDialogFragmentCompat": [
+ "SAVE_STATE_INDEX",
+ "SAVE_STATE_ENTRIES",
+ "SAVE_STATE_ENTRY_VALUES"
+ ]
+ },
+ "android/support/v7/widget/ViewInfoStore": {
+ "androidx/widget/ViewInfoStore": [
+ "DEBUG"
+ ]
+ },
+ "android/support/v7/widget/ActivityChooserModel$ActivityResolveInfo": {
+ "androidx/widget/ActivityChooserModel$ActivityResolveInfo": [
+ "weight",
+ "resolveInfo"
+ ]
+ },
+ "android/support/v7/preference/SeekBarPreference": {
+ "androidx/preference/SeekBarPreference": [
+ "TAG"
+ ]
+ },
+ "android/support/v7/widget/ActivityChooserView$InnerLayout": {
+ "androidx/widget/ActivityChooserView$InnerLayout": [
+ "TINT_ATTRS"
+ ]
+ },
+ "android/support/v7/app/AppCompatDelegateImplV9": {
+ "androidx/app/AppCompatDelegateImplV9": [
+ "IS_PRE_LOLLIPOP"
+ ]
+ },
+ "android/support/v7/media/SystemMediaRouteProvider$LegacyImpl": {
+ "androidx/media/SystemMediaRouteProvider$LegacyImpl": [
+ "PLAYBACK_STREAM",
+ "CONTROL_FILTERS"
+ ]
+ },
+ "android/support/transition/ViewUtilsApi22": {
+ "androidx/transition/ViewUtilsApi22": [
+ "sSetLeftTopRightBottomMethod",
+ "TAG",
+ "sSetLeftTopRightBottomMethodFetched"
+ ]
+ },
+ "android/support/v17/leanback/widget/ObjectAdapter": {
+ "androidx/leanback/widget/ObjectAdapter": [
+ "NO_ID"
+ ]
+ },
+ "android/support/content/Query": {
+ "androidx/content/Query": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/media/MediaControllerAdapter": {
+ "androidx/leanback/media/MediaControllerAdapter": [
+ "TAG",
+ "DEBUG"
+ ]
+ },
+ "android/support/v7/recyclerview/R$id": {
+ "androidx/recyclerview/R$id": [
+ "item_touch_helper_previous_elevation"
+ ]
+ },
+ "android/support/v4/media/session/MediaSessionCompat$Callback$CallbackHandler": {
+ "androidx/media/session/MediaSessionCompat$Callback$CallbackHandler": [
+ "MSG_MEDIA_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT"
+ ]
+ },
+ "android/support/design/widget/FloatingActionButton": {
+ "androidx/design/widget/FloatingActionButton": [
+ "LOG_TAG",
+ "AUTO_MINI_LARGEST_SCREEN_WIDTH",
+ "SIZE_AUTO",
+ "SIZE_NORMAL",
+ "SIZE_MINI"
+ ]
+ },
+ "android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper": {
+ "androidx/leanback/widget/DetailsOverviewSharedElementHelper": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/v7/app/AlertDialog$Builder": {
+ "androidx/app/AlertDialog$Builder": [
+ "P"
+ ]
+ },
+ "android/support/wear/internal/widget/drawer/SinglePagePresenter": {
+ "androidx/wear/internal/widget/drawer/SinglePagePresenter": [
+ "DRAWER_CLOSE_DELAY_MS"
+ ]
+ },
+ "android/support/v17/leanback/app/BrowseSupportFragment$SetSelectionRunnable": {
+ "androidx/leanback/app/BrowseSupportFragment$SetSelectionRunnable": [
+ "TYPE_INTERNAL_SYNC",
+ "TYPE_USER_REQUEST",
+ "TYPE_INVALID"
+ ]
+ },
+ "android/support/v7/preference/R$id": {
+ "androidx/preference/R$id": [
+ "switchWidget",
+ "seekbar",
+ "seekbar_value",
+ "icon_frame",
+ "spinner"
+ ]
+ },
+ "android/support/media/tv/BasePreviewProgram$Builder": {
+ "androidx/media/tv/BasePreviewProgram$Builder": [
+ "sFormat"
+ ]
+ },
+ "android/support/v4/widget/SlidingPaneLayout": {
+ "androidx/widget/SlidingPaneLayout": [
+ "DEFAULT_OVERHANG_SIZE",
+ "IMPL",
+ "DEFAULT_FADE_COLOR",
+ "TAG",
+ "MIN_FLING_VELOCITY"
+ ]
+ },
+ "android/support/v7/app/MediaRouteChooserDialog": {
+ "androidx/app/MediaRouteChooserDialog": [
+ "UPDATE_ROUTES_DELAY_MS",
+ "TAG",
+ "MSG_UPDATE_ROUTES"
+ ]
+ },
+ "android/support/v4/app/ShareCompat$IntentReader": {
+ "androidx/app/ShareCompat$IntentReader": [
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/ItemBridgeAdapter$ViewHolder": {
+ "androidx/leanback/widget/ItemBridgeAdapter$ViewHolder": [
+ "itemView"
+ ]
+ },
+ "android/support/v17/leanback/app/BrandedFragment": {
+ "androidx/leanback/app/BrandedFragment": [
+ "TITLE_SHOW"
+ ]
+ },
+ "android/support/v17/leanback/widget/SearchEditText": {
+ "androidx/leanback/widget/SearchEditText": [
+ "DEBUG",
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/PersistentFocusWrapper$SavedState": {
+ "androidx/leanback/widget/PersistentFocusWrapper$SavedState": [
+ "CREATOR"
+ ]
+ },
+ "android/support/percent/PercentFrameLayout$LayoutParams": {
+ "androidx/PercentFrameLayout$LayoutParams": [
+ "gravity"
+ ]
+ },
+ "android/support/text/emoji/widget/EmojiEditableFactory": {
+ "androidx/text/emoji/widget/EmojiEditableFactory": [
+ "sWatcherClass",
+ "sInstanceLock",
+ "sInstance"
+ ]
+ },
+ "android/support/v4/view/ViewPager$SavedState": {
+ "androidx/view/ViewPager$SavedState": [
+ "position",
+ "adapterState",
+ "CREATOR",
+ "loader"
+ ]
+ },
+ "android/support/v17/leanback/widget/RowPresenter": {
+ "androidx/leanback/widget/RowPresenter": [
+ "SYNC_ACTIVATED_TO_SELECTED",
+ "SYNC_ACTIVATED_TO_EXPANDED_AND_SELECTED",
+ "SYNC_ACTIVATED_CUSTOM",
+ "SYNC_ACTIVATED_TO_EXPANDED"
+ ]
+ },
+ "android/support/v7/preference/EditTextPreferenceDialogFragmentCompat": {
+ "androidx/preference/EditTextPreferenceDialogFragmentCompat": [
+ "SAVE_STATE_TEXT"
+ ]
+ },
+ "android/support/v17/leanback/graphics/ColorFilterCache": {
+ "androidx/leanback/graphics/ColorFilterCache": [
+ "sColorToFiltersMap"
+ ]
+ },
+ "android/support/v7/view/menu/ListMenuPresenter": {
+ "androidx/view/menu/ListMenuPresenter": [
+ "VIEWS_TAG",
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/VerticalGridPresenter$ViewHolder": {
+ "androidx/leanback/widget/VerticalGridPresenter$ViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/v4/app/TaskStackBuilder": {
+ "androidx/app/TaskStackBuilder": [
+ "TAG",
+ "IMPL"
+ ]
+ },
+ "android/support/v7/content/res/AppCompatResources": {
+ "androidx/content/res/AppCompatResources": [
+ "LOG_TAG",
+ "sColorStateCaches",
+ "TL_TYPED_VALUE",
+ "sColorStateCacheLock"
+ ]
+ },
+ "android/support/v7/recyclerview/BuildConfig": {
+ "androidx/recyclerview/BuildConfig": [
+ "DEBUG",
+ "FLAVOR",
+ "VERSION_CODE",
+ "BUILD_TYPE",
+ "VERSION_NAME",
+ "APPLICATION_ID"
+ ]
+ },
+ "android/support/v4/hardware/display/DisplayManagerCompat": {
+ "androidx/hardware/display/DisplayManagerCompat": [
+ "DISPLAY_CATEGORY_PRESENTATION",
+ "sInstances"
+ ]
+ },
+ "android/support/v7/widget/ActionMenuPresenter": {
+ "androidx/widget/ActionMenuPresenter": [
+ "TAG"
+ ]
+ },
+ "android/support/v4/app/NotificationManagerCompat$NotifyTask": {
+ "androidx/app/NotificationManagerCompat$NotifyTask": [
+ "notif",
+ "id",
+ "tag",
+ "packageName"
+ ]
+ },
+ "android/support/text/emoji/FontRequestEmojiCompatConfig": {
+ "androidx/text/emoji/FontRequestEmojiCompatConfig": [
+ "DEFAULT_FONTS_CONTRACT"
+ ]
+ },
+ "android/support/v17/leanback/widget/ShadowHelperApi21": {
+ "androidx/leanback/widget/ShadowHelperApi21": [
+ "sOutlineProvider"
+ ]
+ },
+ "android/support/v17/leanback/widget/ItemBridgeAdapter": {
+ "androidx/leanback/widget/ItemBridgeAdapter": [
+ "TAG",
+ "DEBUG"
+ ]
+ },
+ "android/support/wear/utils/MetadataConstants": {
+ "androidx/wear/utils/MetadataConstants": [
+ "STANDALONE_METADATA_NAME",
+ "WATCH_FACE_PREVIEW_CIRCULAR_METADATA_NAME",
+ "NOTIFICATION_BRIDGE_MODE_NO_BRIDGING",
+ "NOTIFICATION_BRIDGE_MODE_BRIDGING",
+ "WATCH_FACE_PREVIEW_METADATA_NAME",
+ "NOTIFICATION_BRIDGE_MODE_METADATA_NAME"
+ ]
+ },
+ "android/support/transition/GhostViewUtils": {
+ "androidx/transition/GhostViewUtils": [
+ "CREATOR"
+ ]
+ },
+ "android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter$ViewHolder": {
+ "androidx/leanback/widget/AbstractMediaListHeaderPresenter$ViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/v17/leanback/widget/PlaybackControlsRowPresenter": {
+ "androidx/leanback/widget/PlaybackControlsRowPresenter": [
+ "sShadowZ"
+ ]
+ },
+ "android/support/v7/widget/CardView": {
+ "androidx/widget/CardView": [
+ "COLOR_BACKGROUND_ATTR",
+ "IMPL"
+ ]
+ },
+ "android/support/v7/app/ActionBar$Tab": {
+ "androidx/app/ActionBar$Tab": [
+ "INVALID_POSITION"
+ ]
+ },
+ "android/support/v7/app/MediaRouterThemeHelper": {
+ "androidx/app/MediaRouterThemeHelper": [
+ "MIN_CONTRAST",
+ "COLOR_WHITE_ON_DARK_BACKGROUND",
+ "COLOR_DARK_ON_LIGHT_BACKGROUND"
+ ]
+ },
+ "android/support/transition/ChangeClipBounds": {
+ "androidx/transition/ChangeClipBounds": [
+ "PROPNAME_CLIP",
+ "PROPNAME_BOUNDS",
+ "sTransitionProperties"
+ ]
+ },
+ "android/support/transition/Styleable$Slide": {
+ "androidx/transition/Styleable$Slide": [
+ "SLIDE_EDGE"
+ ]
+ },
+ "android/support/transition/TransitionSet": {
+ "androidx/transition/TransitionSet": [
+ "ORDERING_TOGETHER",
+ "ORDERING_SEQUENTIAL"
+ ]
+ },
+ "android/support/v7/widget/SearchView$SavedState": {
+ "androidx/widget/SearchView$SavedState": [
+ "CREATOR",
+ "isIconified"
+ ]
+ },
+ "android/support/v17/leanback/widget/PlaybackControlsPresenter$BoundData": {
+ "androidx/leanback/widget/PlaybackControlsPresenter$BoundData": [
+ "secondaryActionsAdapter"
+ ]
+ },
+ "android/support/v4/content/LocalBroadcastManager$BroadcastRecord": {
+ "androidx/content/LocalBroadcastManager$BroadcastRecord": [
+ "intent",
+ "receivers"
+ ]
+ },
+ "android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat": {
+ "androidx/preference/MultiSelectListPreferenceDialogFragmentCompat": [
+ "SAVE_STATE_ENTRIES",
+ "SAVE_STATE_CHANGED",
+ "SAVE_STATE_ENTRY_VALUES",
+ "SAVE_STATE_VALUES"
+ ]
+ },
+ "android/support/transition/ViewGroupUtils": {
+ "androidx/transition/ViewGroupUtils": [
+ "IMPL"
+ ]
+ },
+ "android/support/v17/leanback/widget/ControlBarPresenter$ViewHolder": {
+ "androidx/leanback/widget/ControlBarPresenter$ViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/v7/mediarouter/BuildConfig": {
+ "androidx/mediarouter/BuildConfig": [
+ "DEBUG",
+ "VERSION_CODE",
+ "FLAVOR",
+ "BUILD_TYPE",
+ "APPLICATION_ID",
+ "VERSION_NAME"
+ ]
+ },
+ "android/support/v17/leanback/R$transition": {
+ "androidx/leanback/R$transition": [
+ "lb_title_in",
+ "lb_browse_headers_out",
+ "lb_title_out",
+ "lb_browse_entrance_transition",
+ "lb_details_enter_transition",
+ "lb_vertical_grid_entrance_transition",
+ "lb_browse_headers_in"
+ ]
+ },
+ "android/support/design/R$drawable": {
+ "androidx/design/R$drawable": [
+ "navigation_empty_icon",
+ "design_bottom_navigation_item_background"
+ ]
+ },
+ "android/support/wear/widget/drawer/NestedScrollViewFlingWatcher": {
+ "androidx/wear/widget/drawer/NestedScrollViewFlingWatcher": [
+ "MAX_WAIT_TIME_MS"
+ ]
+ },
+ "android/support/v17/leanback/app/HeadersSupportFragment": {
+ "androidx/leanback/app/HeadersSupportFragment": [
+ "sHeaderPresenter",
+ "sLayoutChangeListener"
+ ]
+ },
+ "android/support/v17/leanback/widget/ShadowHelper": {
+ "androidx/leanback/widget/ShadowHelper": [
+ "sInstance"
+ ]
+ },
+ "android/support/percent/PercentLayoutHelper": {
+ "androidx/PercentLayoutHelper": [
+ "TAG",
+ "VERBOSE",
+ "DEBUG"
+ ]
+ },
+ "android/support/design/internal/BottomNavigationMenu": {
+ "androidx/design/internal/BottomNavigationMenu": [
+ "MAX_ITEM_COUNT"
+ ]
+ },
+ "android/support/design/internal/TextScale": {
+ "androidx/design/internal/TextScale": [
+ "PROPNAME_SCALE"
+ ]
+ },
+ "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$BoundData": {
+ "androidx/leanback/widget/PlaybackTransportRowPresenter$BoundData": [
+ "adapter",
+ "presenter"
+ ]
+ },
+ "android/support/v13/view/inputmethod/EditorInfoCompat$EditorInfoCompatBaseImpl": {
+ "androidx/view/inputmethod/EditorInfoCompat$EditorInfoCompatBaseImpl": [
+ "CONTENT_MIME_TYPES_KEY"
+ ]
+ },
+ "android/support/v17/leanback/widget/ViewsStateBundle": {
+ "androidx/leanback/widget/ViewsStateBundle": [
+ "UNLIMITED",
+ "LIMIT_DEFAULT"
+ ]
+ },
+ "android/support/v4/content/ContextCompat": {
+ "androidx/content/ContextCompat": [
+ "sLock",
+ "TAG",
+ "sTempValue"
+ ]
+ },
+ "android/support/v4/util/SparseArrayCompat": {
+ "androidx/util/SparseArrayCompat": [
+ "DELETED"
+ ]
+ },
+ "android/support/transition/Styleable$VisibilityTransition": {
+ "androidx/transition/Styleable$VisibilityTransition": [
+ "TRANSITION_VISIBILITY_MODE"
+ ]
+ },
+ "android/support/v14/preference/MultiSelectListPreference$SavedState": {
+ "androidx/preference/MultiSelectListPreference$SavedState": [
+ "CREATOR",
+ "values"
+ ]
+ },
+ "android/support/v17/leanback/app/DetailsFragment$WaitEnterTransitionTimeout": {
+ "androidx/leanback/app/DetailsFragment$WaitEnterTransitionTimeout": [
+ "WAIT_ENTERTRANSITION_START"
+ ]
+ },
+ "android/support/text/emoji/MetadataListReader$OpenTypeReader": {
+ "androidx/text/emoji/MetadataListReader$OpenTypeReader": [
+ "UINT16_BYTE_COUNT",
+ "UINT32_BYTE_COUNT"
+ ]
+ },
+ "android/support/v7/preference/TwoStatePreference$SavedState": {
+ "androidx/preference/TwoStatePreference$SavedState": [
+ "checked",
+ "CREATOR"
+ ]
+ },
+ "android/support/v17/leanback/widget/Action": {
+ "androidx/leanback/widget/Action": [
+ "NO_ID"
+ ]
+ },
+ "android/support/v7/widget/Toolbar": {
+ "androidx/widget/Toolbar": [
+ "TAG"
+ ]
+ },
+ "android/support/v17/preference/LeanbackPreferenceDialogFragment": {
+ "androidx/leanback/preference/LeanbackPreferenceDialogFragment": [
+ "ARG_KEY"
+ ]
+ },
+ "android/support/v4/content/SharedPreferencesCompat$EditorCompat": {
+ "androidx/content/SharedPreferencesCompat$EditorCompat": [
+ "sInstance"
+ ]
+ },
+ "android/support/v17/leanback/widget/RowPresenter$ContainerViewHolder": {
+ "androidx/leanback/widget/RowPresenter$ContainerViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/v7/app/MediaRouteChooserDialog$RouteComparator": {
+ "androidx/app/MediaRouteChooserDialog$RouteComparator": [
+ "sInstance"
+ ]
+ },
+ "android/support/v4/widget/PopupWindowCompat": {
+ "androidx/widget/PopupWindowCompat": [
+ "IMPL"
+ ]
+ },
+ "android/support/v4/widget/ImageViewCompat": {
+ "androidx/widget/ImageViewCompat": [
+ "IMPL"
+ ]
+ },
+ "android/support/v17/leanback/widget/GuidedActionsStylist$ViewHolder": {
+ "androidx/leanback/widget/GuidedActionsStylist$ViewHolder": [
+ "itemView"
+ ]
+ },
+ "android/support/v4/view/ActionProvider": {
+ "androidx/view/ActionProvider": [
+ "TAG"
+ ]
+ },
+ "android/support/v4/view/ViewConfigurationCompat": {
+ "androidx/view/ViewConfigurationCompat": [
+ "TAG",
+ "sGetScaledScrollFactorMethod"
+ ]
+ },
+ "android/support/customtabs/CustomTabsSession": {
+ "androidx/browser/customtabs/CustomTabsSession": [
+ "TAG"
+ ]
+ },
+ "android/support/v7/mediarouter/R$style": {
+ "androidx/mediarouter/R$style": [
+ "Theme_MediaRouter_LightControlPanel",
+ "Theme_MediaRouter_Light",
+ "Theme_MediaRouter_Light_DarkControlPanel",
+ "Theme_MediaRouter"
+ ]
+ },
+ "android/support/text/emoji/EmojiProcessor$CodepointIndexFinder": {
+ "androidx/text/emoji/EmojiProcessor$CodepointIndexFinder": [
+ "INVALID_INDEX"
+ ]
+ },
+ "android/support/v17/leanback/widget/NonOverlappingLinearLayoutWithForeground": {
+ "androidx/leanback/widget/NonOverlappingLinearLayoutWithForeground": [
+ "VERSION_M"
+ ]
+ },
+ "android/support/v4/view/ViewCompat$ViewCompatApi21Impl": {
+ "androidx/view/ViewCompat$ViewCompatApi21Impl": [
+ "sThreadLocalRect"
+ ]
+ },
+ "android/support/v4/app/NotificationCompat$DecoratedCustomViewStyle": {
+ "androidx/app/NotificationCompat$DecoratedCustomViewStyle": [
+ "MAX_ACTION_BUTTONS"
+ ]
+ },
+ "android/support/v7/widget/PagerSnapHelper": {
+ "androidx/widget/PagerSnapHelper": [
+ "MAX_SCROLL_ON_FLING_DURATION"
+ ]
+ },
+ "android/support/wear/widget/CircledImageView": {
+ "androidx/wear/widget/CircledImageView": [
+ "SQUARE_DIMEN_WIDTH",
+ "SQUARE_DIMEN_NONE",
+ "SQUARE_DIMEN_HEIGHT",
+ "ARGB_EVALUATOR"
+ ]
+ },
+ "android/support/v7/widget/RtlSpacingHelper": {
+ "androidx/widget/RtlSpacingHelper": [
+ "UNDEFINED"
+ ]
+ },
+ "android/support/v4/media/MediaBrowserServiceCompatApi26": {
+ "androidx/media/MediaBrowserServiceCompatApi26": [
+ "sResultFlags",
+ "TAG"
+ ]
+ },
+ "android/support/text/emoji/EmojiMetadata": {
+ "androidx/text/emoji/EmojiMetadata": [
+ "HAS_GLYPH_EXISTS",
+ "HAS_GLYPH_ABSENT",
+ "HAS_GLYPH_UNKNOWN",
+ "sMetadataItem"
+ ]
+ },
+ "android/support/mediacompat/R$integer": {
+ "androidx/mediacompat/R$integer": [
+ "cancel_button_image_alpha"
+ ]
+ },
+ "android/support/v7/content/res/AppCompatResources$ColorStateListCacheEntry": {
+ "androidx/content/res/AppCompatResources$ColorStateListCacheEntry": [
+ "value",
+ "configuration"
+ ]
+ },
+ "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$ViewHolder": {
+ "androidx/leanback/widget/DetailsOverviewRowPresenter$ViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/wear/R$color": {
+ "androidx/wear/R$color": [
+ "circular_progress_layout_background_color"
+ ]
+ },
+ "android/support/v17/leanback/widget/ItemAlignmentFacet": {
+ "androidx/leanback/widget/ItemAlignmentFacet": [
+ "ITEM_ALIGN_OFFSET_PERCENT_DISABLED"
+ ]
+ },
+ "android/support/wear/ambient/AmbientMode$AmbientController": {
+ "androidx/wear/ambient/AmbientMode$AmbientController": [
+ "TAG"
+ ]
+ },
+ "android/support/v13/view/inputmethod/InputConnectionCompat": {
+ "androidx/view/inputmethod/InputConnectionCompat": [
+ "INPUT_CONTENT_GRANT_READ_URI_PERMISSION",
+ "IMPL"
+ ]
+ },
+ "android/support/wear/widget/BezierSCurveInterpolator": {
+ "androidx/wear/widget/BezierSCurveInterpolator": [
+ "STEP_SIZE",
+ "VALUES",
+ "INSTANCE"
+ ]
+ },
+ "android/support/v4/graphics/PathParser": {
+ "androidx/graphics/PathParser": [
+ "LOGTAG"
+ ]
+ },
+ "android/support/v7/widget/RecyclerView$RecycledViewPool": {
+ "androidx/widget/RecyclerView$RecycledViewPool": [
+ "DEFAULT_MAX_SCRAP"
+ ]
+ },
+ "android/support/v7/media/MediaRouteSelector": {
+ "androidx/media/MediaRouteSelector": [
+ "KEY_CONTROL_CATEGORIES",
+ "EMPTY"
+ ]
+ },
+ "android/support/transition/PropertyValuesHolderUtils": {
+ "androidx/transition/PropertyValuesHolderUtils": [
+ "IMPL"
+ ]
+ },
+ "android/support/graphics/drawable/VectorDrawableCompat$VFullPath": {
+ "androidx/graphics/drawable/VectorDrawableCompat$VFullPath": [
+ "FILL_TYPE_WINDING"
+ ]
+ },
+ "android/support/mediacompat/R$color": {
+ "androidx/mediacompat/R$color": [
+ "notification_material_background_media_default_color"
+ ]
+ },
+ "android/support/v17/leanback/widget/RowHeaderPresenter$ViewHolder": {
+ "androidx/leanback/widget/RowHeaderPresenter$ViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/design/widget/CollapsingToolbarLayout": {
+ "androidx/design/widget/CollapsingToolbarLayout": [
+ "DEFAULT_SCRIM_ANIMATION_DURATION"
+ ]
+ },
+ "android/support/v17/leanback/app/BrandedSupportFragment": {
+ "androidx/leanback/app/BrandedSupportFragment": [
+ "TITLE_SHOW"
+ ]
+ },
+ "android/support/design/internal/BottomNavigationPresenter$SavedState": {
+ "androidx/design/internal/BottomNavigationPresenter$SavedState": [
+ "CREATOR",
+ "selectedItemId"
+ ]
+ },
+ "android/support/v4/app/BackStackState": {
+ "androidx/app/BackStackState": [
+ "CREATOR"
+ ]
+ },
+ "android/support/v4/provider/FontsContractCompat$FontFamilyResult": {
+ "androidx/provider/FontsContractCompat$FontFamilyResult": [
+ "STATUS_WRONG_CERTIFICATES",
+ "STATUS_OK",
+ "STATUS_UNEXPECTED_DATA_PROVIDED"
+ ]
+ },
+ "android/support/v4/app/FragmentManagerState": {
+ "androidx/app/FragmentManagerState": [
+ "CREATOR"
+ ]
+ },
+ "android/support/media/ExifInterface$Rational": {
+ "androidx/media/ExifInterface$Rational": [
+ "denominator",
+ "numerator"
+ ]
+ },
+ "android/support/text/emoji/TypefaceEmojiSpan": {
+ "androidx/text/emoji/TypefaceEmojiSpan": [
+ "sDebugPaint"
+ ]
+ },
+ "android/support/design/widget/FloatingActionButton$Behavior": {
+ "androidx/design/widget/FloatingActionButton$Behavior": [
+ "AUTO_HIDE_DEFAULT"
+ ]
+ },
+ "android/support/graphics/drawable/ArgbEvaluator": {
+ "androidx/graphics/drawable/ArgbEvaluator": [
+ "sInstance"
+ ]
+ },
+ "android/support/v4/util/ContainerHelpers": {
+ "androidx/util/ContainerHelpers": [
+ "EMPTY_INTS",
+ "EMPTY_LONGS",
+ "EMPTY_OBJECTS"
+ ]
+ },
+ "android/support/v7/media/MediaRouterJellybeanMr1": {
+ "androidx/media/MediaRouterJellybeanMr1": [
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/ActionPresenterSelector$ActionViewHolder": {
+ "androidx/leanback/widget/ActionPresenterSelector$ActionViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/v4/app/FragmentState": {
+ "androidx/app/FragmentState": [
+ "CREATOR"
+ ]
+ },
+ "android/support/v7/widget/LinearSnapHelper": {
+ "androidx/widget/LinearSnapHelper": [
+ "INVALID_DISTANCE"
+ ]
+ },
+ "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder": {
+ "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/constraint/solver/widgets/ConstraintAnchor$Strength": {
+ "androidx/constraint/solver/widgets/ConstraintAnchor$Strength": [
+ "STRONG"
+ ]
+ },
+ "android/support/design/widget/HeaderBehavior": {
+ "androidx/design/widget/HeaderBehavior": [
+ "INVALID_POINTER"
+ ]
+ },
+ "android/support/v7/widget/LinearLayoutManager$SavedState": {
+ "androidx/widget/LinearLayoutManager$SavedState": [
+ "CREATOR"
+ ]
+ },
+ "android/support/v7/widget/GridLayout$Interval": {
+ "androidx/widget/GridLayout$Interval": [
+ "min",
+ "max"
+ ]
+ },
+ "android/support/v4/widget/SlidingPaneLayout$SavedState": {
+ "androidx/widget/SlidingPaneLayout$SavedState": [
+ "CREATOR",
+ "isOpen"
+ ]
+ },
+ "android/support/v17/leanback/widget/DetailsOverviewLogoPresenter$ViewHolder": {
+ "androidx/leanback/widget/DetailsOverviewLogoPresenter$ViewHolder": [
+ "view"
+ ]
+ },
+ "android/support/v4/media/session/MediaSessionCompatApi24": {
+ "androidx/media/session/MediaSessionCompatApi24": [
+ "TAG"
+ ]
+ },
+ "android/support/v7/app/MediaRouteActionProvider": {
+ "androidx/app/MediaRouteActionProvider": [
+ "TAG"
+ ]
+ },
+ "android/support/v4/media/session/MediaButtonReceiver": {
+ "androidx/media/session/MediaButtonReceiver": [
+ "TAG"
+ ]
+ },
+ "android/support/v4/content/AsyncTaskLoader$LoadTask": {
+ "androidx/content/AsyncTaskLoader$LoadTask": [
+ "waiting"
+ ]
+ },
+ "android/support/v4/media/session/MediaSessionCompatApi21": {
+ "androidx/media/session/MediaSessionCompatApi21": [
+ "TAG"
+ ]
+ },
+ "android/support/design/internal/NavigationMenuPresenter$ViewHolder": {
+ "androidx/design/internal/NavigationMenuPresenter$ViewHolder": [
+ "itemView"
+ ]
+ },
+ "android/support/v7/widget/AppCompatButton": {
+ "androidx/widget/AppCompatButton": [
+ "PLATFORM_SUPPORTS_AUTOSIZE"
+ ]
+ },
+ "android/support/v17/leanback/widget/CheckableImageView": {
+ "androidx/leanback/widget/CheckableImageView": [
+ "CHECKED_STATE_SET"
+ ]
+ },
+ "android/support/v4/view/animation/FastOutLinearInInterpolator": {
+ "androidx/view/animation/FastOutLinearInInterpolator": [
+ "VALUES"
+ ]
+ },
+ "android/support/v7/app/MediaRouteDiscoveryFragment": {
+ "androidx/app/MediaRouteDiscoveryFragment": [
+ "ARGUMENT_SELECTOR"
+ ]
+ },
+ "android/support/v4/graphics/TypefaceCompatApi21Impl": {
+ "androidx/graphics/TypefaceCompatApi21Impl": [
+ "TAG"
+ ]
+ },
+ "android/support/v17/leanback/widget/FocusHighlightHelper$BrowseItemFocusHighlight": {
+ "androidx/leanback/widget/FocusHighlightHelper$BrowseItemFocusHighlight": [
+ "DURATION_MS"
+ ]
+ },
+ "android/support/transition/ImageViewUtilsApi21": {
+ "androidx/transition/ImageViewUtilsApi21": [
+ "TAG",
+ "sAnimateTransformMethodFetched",
+ "sAnimateTransformMethod"
+ ]
+ },
+ "android/support/v7/widget/RecyclerView$SmoothScroller$Action": {
+ "androidx/widget/RecyclerView$SmoothScroller$Action": [
+ "UNDEFINED_DURATION"
+ ]
+ },
+ "android/support/v4/media/session/PlaybackStateCompat$CustomAction": {
+ "androidx/media/session/PlaybackStateCompat$CustomAction": [
+ "CREATOR"
+ ]
+ },
+ "android/support/design/R$integer": {
+ "androidx/design/R$integer": [
+ "app_bar_elevation_anim_duration"
+ ]
+ },
+ "android/support/v4/provider/DocumentFile": {
+ "androidx/provider/DocumentFile": [
+ "TAG"
+ ]
+ },
+ "android/support/v7/widget/StaggeredGridLayoutManager$SavedState": {
+ "androidx/widget/StaggeredGridLayoutManager$SavedState": [
+ "CREATOR"
+ ]
+ },
+ "android/support/animation/FlingAnimation$DragForce": {
+ "androidx/animation/FlingAnimation$DragForce": [
+ "VELOCITY_THRESHOLD_MULTIPLIER",
+ "DEFAULT_FRICTION"
+ ]
+ },
+ "android/support/v17/leanback/transition/ParallaxTransition": {
+ "androidx/leanback/transition/ParallaxTransition": [
+ "sInterpolator"
+ ]
+ },
+ "android/support/v4/app/NotificationCompat$MessagingStyle": {
+ "androidx/app/NotificationCompat$MessagingStyle": [
+ "MAXIMUM_RETAINED_MESSAGES"
+ ]
+ },
+ "android/support/v7/widget/RecyclerView$SavedState": {
+ "androidx/widget/RecyclerView$SavedState": [
+ "CREATOR"
+ ]
+ },
+ "android/support/v17/leanback/widget/ResizingTextView": {
+ "androidx/leanback/widget/ResizingTextView": [
+ "TRIGGER_MAX_LINES"
+ ]
+ },
+ "android/support/v7/widget/StaggeredGridLayoutManager$LazySpanLookup": {
+ "androidx/widget/StaggeredGridLayoutManager$LazySpanLookup": [
+ "MIN_SIZE"
+ ]
+ },
+ "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase": {
+ "androidx/media/session/MediaSessionCompat$MediaSessionImplBase": [
+ "RCC_PLAYSTATE_NONE"
+ ]
+ },
+ "android/support/v4/util/LongSparseArray": {
+ "androidx/util/LongSparseArray": [
+ "DELETED"
+ ]
+ },
+ "android/support/v4/view/accessibility/AccessibilityNodeProviderCompat": {
+ "androidx/view/accessibility/AccessibilityNodeProviderCompat": [
+ "HOST_VIEW_ID"
+ ]
+ },
+ "android/support/v4/view/AsyncLayoutInflater": {
+ "androidx/view/AsyncLayoutInflater": [
+ "TAG"
+ ]
+ },
+ "android/support/graphics/drawable/VectorDrawableCompat$VPathRenderer": {
+ "androidx/graphics/drawable/VectorDrawableCompat$VPathRenderer": [
+ "IDENTITY_MATRIX"
+ ]
+ },
+ "android/support/v13/view/DragAndDropPermissionsCompat": {
+ "androidx/view/DragAndDropPermissionsCompat": [
+ "IMPL"
+ ]
+ },
+ "android/support/v4/media/MediaBrowserCompatApi21": {
+ "androidx/media/MediaBrowserCompatApi21": [
+ "NULL_MEDIA_ITEM_ID"
+ ]
+ },
+ "android/support/v4/view/animation/FastOutSlowInInterpolator": {
+ "androidx/view/animation/FastOutSlowInInterpolator": [
+ "VALUES"
+ ]
+ },
+ "android/support/v7/widget/AppCompatProgressBarHelper": {
+ "androidx/widget/AppCompatProgressBarHelper": [
+ "TINT_ATTRS"
+ ]
+ },
+ "android/support/v4/media/ParceledListSliceAdapterApi21": {
+ "androidx/media/ParceledListSliceAdapterApi21": [
+ "sConstructor"
+ ]
+ },
+ "android/support/compat/R$integer": {
+ "androidx/compat/R$integer": [
+ "status_bar_notification_info_maxnum"
+ ]
+ },
+ "android/support/v14/preference/EditTextPreferenceDialogFragment": {
+ "androidx/preference/EditTextPreferenceDialogFragment": [
+ "SAVE_STATE_TEXT"
+ ]
+ },
+ "android/support/wear/R$array": {
+ "androidx/wear/R$array": [
+ "circular_progress_layout_color_scheme_colors"
+ ]
+ },
+ "android/support/v7/cardview/R$style": {
+ "androidx/cardview/R$style": [
+ "CardView"
+ ]
+ },
+ "android/support/design/internal/ParcelableSparseArray": {
+ "androidx/design/internal/ParcelableSparseArray": [
+ "CREATOR"
+ ]
+ },
+ "android/support/design/widget/CircularBorderDrawable": {
+ "androidx/design/widget/CircularBorderDrawable": [
+ "DRAW_STROKE_WIDTH_MULTIPLE"
+ ]
+ },
+ "android/support/transition/ObjectAnimatorUtils": {
+ "androidx/transition/ObjectAnimatorUtils": [
+ "IMPL"
+ ]
+ },
+ "android/support/v4/app/ActivityCompat": {
+ "androidx/app/ActivityCompat": [
+ "sDelegate"
+ ]
+ },
+ "android/support/wear/internal/widget/drawer/MultiPageUi": {
+ "androidx/wear/internal/widget/drawer/MultiPageUi": [
+ "TAG"
+ ]
+ },
+ "android/support/transition/ViewOverlayApi14$OverlayViewGroup": {
+ "androidx/transition/ViewOverlayApi14$OverlayViewGroup": [
+ "sInvalidateChildInParentFastMethod"
+ ]
+ },
+ "android/support/v4/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicLocale": {
+ "androidx/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicLocale": [
+ "INSTANCE"
+ ]
+ },
+ "android/support/v7/preference/Preference": {
+ "androidx/preference/Preference": [
+ "DEFAULT_ORDER"
+ ]
+ },
+ "android/support/v4/graphics/drawable/RoundedBitmapDrawable": {
+ "androidx/graphics/drawable/RoundedBitmapDrawable": [
+ "DEFAULT_PAINT_FLAGS"
+ ]
+ },
+ "android/support/design/widget/TabLayout$Tab": {
+ "androidx/design/widget/TabLayout$Tab": [
+ "INVALID_POSITION"
+ ]
+ },
+ "android/support/v7/widget/SnapHelper": {
+ "androidx/widget/SnapHelper": [
+ "MILLISECONDS_PER_INCH"
+ ]
+ },
+ "android/support/v7/widget/AbsActionBarView": {
+ "androidx/widget/AbsActionBarView": [
+ "FADE_DURATION"
+ ]
+ },
+ "android/support/v17/leanback/graphics/FitWidthBitmapDrawable": {
+ "androidx/leanback/graphics/FitWidthBitmapDrawable": [
+ "PROPERTY_VERTICAL_OFFSET"
+ ]
+ },
+ "android/support/v4/media/session/MediaSessionCompat$ResultReceiverWrapper": {
+ "androidx/media/session/MediaSessionCompat$ResultReceiverWrapper": [
+ "CREATOR"
+ ]
+ },
+ "android/support/v7/view/SupportMenuInflater$InflatedOnMenuItemClickListener": {
+ "androidx/view/SupportMenuInflater$InflatedOnMenuItemClickListener": [
+ "PARAM_TYPES"
+ ]
+ },
+ "android/support/v4/widget/EdgeEffectCompat": {
+ "androidx/widget/EdgeEffectCompat": [
+ "IMPL"
+ ]
+ },
+ "android/support/v7/app/MediaRouteDialogFactory": {
+ "androidx/app/MediaRouteDialogFactory": [
+ "sDefault"
+ ]
+ },
+ "android/support/v4/app/Fragment$SavedState": {
+ "androidx/app/Fragment$SavedState": [
+ "CREATOR"
+ ]
+ },
+ "android/support/transition/Styleable$TransitionSet": {
+ "androidx/transition/Styleable$TransitionSet": [
+ "TRANSITION_ORDERING"
+ ]
+ },
+ "android/support/v7/preference/PreferenceGroupAdapter": {
+ "androidx/preference/PreferenceGroupAdapter": [
+ "TAG"
+ ]
+ },
+ "android/support/v7/view/menu/MenuPopupHelper": {
+ "androidx/view/menu/MenuPopupHelper": [
+ "TOUCH_EPICENTER_SIZE_DP"
+ ]
+ },
+ "android/support/v4/app/NotificationCompat$Builder": {
+ "androidx/app/NotificationCompat$Builder": [
+ "MAX_CHARSEQUENCE_LENGTH"
+ ]
+ }
+ }
+ },
+ "proGuardMap": {
+ "rules": {}
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/config/ConfigParserTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/config/ConfigParserTest.kt
new file mode 100644
index 0000000..4a03ef3
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/config/ConfigParserTest.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.config
+
+import com.google.common.truth.Truth
+import org.junit.Test
+
+class ConfigParserTest {
+
+ @Test fun parseConfig_validInput() {
+ val confStr =
+ "{\n" +
+ " restrictToPackagePrefixes: [\"android/support/\"],\n" +
+ " # Sample comment \n" +
+ " rules: [\n" +
+ " {\n" +
+ " from: \"android/support/v14/preferences/(.*)\",\n" +
+ " to: \"android/jetpack/prefs/main/{0}\"\n" +
+ " },\n" +
+ " {\n" +
+ " from: \"android/support/v14/preferences/(.*)\",\n" +
+ " to: \"android/jetpack/prefs/main/{0}\",\n" +
+ " fieldSelectors: [\"dialog_(.*)\"]\n" +
+ " }\n" +
+ " ],\n" +
+ " pomRules: [\n" +
+ " {\n" +
+ " from: {groupId: \"g\", artifactId: \"a\", version: \"1.0\"},\n" +
+ " to: [\n" +
+ " {groupId: \"g\", artifactId: \"a\", version: \"2.0\"} \n" +
+ " ]\n" +
+ " }\n" +
+ " ]\n" +
+ "}"
+
+ val config = ConfigParser.parseFromString(confStr)
+
+ Truth.assertThat(config).isNotNull()
+ Truth.assertThat(config!!.restrictToPackagePrefixes[0]).isEqualTo("android/support/")
+ Truth.assertThat(config.rewriteRules.size).isEqualTo(2)
+ }
+}
+
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/map/MapGenerationTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/map/MapGenerationTest.kt
new file mode 100644
index 0000000..e7f8570
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/map/MapGenerationTest.kt
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.map
+
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.rules.JavaField
+import android.support.tools.jetifier.core.rules.JavaType
+import android.support.tools.jetifier.core.rules.RewriteRule
+import android.support.tools.jetifier.core.transform.proguard.ProGuardTypesMap
+import com.google.common.truth.Truth
+import org.junit.Test
+
+
+class MapGenerationTest {
+
+ @Test fun fromOneType_toOneType() {
+ ScanTester
+ .testThatRules(
+ RewriteRule("android/support/v7/(.*)", "android/test/{0}")
+ )
+ .withAllowedPrefixes(
+ "android/support/"
+ )
+ .forGivenTypes(
+ JavaType("android/support/v7/pref/Preference")
+ )
+ .mapInto(
+ types = mapOf(
+ "android/support/v7/pref/Preference" to "android/test/pref/Preference"
+ ),
+ fields = mapOf(
+ )
+ )
+ .andIsComplete()
+ }
+
+ @Test fun fromTwoTypes_toOneType_prefixRespected() {
+ ScanTester
+ .testThatRules(
+ RewriteRule("android/support/v7/(.*)", "android/test/{0}"),
+ RewriteRule("android/support/v14/(.*)", "android/test/{0}")
+ )
+ .withAllowedPrefixes(
+ "android/support/v7/"
+ )
+ .forGivenTypes(
+ JavaType("android/support/v7/pref/Preference"),
+ JavaType("android/support/v14/pref/PreferenceDialog")
+ )
+ .mapInto(
+ types = mapOf(
+ "android/support/v7/pref/Preference" to "android/test/pref/Preference"
+ ),
+ fields = mapOf(
+ )
+ )
+ .andIsComplete()
+ }
+
+ @Test fun fromTwoTypes_toTwoTypes_distinctRules() {
+ ScanTester
+ .testThatRules(
+ RewriteRule("android/support/v7/(.*)", "android/test/{0}"),
+ RewriteRule("android/support/v14/(.*)", "android/test/{0}")
+ )
+ .withAllowedPrefixes(
+ "android/support/v7/",
+ "android/support/v14/"
+ )
+ .forGivenTypes(
+ JavaType("android/support/v7/pref/Preference"),
+ JavaType("android/support/v14/pref/PreferenceDialog")
+ )
+ .mapInto(
+ types = mapOf(
+ "android/support/v7/pref/Preference" to "android/test/pref/Preference",
+ "android/support/v14/pref/PreferenceDialog" to "android/test/pref/PreferenceDialog"
+ ),
+ fields = mapOf(
+ )
+ )
+ .andIsComplete()
+ }
+
+ @Test fun fromTwoTypes_toTwoTypes_respectsOrder() {
+ ScanTester
+ .testThatRules(
+ RewriteRule("android/support/v14/(.*)", "android/test/{0}"),
+ RewriteRule("android/support/(.*)", "android/fallback/{0}")
+ )
+ .withAllowedPrefixes(
+ "android/support/"
+ )
+ .forGivenTypes(
+ JavaType("android/support/v7/pref/Preference"),
+ JavaType("android/support/v14/pref/PreferenceDialog")
+ )
+ .mapInto(
+ types = mapOf(
+ "android/support/v7/pref/Preference" to "android/fallback/v7/pref/Preference",
+ "android/support/v14/pref/PreferenceDialog" to "android/test/pref/PreferenceDialog"
+ ),
+ fields = mapOf(
+ )
+ )
+ .andIsComplete()
+ }
+
+ @Test fun mapTwoFields_usingOneTypeRule() {
+ ScanTester
+ .testThatRules(
+ RewriteRule("android/support/v7/(.*)", "android/test/{0}")
+ )
+ .withAllowedPrefixes(
+ "android/support/"
+ )
+ .forGivenFields(
+ JavaField("android/support/v7/pref/Preference", "count"),
+ JavaField("android/support/v7/pref/Preference", "min")
+ )
+ .mapInto(
+ types = mapOf(
+ ),
+ fields = mapOf(
+ "android/support/v7/pref/Preference" to mapOf(
+ "android/test/pref/Preference" to listOf(
+ "count",
+ "min"
+ )
+ )
+ )
+ )
+ .andIsComplete()
+ }
+
+ @Test fun mapFieldInInnerClass_usingOneTypeRule() {
+ ScanTester
+ .testThatRules(
+ RewriteRule("android/support/v7/(.*)", "android/test/{0}")
+ )
+ .withAllowedPrefixes(
+ "android/support/"
+ )
+ .forGivenFields(
+ JavaField("android/support/v7/pref/R\$attr", "border")
+ )
+ .mapInto(
+ types = mapOf(
+ ),
+ fields = mapOf(
+ "android/support/v7/pref/R\$attr" to mapOf(
+ "android/test/pref/R\$attr" to listOf(
+ "border"
+ )
+ )
+ )
+ )
+ .andIsComplete()
+ }
+
+ @Test fun mapPrivateFields_shouldIgnore() {
+ ScanTester
+ .testThatRules(
+ RewriteRule("android/support/v7/(.*)", "android/test/{0}")
+ )
+ .withAllowedPrefixes(
+ "android/support/"
+ )
+ .forGivenFields(
+ JavaField("android/support/v7/pref/Preference", "mCount"),
+ JavaField("android/support/v7/pref/Preference", "this$0")
+ )
+ .mapInto(
+ types = mapOf(
+ ),
+ fields = mapOf(
+ )
+ )
+ .andIsComplete()
+ }
+
+ @Test fun mapType_usingFieldSelector_shouldNotApply() {
+ ScanTester
+ .testThatRules(
+ RewriteRule("android/support/v7/(.*)", "android/test/{0}", listOf("count"))
+ )
+ .withAllowedPrefixes(
+ "android/support/"
+ )
+ .forGivenTypes(
+ JavaType("android/support/v7/pref/Preference")
+ )
+ .mapInto(
+ types = mapOf(
+ "android/support/v7/pref/Preference" to "android/support/v7/pref/Preference"
+ ),
+ fields = mapOf(
+ )
+ )
+ .andIsNotComplete()
+ }
+
+ @Test fun mapField_noApplicableRule() {
+ ScanTester
+ .testThatRules(
+ RewriteRule("android/support/v7/(.*)", "android/test/{0}", listOf("count2"))
+ )
+ .withAllowedPrefixes(
+ "android/support/"
+ )
+ .forGivenFields(
+ JavaField("android/support/v7/pref/Preference", "count")
+ )
+ .mapInto(
+ types = mapOf(
+ ),
+ fields = mapOf(
+ "android/support/v7/pref/Preference" to mapOf(
+ "android/support/v7/pref/Preference" to listOf(
+ "count"
+ )
+ )
+ )
+ )
+ .andIsNotComplete()
+ }
+
+ @Test fun mapTwoFields_usingTwoFieldsSelectors() {
+ ScanTester
+ .testThatRules(
+ RewriteRule("android/support/v7/(.*)", "android/test/{0}", listOf("count")),
+ RewriteRule("android/support/v7/(.*)", "android/test2/{0}", listOf("size"))
+ )
+ .withAllowedPrefixes(
+ "android/support/"
+ )
+ .forGivenFields(
+ JavaField("android/support/v7/pref/Preference", "count"),
+ JavaField("android/support/v7/pref/Preference", "size")
+ )
+ .mapInto(
+ types = mapOf(
+ ),
+ fields = mapOf(
+ "android/support/v7/pref/Preference" to mapOf(
+ "android/test/pref/Preference" to listOf(
+ "count"
+ ),
+ "android/test2/pref/Preference" to listOf(
+ "size"
+ )
+ )
+ )
+ )
+ .andIsComplete()
+ }
+
+
+ object ScanTester {
+
+ fun testThatRules(vararg rules: RewriteRule) = Step1(rules.toList())
+
+
+ class Step1(val rules: List<RewriteRule>) {
+
+ fun withAllowedPrefixes(vararg prefixes: String) = Step2(rules, prefixes.toList())
+
+
+ class Step2(val rules: List<RewriteRule>, val prefixes: List<String>) {
+
+ private val allTypes: MutableList<JavaType> = mutableListOf()
+ private val allFields: MutableList<JavaField> = mutableListOf()
+ private var wasMapIncomplete = false
+
+
+ fun forGivenTypes(vararg types: JavaType) : Step2 {
+ allTypes.addAll(types)
+ return this
+ }
+
+ fun forGivenFields(vararg fields: JavaField) : Step2 {
+ allFields.addAll(fields)
+ return this
+ }
+
+ fun mapInto(types: Map<String, String>,
+ fields: Map<String, Map<String, List<String>>>) : Step2 {
+ val config = Config(
+ restrictToPackagePrefixes = prefixes,
+ rewriteRules = rules,
+ pomRewriteRules = emptyList(),
+ typesMap = TypesMap.EMPTY,
+ proGuardMap = ProGuardTypesMap.EMPTY)
+ val scanner = MapGeneratorRemapper(config)
+
+ allTypes.forEach { scanner.rewriteType(it) }
+ allFields.forEach { scanner.rewriteField(it) }
+
+ val typesMap = scanner.createTypesMap().toJson()
+ wasMapIncomplete = scanner.isMapNotComplete
+
+ Truth.assertThat(typesMap.types).containsExactlyEntriesIn(types)
+ Truth.assertThat(typesMap.fields).containsExactlyEntriesIn(fields)
+ return this
+ }
+
+ fun andIsNotComplete() {
+ Truth.assertThat(wasMapIncomplete).isTrue()
+ }
+
+ fun andIsComplete() {
+ Truth.assertThat(wasMapIncomplete).isFalse()
+ }
+ }
+
+ }
+
+ }
+}
+
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/RewriteRuleTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/RewriteRuleTest.kt
new file mode 100644
index 0000000..ca6288d
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/RewriteRuleTest.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform
+
+import android.support.tools.jetifier.core.rules.JavaField
+import android.support.tools.jetifier.core.rules.JavaType
+import android.support.tools.jetifier.core.rules.RewriteRule
+import com.google.common.truth.Truth
+import org.junit.Test
+
+
+class RewriteRuleTest {
+
+ @Test fun noRegEx_shouldRewrite() {
+ RuleTester
+ .testThatRule("A/B", "A/C")
+ .rewritesType("A/B")
+ .into("A/C")
+ }
+
+ @Test fun noRegEx_underscore_shouldRewrite() {
+ RuleTester
+ .testThatRule("A/B_B", "A/C")
+ .rewritesType("A/B_B")
+ .into("A/C")
+ }
+
+ @Test fun groupRegEx_shouldRewrite() {
+ RuleTester
+ .testThatRule("A/B/(.*)", "A/{0}")
+ .rewritesType("A/B/C/D")
+ .into("A/C/D")
+ }
+
+ @Test fun groupRegEx__innerClass_shouldRewrite() {
+ RuleTester
+ .testThatRule("A/B/(.*)", "A/{0}")
+ .rewritesType("A/B/C\$D")
+ .into("A/C\$D")
+ }
+
+ @Test fun fieldRule_noRegEx_shouldRewrite() {
+ RuleTester
+ .testThatRule("A/B", "A/C")
+ .withFieldSelector("MyField")
+ .rewritesField("A/B", "MyField")
+ .into("A/C", "MyField")
+ }
+
+ @Test fun fieldRule_innerClass_groupRegEx_shouldRewrite() {
+ RuleTester
+ .testThatRule("A/B$(.*)", "A/C\${0}")
+ .rewritesType("A/B\$D")
+ .into("A/C\$D")
+ }
+
+ @Test fun noFieldRule_shouldRewriteEvenWithField() {
+ RuleTester
+ .testThatRule("A/B", "A/C")
+ .rewritesField("A/B", "test")
+ .into("A/C", "test")
+ }
+
+
+ object RuleTester {
+
+ fun testThatRule(from: String, to: String) = RuleTesterStep1(from, to)
+
+ class RuleTesterStep1(val from: String, val to: String) {
+
+ val fieldSelectors: MutableList<String> = mutableListOf()
+
+ fun withFieldSelector(input: String) : RuleTesterStep1 {
+ fieldSelectors.add(input)
+ return this
+ }
+
+ fun rewritesField(inputType: String, inputField: String)
+ = RuleTesterFinalFieldStep(from, to, inputType, inputField, fieldSelectors)
+
+ fun rewritesType(inputType: String)
+ = RuleTesterFinalTypeStep(from, to, inputType, fieldSelectors)
+ }
+
+ class RuleTesterFinalFieldStep(val fromType: String,
+ val toType: String,
+ val inputType: String,
+ val inputField: String,
+ val fieldSelectors: List<String>) {
+
+ fun into(expectedTypeName: String, expectedFieldName: String) {
+ val fieldRule = RewriteRule(fromType, toType, fieldSelectors)
+ val result = fieldRule.apply(JavaField(inputType, inputField))
+ Truth.assertThat(result).isNotNull()
+
+ Truth.assertThat(result!!.owner.fullName).isEqualTo(expectedTypeName)
+ Truth.assertThat(result.name).isEqualTo(expectedFieldName)
+ }
+
+ }
+
+ class RuleTesterFinalTypeStep(val fromType: String,
+ val toType: String,
+ val inputType: String,
+ val fieldSelectors: List<String>) {
+
+ fun into(expectedResult: String) {
+ val fieldRule = RewriteRule(fromType, toType, fieldSelectors)
+ val result = fieldRule.apply(JavaType(inputType))
+ Truth.assertThat(result).isNotNull()
+
+ Truth.assertThat(result).isNotNull()
+ Truth.assertThat(result!!.fullName).isEqualTo(expectedResult)
+ }
+
+ }
+ }
+
+}
+
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/pom/PomDocumentTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/pom/PomDocumentTest.kt
new file mode 100644
index 0000000..d55687f
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/pom/PomDocumentTest.kt
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.pom
+
+import android.support.tools.jetifier.core.archive.ArchiveFile
+import com.google.common.truth.Truth
+import org.junit.Test
+import java.nio.charset.StandardCharsets
+import java.nio.file.Paths
+
+class PomDocumentTest {
+
+ @Test fun pom_noRules_noChange() {
+ testRewriteToTheSame(
+ givenAndExpectedXml =
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>supportGroup</groupId>\n" +
+ " <artifactId>supportArtifact</artifactId>\n" +
+ " <version>4.0</version>\n" +
+ " <type>jar</type>\n" +
+ " <scope>test</scope>\n" +
+ " <optional>true</optional>\n" +
+ " </dependency>\n" +
+ " </dependencies>",
+ rules = listOf()
+ )
+ }
+
+ @Test fun pom_oneRule_shouldApply() {
+ testRewrite(
+ givenXml =
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>supportGroup</groupId>\n" +
+ " <artifactId>supportArtifact</artifactId>\n" +
+ " <version>4.0</version>\n" +
+ " </dependency>\n" +
+ " <dependency>\n" +
+ " <systemPath>test/test</systemPath>\n" +
+ " </dependency>\n" +
+ " </dependencies>",
+ expectedXml =
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>testGroup</groupId>\n" +
+ " <artifactId>testArtifact</artifactId>\n" +
+ " <version>1.0</version>\n" +
+ " </dependency>\n" +
+ " <dependency>\n" +
+ " <systemPath>test/test</systemPath>\n" +
+ " </dependency>\n" +
+ " </dependencies>",
+ rules = listOf(
+ PomRewriteRule(
+ PomDependency(
+ groupId = "supportGroup", artifactId = "supportArtifact",
+ version = "4.0"),
+ listOf(
+ PomDependency(
+ groupId = "testGroup", artifactId = "testArtifact",
+ version = "1.0")
+ )
+ )
+ )
+ )
+ }
+
+ @Test fun pom_oneRule_shouldSkipTestScopedRule() {
+ testRewriteToTheSame(
+ givenAndExpectedXml =
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>supportGroup</groupId>\n" +
+ " <artifactId>supportArtifact</artifactId>\n" +
+ " <version>4.0</version>\n" +
+ " <scope>test</scope>\n" +
+ " </dependency>\n" +
+ " </dependencies>",
+ rules = listOf(
+ PomRewriteRule(
+ PomDependency(
+ groupId = "supportGroup", artifactId = "supportArtifact",
+ version = "4.0"),
+ listOf(
+ PomDependency(
+ groupId = "testGroup", artifactId = "testArtifact",
+ version = "1.0")
+ )
+ )
+ )
+ )
+ }
+
+ @Test fun pom_oneRule_notApplicable() {
+ testRewriteToTheSame(
+ givenAndExpectedXml =
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>supportGroup</groupId>\n" +
+ " <artifactId>supportArtifact</artifactId>\n" +
+ " <version>4.0</version>\n" +
+ " </dependency>\n" +
+ " </dependencies>",
+ rules = listOf(
+ PomRewriteRule(
+ PomDependency(
+ groupId = "supportGroup", artifactId = "supportArtifact2",
+ version = "4.0"),
+ listOf(
+ PomDependency(
+ groupId = "testGroup", artifactId = "testArtifact",
+ version = "1.0")
+ )
+ )
+ )
+ )
+ }
+
+ @Test fun pom_oneRule_appliedForEachType() {
+ testRewrite(
+ givenXml =
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>supportGroup</groupId>\n" +
+ " <artifactId>supportArtifact</artifactId>\n" +
+ " <version>4.0</version>\n" +
+ " <type>test</type>\n" +
+ " </dependency>\n" +
+ " <dependency>\n" +
+ " <groupId>supportGroup</groupId>\n" +
+ " <artifactId>supportArtifact</artifactId>\n" +
+ " <version>4.0</version>\n" +
+ " <type>compile</type>\n" +
+ " </dependency>\n" +
+ " </dependencies>",
+ expectedXml =
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>testGroup</groupId>\n" +
+ " <artifactId>testArtifact</artifactId>\n" +
+ " <version>1.0</version>\n" +
+ " <type>test</type>\n" +
+ " </dependency>\n" +
+ " <dependency>\n" +
+ " <groupId>testGroup</groupId>\n" +
+ " <artifactId>testArtifact</artifactId>\n" +
+ " <version>1.0</version>\n" +
+ " <type>compile</type>\n" +
+ " </dependency>\n" +
+ " </dependencies>",
+ rules = listOf(
+ PomRewriteRule(
+ PomDependency(
+ groupId = "supportGroup", artifactId = "supportArtifact",
+ version = "4.0"),
+ listOf(
+ PomDependency(
+ groupId = "testGroup", artifactId = "testArtifact",
+ version = "1.0")
+ )
+ )
+ )
+ )
+ }
+
+ @Test fun pom_multipleTargets_shouldApplyAll() {
+ testRewrite(
+ givenXml =
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>supportGroup</groupId>\n" +
+ " <artifactId>supportArtifact</artifactId>\n" +
+ " <version>4.0</version>\n" +
+ " </dependency>\n" +
+ " </dependencies>",
+ expectedXml =
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>testGroup</groupId>\n" +
+ " <artifactId>testArtifact</artifactId>\n" +
+ " <version>1.0</version>\n" +
+ " </dependency>\n" +
+ " <dependency>\n" +
+ " <groupId>testGroup2</groupId>\n" +
+ " <artifactId>testArtifact2</artifactId>\n" +
+ " <version>2.0</version>\n" +
+ " </dependency>\n" +
+ " </dependencies>",
+ rules = listOf(
+ PomRewriteRule(
+ PomDependency(
+ groupId = "supportGroup", artifactId = "supportArtifact",
+ version = "4.0"),
+ listOf(
+ PomDependency(
+ groupId = "testGroup", artifactId = "testArtifact",
+ version = "1.0"),
+ PomDependency(
+ groupId = "testGroup2", artifactId = "testArtifact2",
+ version = "2.0"))
+ )
+ )
+ )
+ }
+
+ @Test fun pom_multipleRulesAndTargets_shouldApplyAll_distinct() {
+ testRewrite(
+ givenXml =
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>supportGroup</groupId>\n" +
+ " <artifactId>supportArtifact</artifactId>\n" +
+ " <version>4.0</version>\n" +
+ " </dependency>\n" +
+ " <dependency>\n" +
+ " <groupId>supportGroup</groupId>\n" +
+ " <artifactId>supportArtifact2</artifactId>\n" +
+ " <version>4.0</version>\n" +
+ " </dependency>\n" +
+ " </dependencies>",
+ expectedXml =
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>testGroup</groupId>\n" +
+ " <artifactId>testArtifact</artifactId>\n" +
+ " <version>1.0</version>\n" +
+ " </dependency>\n" +
+ " <dependency>\n" +
+ " <groupId>testGroup2</groupId>\n" +
+ " <artifactId>testArtifact2</artifactId>\n" +
+ " <version>2.0</version>\n" +
+ " </dependency>\n" +
+ " </dependencies>",
+ rules = listOf(
+ PomRewriteRule(
+ PomDependency(
+ groupId = "supportGroup", artifactId = "supportArtifact",
+ version = "4.0"),
+ listOf(
+ PomDependency(
+ groupId = "testGroup", artifactId = "testArtifact",
+ version = "1.0"),
+ PomDependency(
+ groupId = "testGroup2", artifactId = "testArtifact2",
+ version = "2.0")
+ )
+ ),
+ PomRewriteRule(
+ PomDependency(
+ groupId = "supportGroup", artifactId = "supportArtifact2",
+ version = "4.0"),
+ listOf(
+ PomDependency(
+ groupId = "testGroup", artifactId = "testArtifact",
+ version = "1.0"),
+ PomDependency(
+ groupId = "testGroup2", artifactId = "testArtifact2",
+ version = "2.0"))
+ )
+ )
+ )
+ }
+
+ @Test fun pom_oneRule_hasToKeepExtraAttributesAndRewrite() {
+ testRewrite(
+ givenXml =
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>supportGroup</groupId>\n" +
+ " <artifactId>supportArtifact</artifactId>\n" +
+ " <version>4.0</version>\n" +
+ " <classifier>hey</classifier>\n" +
+ " <type>jar</type>\n" +
+ " <scope>runtime</scope>\n" +
+ " <systemPath>somePath</systemPath>\n" +
+ " <optional>true</optional>\n" +
+ " </dependency>\n" +
+ " </dependencies>",
+ expectedXml =
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>testGroup</groupId>\n" +
+ " <artifactId>testArtifact</artifactId>\n" +
+ " <version>1.0</version>\n" +
+ " <classifier>hey</classifier>\n" +
+ " <type>jar</type>\n" +
+ " <scope>runtime</scope>\n" +
+ " <systemPath>somePath</systemPath>\n" +
+ " <optional>true</optional>\n" +
+ " </dependency>\n" +
+ " </dependencies>",
+ rules = listOf(
+ PomRewriteRule(
+ PomDependency(
+ groupId = "supportGroup", artifactId = "supportArtifact",
+ version = "4.0"),
+ listOf(
+ PomDependency(
+ groupId = "testGroup", artifactId = "testArtifact",
+ version = "1.0")
+ )
+ )
+ )
+ )
+ }
+
+ @Test fun pom_usingEmptyProperties_shouldNotCrash() {
+ val document = loadDocument(
+ " <properties/>\n" +
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>supportGroup</groupId>\n" +
+ " <artifactId>\${groupId.version.property}</artifactId>\n" +
+ " <version>\${groupId.version.property}</version>\n" +
+ " </dependency>\n" +
+ " </dependencies>"
+ )
+
+ Truth.assertThat(document.dependencies).hasSize(1)
+ }
+
+ @Test fun pom_usingProperties_shouldResolve() {
+ val document = loadDocument(
+ " <properties>\n" +
+ " <groupId.version.property>1.0.0</groupId.version.property>\n" +
+ " <groupId.artifactId.property>supportArtifact</groupId.artifactId.property>\n" +
+ " </properties>\n" +
+ " <dependencies>\n" +
+ " <dependency>\n" +
+ " <groupId>supportGroup</groupId>\n" +
+ " <artifactId>\${groupId.artifactId.property}</artifactId>\n" +
+ " <version>\${groupId.version.property}</version>\n" +
+ " </dependency>\n" +
+ " </dependencies>"
+ )
+
+ Truth.assertThat(document.dependencies).hasSize(1)
+
+ val dependency = document.dependencies.first()
+ Truth.assertThat(dependency.version).isEqualTo("1.0.0")
+ Truth.assertThat(dependency.artifactId).isEqualTo("supportArtifact")
+ }
+
+
+ private fun testRewriteToTheSame(givenAndExpectedXml: String, rules: List<PomRewriteRule>) {
+ testRewrite(givenAndExpectedXml, givenAndExpectedXml, rules)
+ }
+
+ private fun testRewrite(givenXml: String, expectedXml : String, rules: List<PomRewriteRule>) {
+ val given =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" " +
+ "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
+ "xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" +
+ " <!-- Some comment -->\n" +
+ " <groupId>test.group</groupId>\n" +
+ " <artifactId>test.artifact.id</artifactId>\n" +
+ " <version>1.0</version>\n" +
+ " $givenXml\n" +
+ "</project>\n"
+
+ var expected =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" " +
+ "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
+ "xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" +
+ " <!-- Some comment -->\n" +
+ " <groupId>test.group</groupId>\n" +
+ " <artifactId>test.artifact.id</artifactId>\n" +
+ " <version>1.0</version>\n" +
+ " $expectedXml\n" +
+ "</project>\n"
+
+ val file = ArchiveFile(Paths.get("pom.xml"), given.toByteArray())
+ val pomDocument = PomDocument.loadFrom(file)
+ pomDocument.applyRules(rules)
+ pomDocument.saveBackToFileIfNeeded()
+ var strResult = file.data.toString(StandardCharsets.UTF_8)
+
+ // Remove spaces in front of '<' and the back of '>'
+ expected = expected.replace(">[ ]+".toRegex(), ">")
+ expected = expected.replace("[ ]+<".toRegex(), "<")
+
+ strResult = strResult.replace(">[ ]+".toRegex(), ">")
+ strResult = strResult.replace("[ ]+<".toRegex(), "<")
+
+ // Replace newline characters to match the ones we are using in the expected string
+ strResult = strResult.replace("\\r\\n".toRegex(), "\n")
+
+ Truth.assertThat(strResult).isEqualTo(expected)
+ }
+
+ private fun loadDocument(givenXml : String) : PomDocument {
+ val given =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" " +
+ "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
+ "xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" +
+ " <!-- Some comment -->\n" +
+ " <groupId>test.group</groupId>\n" +
+ " <artifactId>test.artifact.id</artifactId>\n" +
+ " <version>1.0</version>\n" +
+ " $givenXml\n" +
+ "</project>\n"
+
+ val file = ArchiveFile(Paths.get("pom.xml"), given.toByteArray())
+ val pomDocument = PomDocument.loadFrom(file)
+ return pomDocument
+ }
+}
+
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/pom/PomRewriteRuleTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/pom/PomRewriteRuleTest.kt
new file mode 100644
index 0000000..34ebd04
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/pom/PomRewriteRuleTest.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.pom
+
+import com.google.common.truth.Truth
+import org.junit.Test
+
+class PomRewriteRuleTest {
+
+ @Test fun versions_nullInRule_match() {
+ testVersionsMatch(
+ ruleVersion = null,
+ pomVersion = "27.0.0"
+ )
+ }
+
+ @Test fun versions_nullInPom_match() {
+ testVersionsMatch(
+ ruleVersion = "27.0.0",
+ pomVersion = null
+ )
+ }
+
+ @Test fun versions_nullBoth_match() {
+ testVersionsMatch(
+ ruleVersion = null,
+ pomVersion = null
+ )
+ }
+
+ @Test fun versions_same_match() {
+ testVersionsMatch(
+ ruleVersion = "27.0.0",
+ pomVersion = "27.0.0"
+ )
+ }
+
+ @Test fun versions_same_strict_match() {
+ testVersionsMatch(
+ ruleVersion = "27.0.0",
+ pomVersion = "[27.0.0]"
+ )
+ }
+
+ @Test fun versions_different_noMatch() {
+ testVersionsDoNotMatch(
+ ruleVersion = "27.0.0",
+ pomVersion = "26.0.0"
+ )
+ }
+
+ @Test fun versions_release_match() {
+ testVersionsMatch(
+ ruleVersion = "27.0.0",
+ pomVersion = "release"
+ )
+ }
+
+ @Test fun versions_latest_match() {
+ testVersionsMatch(
+ ruleVersion = "27.0.0",
+ pomVersion = "latest"
+ )
+ }
+
+ @Test fun versions_range_rightOpen_match() {
+ testVersionsMatch(
+ ruleVersion = "27.0.0",
+ pomVersion = "(26.0.0,]"
+ )
+ }
+
+ @Test fun versions_range_rightOpen2_match() {
+ testVersionsMatch(
+ ruleVersion = "27.0.0",
+ pomVersion = "(26.0.0,)"
+ )
+ }
+
+ @Test fun versions_range_inclusive_match() {
+ testVersionsMatch(
+ ruleVersion = "27.0.0",
+ pomVersion = "[21.0.0,27.0.0]"
+ )
+ }
+
+ @Test fun versions_range_inclusive_noMatch() {
+ testVersionsDoNotMatch(
+ ruleVersion = "27.0.0",
+ pomVersion = "[21.0.0,26.0.0]"
+ )
+ }
+
+ @Test fun versions_range_exclusive_noMatch() {
+ testVersionsDoNotMatch(
+ ruleVersion = "27.0.0",
+ pomVersion = "[21.0.0,27.0.0)"
+ )
+ }
+
+ @Test fun versions_exclusionRange_match() {
+ testVersionsMatch(
+ ruleVersion = "27.0.0",
+ pomVersion = "(,26.0.0),(26.0.0,)"
+ )
+ }
+
+ private fun testVersionsMatch(ruleVersion: String?, pomVersion: String?) {
+ val from = PomDependency(version = ruleVersion)
+ val pom = PomDependency(version = pomVersion)
+
+ val rule = PomRewriteRule(from, listOf(from))
+
+ Truth.assertThat(rule.validateVersion(pom)).isTrue()
+ }
+
+ private fun testVersionsDoNotMatch(ruleVersion: String?, pomVersion: String?) {
+ val from = PomDependency(version = ruleVersion)
+ val pom = PomDependency(version = pomVersion)
+
+ val rule = PomRewriteRule(from, listOf(from))
+
+ Truth.assertThat(rule.validateVersion(pom)).isFalse()
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassFilterTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassFilterTest.kt
new file mode 100644
index 0000000..2c7d7e2
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassFilterTest.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import org.junit.Test
+
+class ClassFilterTest {
+
+ @Test fun proGuard_classFilter() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ "-adaptclassstrings support.Activity, support.Fragment, keep.Me"
+ )
+ .rewritesTo(
+ "-adaptclassstrings test.Activity, test.Fragment, keep.Me"
+ )
+ }
+
+ @Test fun proGuard_classFilter_newLineIgnored() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ "-adaptclassstrings support.Activity, support.Fragment, keep.Me \n" +
+ " support.Activity"
+ )
+ .rewritesTo(
+ "-adaptclassstrings test.Activity, test.Fragment, keep.Me \n" +
+ " support.Activity"
+ )
+ }
+
+ @Test fun proGuard_classFilter_spacesRespected() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ " -adaptclassstrings support.Activity , support.Fragment,keep.Me "
+ )
+ .rewritesTo(
+ " -adaptclassstrings test.Activity, test.Fragment, keep.Me"
+ )
+ }
+
+ @Test fun proGuard_classFilter_negation() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ " -adaptclassstrings !support.Activity, !support.Fragment, !keep.Me "
+ )
+ .rewritesTo(
+ " -adaptclassstrings !test.Activity, !test.Fragment, !keep.Me"
+ )
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest.kt
new file mode 100644
index 0000000..e64590f
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest.kt
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import org.junit.Test
+
+class ClassSpecTest {
+
+ @Test fun proGuard_classSpec_simple() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep class support.Activity"
+ )
+ .rewritesTo(
+ "-keep class test.Activity"
+ )
+ }
+
+ @Test fun proGuard_classSpec_allExistingRules() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep class support.Activity \n" +
+ "-keepclassmembers class support.Activity \n" +
+ "-keepclasseswithmembers class support.Activity \n" +
+ "-keepnames class support.Activity \n" +
+ "-keepclassmembernames class support.Activity \n" +
+ "-keepclasseswithmembernames class support.Activity \n" +
+ "-whyareyoukeeping class support.Activity \n" +
+ "-assumenosideeffects class support.Activity"
+ )
+ .rewritesTo(
+ "-keep class test.Activity \n" +
+ "-keepclassmembers class test.Activity \n" +
+ "-keepclasseswithmembers class test.Activity \n" +
+ "-keepnames class test.Activity \n" +
+ "-keepclassmembernames class test.Activity \n" +
+ "-keepclasseswithmembernames class test.Activity \n" +
+ "-whyareyoukeeping class test.Activity \n" +
+ "-assumenosideeffects class test.Activity"
+ )
+ }
+
+ @Test fun proGuard_classSpec_rulesModifiers() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep includedescriptorclasses class support.Activity \n" +
+ "-keep allowshrinking class support.Activity \n" +
+ "-keep allowoptimization class support.Activity \n" +
+ "-keep allowobfuscation class support.Activity \n" +
+ "-keep allowshrinking allowoptimization allowobfuscation class support.Activity \n" +
+ "-keep allowshrinking allowoptimization allowobfuscation class support.Activity"
+ )
+ .rewritesTo(
+ "-keep includedescriptorclasses class test.Activity \n" +
+ "-keep allowshrinking class test.Activity \n" +
+ "-keep allowoptimization class test.Activity \n" +
+ "-keep allowobfuscation class test.Activity \n" +
+ "-keep allowshrinking allowoptimization allowobfuscation class test.Activity \n" +
+ "-keep allowshrinking allowoptimization allowobfuscation class test.Activity"
+ )
+ }
+
+ @Test fun proGuard_classSpec_extends() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep class * extends support.Activity \n" +
+ "-keep class support.Fragment extends support.Activity"
+ )
+ .rewritesTo(
+ "-keep class * extends test.Activity \n" +
+ "-keep class test.Fragment extends test.Activity"
+ )
+ }
+
+ @Test fun proGuard_classSpec_modifiers_extends() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity"
+ )
+ .testThatGivenProGuard(
+ "-keep !public enum * extends support.Activity \n" +
+ "-keep public !final enum * extends support.Activity"
+ )
+ .rewritesTo(
+ "-keep !public enum * extends test.Activity \n" +
+ "-keep public !final enum * extends test.Activity"
+ )
+ }
+
+ @Test fun proGuard_classSpec_annotation() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep @support.Annotation public class support.Activity \n" +
+ "-keep @some.Annotation public class support.Activity"
+ )
+ .rewritesTo(
+ "-keep @test.Annotation public class test.Activity \n" +
+ "-keep @some.Annotation public class test.Activity"
+ )
+ }
+
+ @Test fun proGuard_classSpec_annotation_extends() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep @support.Annotation public class * extends support.Activity\n" +
+ "-keep @some.Annotation !public class * extends support.Activity"
+ )
+ .rewritesTo(
+ "-keep @test.Annotation public class * extends test.Activity\n" +
+ "-keep @some.Annotation !public class * extends test.Activity"
+ )
+ }
+
+ @Test fun proGuard_classSpec_annotation_extends_spaces() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep \t @support.Annotation \t public class * extends support.Activity"
+ )
+ .rewritesTo(
+ "-keep \t @test.Annotation \t public class * extends test.Activity"
+ )
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_FieldTypeSelector.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_FieldTypeSelector.kt
new file mode 100644
index 0000000..2832385
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_FieldTypeSelector.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import org.junit.Test
+
+class ClassSpecTest_FieldTypeSelector {
+
+ @Test fun proGuard_fieldTypeSelector() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " support.Activity height; \n" +
+ " support.Fragment *; \n" +
+ " keep.Me width; \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " test.Activity height; \n" +
+ " test.Fragment *; \n" +
+ " keep.Me width; \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_fieldTypeSelector_modifiers() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " public support.Fragment height; \n" +
+ " !public !static support.Fragment height; \n" +
+ " !protected support.Fragment height; \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " public test.Fragment height; \n" +
+ " !public !static test.Fragment height; \n" +
+ " !protected test.Fragment height; \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_fieldTypeSelector_annotation() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation support.Fragment height; \n" +
+ " @some.Annotation support.Fragment height; \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation test.Fragment height; \n" +
+ " @some.Annotation test.Fragment height; \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_fieldTypeSelector_modifiers_annotation() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation public support.Fragment height; \n" +
+ " @support.Annotation !public !static support.Fragment height; \n" +
+ " @support.Annotation !protected volatile support.Fragment height; \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation public test.Fragment height; \n" +
+ " @test.Annotation !public !static test.Fragment height; \n" +
+ " @test.Annotation !protected volatile test.Fragment height; \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_fieldTypeSelector_modifiers_annotation_spaces() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation public static \t support.Fragment height ; \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation public static \t test.Fragment height ; \n" +
+ "}"
+ )
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_FieldsSelector.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_FieldsSelector.kt
new file mode 100644
index 0000000..6f6a1f9
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_FieldsSelector.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import org.junit.Test
+
+class ClassSpecTest_FieldsSelector {
+
+ @Test fun proGuard_fieldsSelector_minimal() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * extends support.Activity { \n" +
+ " <fields>; \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * extends test.Activity { \n" +
+ " <fields>; \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_fieldsSelector_modifiers() {
+ ProGuardTester
+ .forGivenPrefixes(
+ )
+ .forGivenTypesMap(
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " public <fields>; \n" +
+ " public static <fields>; \n" +
+ " !private !protected <fields>; \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " public <fields>; \n" +
+ " public static <fields>; \n" +
+ " !private !protected <fields>; \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_fieldsSelector_modifiers_annotation() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation public <fields>; \n" +
+ " @support.Annotation public static <fields>; \n" +
+ " @support.Annotation !private !protected <fields>; \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation public <fields>; \n" +
+ " @test.Annotation public static <fields>; \n" +
+ " @test.Annotation !private !protected <fields>; \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_fieldsSelector_modifiers_annotation_spaces() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation public \t <fields> ; \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation public \t <fields> ; \n" +
+ "}"
+ )
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_MethodInitSelector.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_MethodInitSelector.kt
new file mode 100644
index 0000000..9a792cf
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_MethodInitSelector.kt
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import org.junit.Test
+
+class ClassSpecTest_MethodInitSelector {
+
+ @Test fun proGuard_methodsInitSelector() {
+ ProGuardTester
+ .forGivenPrefixes(
+ )
+ .forGivenTypesMap(
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " <methods>; \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " <methods>; \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodsInitSelector_modifiers() {
+ ProGuardTester
+ .forGivenPrefixes(
+ )
+ .forGivenTypesMap(
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " public <methods>; \n" +
+ " public static <methods>; \n" +
+ " public !static <methods>; \n" +
+ " !private static <methods>; \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " public <methods>; \n" +
+ " public static <methods>; \n" +
+ " public !static <methods>; \n" +
+ " !private static <methods>; \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodsInitSelector_modifiers_annotation() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation public <methods>; \n" +
+ " @support.Annotation public static <methods>; \n" +
+ " @support.Annotation public !static <methods>; \n" +
+ " @support.Annotation !private static <methods>; \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation public <methods>; \n" +
+ " @test.Annotation public static <methods>; \n" +
+ " @test.Annotation public !static <methods>; \n" +
+ " @test.Annotation !private static <methods>; \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodInitSelector() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " <init>(); \n" +
+ " <init>(*); \n" +
+ " <init>(...); \n" +
+ " <init>(support.Activity); \n" +
+ " <init>(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " <init>(); \n" +
+ " <init>(*); \n" +
+ " <init>(...); \n" +
+ " <init>(test.Activity); \n" +
+ " <init>(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodInitSelector_modifiers() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " public <init>(); \n" +
+ " public static <init>(*); \n" +
+ " !public !static <init>(...); \n" +
+ " !private static <init>(support.Activity); \n" +
+ " public !abstract <init>(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " public <init>(); \n" +
+ " public static <init>(*); \n" +
+ " !public !static <init>(...); \n" +
+ " !private static <init>(test.Activity); \n" +
+ " public !abstract <init>(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodInitSelector_annotation() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation <init>(); \n" +
+ " @support.Annotation <init>(*); \n" +
+ " @support.Annotation <init>(...); \n" +
+ " @keep.Me <init>(support.Activity); \n" +
+ " @support.Annotation <init>(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation <init>(); \n" +
+ " @test.Annotation <init>(*); \n" +
+ " @test.Annotation <init>(...); \n" +
+ " @keep.Me <init>(test.Activity); \n" +
+ " @test.Annotation <init>(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodInitSelector_modifiers_annotation() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation public <init>(); \n" +
+ " @support.Annotation public static <init>(*); \n" +
+ " @support.Annotation !public !static <init>(...); \n" +
+ " @support.Annotation !private static <init>(support.Activity); \n" +
+ " @support.Annotation public !abstract <init>(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation public <init>(); \n" +
+ " @test.Annotation public static <init>(*); \n" +
+ " @test.Annotation !public !static <init>(...); \n" +
+ " @test.Annotation !private static <init>(test.Activity); \n" +
+ " @test.Annotation public !abstract <init>(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodInitSelector_modifiers_annotation_test() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation public !abstract \t <init> ( support.Activity , support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation public !abstract \t <init> (test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_MethodSelectorWithReturnType.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_MethodSelectorWithReturnType.kt
new file mode 100644
index 0000000..d9960b4
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_MethodSelectorWithReturnType.kt
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import org.junit.Test
+
+class ClassSpecTest_MethodSelectorWithReturnType {
+
+ @Test fun proGuard_methodReturnTypeSelector() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " void get*(); \n" +
+ " void get*(...); \n" +
+ " void get*(*); \n" +
+ " void get*(support.Activity); \n" +
+ " void get?(support.Activity); \n" +
+ " void get(support.Activity); \n" +
+ " void *(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " void get*(); \n" +
+ " void get*(...); \n" +
+ " void get*(*); \n" +
+ " void get*(test.Activity); \n" +
+ " void get?(test.Activity); \n" +
+ " void get(test.Activity); \n" +
+ " void *(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodReturnTypeSelector_voidResult() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " void get(); \n" +
+ " void get(...); \n" +
+ " void get(*); \n" +
+ " void get(support.Activity); \n" +
+ " void get(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " void get(); \n" +
+ " void get(...); \n" +
+ " void get(*); \n" +
+ " void get(test.Activity); \n" +
+ " void get(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodReturnTypeSelector_starResult() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " * get(); \n" +
+ " * get(...); \n" +
+ " * get(*); \n" +
+ " * get(support.Activity); \n" +
+ " * get(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " * get(); \n" +
+ " * get(...); \n" +
+ " * get(*); \n" +
+ " * get(test.Activity); \n" +
+ " * get(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodReturnTypeSelector_typeResult() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " support.Fragment get(); \n" +
+ " support.Fragment get(...); \n" +
+ " support.Fragment get(*); \n" +
+ " support.Fragment get(support.Activity); \n" +
+ " support.Fragment get(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " test.Fragment get(); \n" +
+ " test.Fragment get(...); \n" +
+ " test.Fragment get(*); \n" +
+ " test.Fragment get(test.Activity); \n" +
+ " test.Fragment get(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodReturnTypeSelector_typeResult_wildcards() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " support.Fragment get*(); \n" +
+ " support.Fragment get?(...); \n" +
+ " support.Fragment *(*); \n" +
+ " support.Fragment *(support.Activity); \n" +
+ " support.Fragment *(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " test.Fragment get*(); \n" +
+ " test.Fragment get?(...); \n" +
+ " test.Fragment *(*); \n" +
+ " test.Fragment *(test.Activity); \n" +
+ " test.Fragment *(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodReturnTypeSelector_typeResult_modifiers() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " public support.Fragment get(); \n" +
+ " public static support.Fragment get(...); \n" +
+ " !public !static support.Fragment get(*); \n" +
+ " private support.Fragment get(support.Activity); \n" +
+ " public abstract support.Fragment get(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " public test.Fragment get(); \n" +
+ " public static test.Fragment get(...); \n" +
+ " !public !static test.Fragment get(*); \n" +
+ " private test.Fragment get(test.Activity); \n" +
+ " public abstract test.Fragment get(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodReturnTypeSelector_typeResult_annotation() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation support.Fragment get(); \n" +
+ " @support.Annotation support.Fragment get(...); \n" +
+ " @support.Annotation support.Fragment get(*); \n" +
+ " @keep.Me support.Fragment get(support.Activity); \n" +
+ " @support.Annotation support.Fragment get(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation test.Fragment get(); \n" +
+ " @test.Annotation test.Fragment get(...); \n" +
+ " @test.Annotation test.Fragment get(*); \n" +
+ " @keep.Me test.Fragment get(test.Activity); \n" +
+ " @test.Annotation test.Fragment get(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodReturnTypeSelector_typeResult_modifiers_annotation() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation public support.Fragment get(); \n" +
+ " @support.Annotation public static support.Fragment get(...); \n" +
+ " @support.Annotation !public !static support.Fragment get(*); \n" +
+ " @support.Annotation private support.Fragment get(support.Activity); \n" +
+ " @support.Annotation public abstract support.Fragment get(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation public test.Fragment get(); \n" +
+ " @test.Annotation public static test.Fragment get(...); \n" +
+ " @test.Annotation !public !static test.Fragment get(*); \n" +
+ " @test.Annotation private test.Fragment get(test.Activity); \n" +
+ " @test.Annotation public abstract test.Fragment get(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_methodReturnTypeSelector_typeResult_modifiers_annotation_spaces() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation support.Fragment \t get(support.Activity , support.Fragment , keep.Please) ; \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation test.Fragment \t get(test.Activity, test.Fragment, keep.Please) ; \n" +
+ "}"
+ )
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_NamedCtorSelector.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_NamedCtorSelector.kt
new file mode 100644
index 0000000..21b8b8c
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_NamedCtorSelector.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import org.junit.Test
+
+class ClassSpecTest_NamedCtorSelector {
+
+ @Test fun proGuard_ctorSelector() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " support.Activity(); \n" +
+ " support.Activity(...); \n" +
+ " support.Activity(*); \n" +
+ " support.Activity(support.Activity); \n" +
+ " support.Activity(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " test.Activity(); \n" +
+ " test.Activity(...); \n" +
+ " test.Activity(*); \n" +
+ " test.Activity(test.Activity); \n" +
+ " test.Activity(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_ctorSelector_modifiers() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " public support.Activity(); \n" +
+ " public static support.Activity(...); \n" +
+ " !private support.Activity(*); \n" +
+ " !public !static support.Activity(support.Activity); \n" +
+ " !protected support.Activity(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " public test.Activity(); \n" +
+ " public static test.Activity(...); \n" +
+ " !private test.Activity(*); \n" +
+ " !public !static test.Activity(test.Activity); \n" +
+ " !protected test.Activity(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_ctorSelector_annotation() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation support.Activity(); \n" +
+ " @support.Annotation support.Activity(...); \n" +
+ " @support.Annotation support.Activity(*); \n" +
+ " @support.Annotation support.Activity(support.Activity); \n" +
+ " @support.Annotation support.Activity(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation test.Activity(); \n" +
+ " @test.Annotation test.Activity(...); \n" +
+ " @test.Annotation test.Activity(*); \n" +
+ " @test.Annotation test.Activity(test.Activity); \n" +
+ " @test.Annotation test.Activity(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_ctorSelector_modifiers_annotation() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation public support.Activity(); \n" +
+ " @support.Annotation public static support.Activity(...); \n" +
+ " @support.Annotation !private support.Activity(*); \n" +
+ " @support.Annotation !public !static support.Activity(support.Activity); \n" +
+ " @support.Annotation !protected support.Activity(support.Activity, support.Fragment, keep.Please); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation public test.Activity(); \n" +
+ " @test.Annotation public static test.Activity(...); \n" +
+ " @test.Annotation !private test.Activity(*); \n" +
+ " @test.Annotation !public !static test.Activity(test.Activity); \n" +
+ " @test.Annotation !protected test.Activity(test.Activity, test.Fragment, keep.Please); \n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_ctorSelector_modifiers_annotation_spaces() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * { \n" +
+ " @support.Annotation !protected \t support.Activity( support.Activity ); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * { \n" +
+ " @test.Annotation !protected \t test.Activity(test.Activity); \n" +
+ "}"
+ )
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTester.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTester.kt
new file mode 100644
index 0000000..cae21d0
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTester.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import android.support.tools.jetifier.core.archive.ArchiveFile
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.map.TypesMap
+import android.support.tools.jetifier.core.rules.JavaType
+import android.support.tools.jetifier.core.transform.TransformationContext
+import com.google.common.truth.Truth
+import java.nio.charset.StandardCharsets
+import java.nio.file.Paths
+
+
+/**
+ * Helper to test ProGuard rewriting logic using lightweight syntax.
+ */
+object ProGuardTester {
+
+ private var javaTypes = emptyList<Pair<String, String>>()
+ private var proGuardTypes = emptyList<Pair<ProGuardType, ProGuardType>>()
+ private var prefixes = emptyList<String>()
+
+ fun forGivenPrefixes(vararg prefixes: String) : ProGuardTester {
+ this.prefixes = prefixes.toList()
+ return this
+ }
+
+ fun forGivenTypesMap(vararg rules: Pair<String, String>) : ProGuardTester {
+ this.javaTypes = rules.toList()
+ return this
+ }
+
+ fun forGivenProGuardMap(vararg rules: Pair<String, String>) : ProGuardTester {
+ this.proGuardTypes = rules.map {
+ ProGuardType.fromDotNotation(it.first) to ProGuardType.fromDotNotation(it.second) }
+ .toList()
+ return this
+ }
+
+ fun testThatGivenType(givenType: String) : ProGuardTesterForType {
+ return ProGuardTesterForType(createConfig(), givenType)
+ }
+
+ fun testThatGivenArguments(givenArgs: String) : ProGuardTesterForArgs {
+ return ProGuardTesterForArgs(createConfig(), givenArgs)
+ }
+
+ fun testThatGivenProGuard(given: String) : ProGuardTesterForFile {
+ return ProGuardTesterForFile(createConfig(), given)
+ }
+
+ private fun createConfig() : Config {
+ return Config(
+ restrictToPackagePrefixes = prefixes,
+ rewriteRules = emptyList(),
+ pomRewriteRules = emptyList(),
+ typesMap = TypesMap(
+ types = javaTypes.map { JavaType(it.first) to JavaType(it.second) }.toMap(),
+ fields = emptyMap()),
+ proGuardMap = ProGuardTypesMap(proGuardTypes.toMap()))
+ }
+
+
+ class ProGuardTesterForFile(private val config: Config, private val given: String) {
+
+ fun rewritesTo(expected: String) {
+ val context = TransformationContext(config)
+ val transformer = ProGuardTransformer(context)
+ val file = ArchiveFile(Paths.get("proguard.txt"), given.toByteArray())
+ transformer.runTransform(file)
+
+ val result = file.data.toString(StandardCharsets.UTF_8)
+
+ Truth.assertThat(result).isEqualTo(expected)
+ }
+
+ }
+
+ class ProGuardTesterForType(private val config: Config, private val given: String) {
+
+ fun getsRewrittenTo(expectedType: String) {
+ val context = TransformationContext(config)
+ val mapper = ProGuardTypesMapper(context)
+ val result = mapper.replaceType(given)
+
+ Truth.assertThat(result).isEqualTo(expectedType)
+ }
+
+ }
+
+ class ProGuardTesterForArgs(private val config: Config, private val given: String) {
+
+ fun getRewrittenTo(expectedArguments: String) {
+ val context = TransformationContext(config)
+ val mapper = ProGuardTypesMapper(context)
+ val result = mapper.replaceMethodArgs(given)
+
+ Truth.assertThat(result).isEqualTo(expectedArguments)
+ }
+ }
+
+}
+
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMapperTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMapperTest.kt
new file mode 100644
index 0000000..5e12aff
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMapperTest.kt
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import org.junit.Test
+
+class ProGuardTypesMapperTest {
+
+ @Test fun proGuard_typeMapper_wildcard_simple() {
+ ProGuardTester
+ .testThatGivenType("*")
+ .getsRewrittenTo("*")
+ }
+
+ @Test fun proGuard_typeMapper_wildcard_double() {
+ ProGuardTester
+ .testThatGivenType("**")
+ .getsRewrittenTo("**")
+ }
+
+ @Test fun proGuard_typeMapper_wildcard_composed() {
+ ProGuardTester
+ .testThatGivenType("**/*")
+ .getsRewrittenTo("**/*")
+ }
+
+ @Test fun proGuard_typeMapper_wildcard_viaMap() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenProGuardMap(
+ "support/v7/*" to "test/v7/*"
+ )
+ .testThatGivenType("support.v7.*")
+ .getsRewrittenTo("test.v7.*")
+ }
+
+ @Test fun proGuard_typeMapper_wildcard_viaMap2() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenProGuardMap(
+ "support/v7/**" to "test/v7/**"
+ )
+ .testThatGivenType("support.v7.**")
+ .getsRewrittenTo("test.v7.**")
+ }
+
+ @Test fun proGuard_typeMapper_wildcard_viaTypesMap() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/v7/Activity" to "test/v7/Activity"
+ )
+ .testThatGivenType("support.v7.Activity")
+ .getsRewrittenTo("test.v7.Activity")
+ }
+
+ @Test fun proGuard_typeMapper_wildcard_notFoundInMap() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenProGuardMap(
+ "support/**" to "test/**"
+ )
+ .testThatGivenType("keep.me.**")
+ .getsRewrittenTo("keep.me.**")
+ }
+
+ @Test fun proGuard_typeMapper_differentPrefix_notRewritten() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "hello/Activity" to "test/Activity"
+ )
+ .testThatGivenType("hello.Activity")
+ .getsRewrittenTo("hello.Activity")
+ }
+
+ @Test fun proGuard_typeMapper_differentPrefix_wildcard_getsRewritten() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenProGuardMap(
+ "hello/**" to "test/**"
+ )
+ .testThatGivenType("hello.**")
+ .getsRewrittenTo("test.**")
+ }
+
+ @Test fun proGuard_typeMapper_innerClass() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity\$InnerClass" to "test/Activity\$InnerClass"
+ )
+ .testThatGivenType("support.Activity\$InnerClass")
+ .getsRewrittenTo("test.Activity\$InnerClass")
+ }
+
+ @Test fun proGuard_typeMapper_innerClass_wildcard() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenProGuardMap(
+ "**R\$Attrs" to "**R2\$Attrs"
+ )
+ .testThatGivenType("**R\$Attrs")
+ .getsRewrittenTo("**R2\$Attrs")
+ }
+
+ @Test fun proGuard_argsMapper_tripleDots() {
+ ProGuardTester
+ .testThatGivenArguments("...")
+ .getRewrittenTo("...")
+ }
+
+ @Test fun proGuard_argsMapper_wildcard() {
+ ProGuardTester
+ .testThatGivenArguments("*")
+ .getRewrittenTo("*")
+ }
+
+ @Test fun proGuard_argsMapper_wildcards() {
+ ProGuardTester
+ .testThatGivenArguments("**, **")
+ .getRewrittenTo("**, **")
+ }
+
+ @Test fun proGuard_argsMapper_viaMaps() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity"
+ )
+ .forGivenProGuardMap(
+ "support/v7/**" to "test/v7/**"
+ )
+ .testThatGivenArguments("support.Activity, support.v7.**, keep.Me")
+ .getRewrittenTo("test.Activity, test.v7.**, keep.Me")
+ }
+
+ @Test fun proGuard_argsMapper_viaMaps_spaces() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity"
+ )
+ .forGivenProGuardMap(
+ "support/v7/**" to "test/v7/**"
+ )
+ .testThatGivenArguments(" support.Activity , \t support.v7.**, keep.Me ")
+ .getRewrittenTo("test.Activity, test.v7.**, keep.Me")
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProguardSamplesTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProguardSamplesTest.kt
new file mode 100644
index 0000000..0542e7d
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProguardSamplesTest.kt
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.proguard
+
+import org.junit.Test
+
+class ProguardSamplesTest {
+
+ @Test fun proGuard_sample() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "android/app/",
+ "android/view/",
+ "android/content/",
+ "android/os/",
+ "android/webkit/"
+ )
+ .forGivenTypesMap(
+ "android/app/Activity" to "test/app/Activity",
+ "android/app/Application" to "test/app/Application",
+ "android/view/View" to "test/view/View",
+ "android/view/MenuItem" to "test/view/MenuItem",
+ "android/content/Context" to "test/content/Context",
+ "android/os/Parcelable" to "test/os/Parcelable",
+ "android/webkit/JavascriptInterface" to "test/webkit/JavascriptInterface"
+ )
+ .testThatGivenProGuard(
+ "-injars bin/classes \n" +
+ "-injars libs \n" +
+ "-outjars bin/classes-processed.jar \n" +
+ "-libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar \n" +
+ "\n" +
+ "-dontpreverify \n" +
+ "-repackageclasses '' \n" +
+ "-allowaccessmodification \n" +
+ "-optimizations !code/simplification/arithmetic \n" +
+ "-keepattributes *Annotation* \n" +
+ "\n" +
+ "-keep public class * extends android.app.Activity \n" +
+ "-keep public class * extends android.app.Application \n" +
+ " \n" +
+ "-keep public class * extends android.view.View { \n" +
+ " public <init>(android.content.Context); \n" +
+ " public <init>(android.content.Context, android.util.AttributeSet); \n" +
+ " public <init>(android.content.Context, android.util.AttributeSet, int); \n" +
+ " public void set*(...); \n" +
+ "} \n" +
+ "\n" +
+ "-keepclasseswithmembers class * { \n" +
+ " public <init>(android.content.Context, android.util.AttributeSet); \n" +
+ "} \n" +
+ "\n" +
+ "-keepclasseswithmembers class * { \n" +
+ " public <init>(android.content.Context, android.util.AttributeSet, int); \n" +
+ "} \n" +
+ "\n" +
+ "-keepclassmembers class * extends android.content.Context { \n" +
+ " public void *(android.view.View); \n" +
+ " public void *(android.view.MenuItem); \n" +
+ "} \n" +
+ "\n" +
+ "-keepclassmembers class * implements android.os.Parcelable { \n" +
+ " static ** CREATOR; \n" +
+ "} \n" +
+ "\n" +
+ "-keepclassmembers class **.R\$* { \n" +
+ " public static <fields>; \n" +
+ "} \n" +
+ "\n" +
+ "-keepclassmembers class * { \n" +
+ " @android.webkit.JavascriptInterface <methods>; \n" +
+ "} "
+ )
+ .rewritesTo(
+ "-injars bin/classes \n" +
+ "-injars libs \n" +
+ "-outjars bin/classes-processed.jar \n" +
+ "-libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar \n" +
+ "\n" +
+ "-dontpreverify \n" +
+ "-repackageclasses '' \n" +
+ "-allowaccessmodification \n" +
+ "-optimizations !code/simplification/arithmetic \n" +
+ "-keepattributes *Annotation* \n" +
+ "\n" +
+ "-keep public class * extends test.app.Activity \n" +
+ "-keep public class * extends test.app.Application \n" +
+ " \n" +
+ "-keep public class * extends test.view.View { \n" +
+ " public <init>(test.content.Context); \n" +
+ " public <init>(test.content.Context, android.util.AttributeSet); \n" +
+ " public <init>(test.content.Context, android.util.AttributeSet, int); \n" +
+ " public void set*(...); \n" +
+ "} \n" +
+ "\n" +
+ "-keepclasseswithmembers class * { \n" +
+ " public <init>(test.content.Context, android.util.AttributeSet); \n" +
+ "} \n" +
+ "\n" +
+ "-keepclasseswithmembers class * { \n" +
+ " public <init>(test.content.Context, android.util.AttributeSet, int); \n" +
+ "} \n" +
+ "\n" +
+ "-keepclassmembers class * extends test.content.Context { \n" +
+ " public void *(test.view.View); \n" +
+ " public void *(test.view.MenuItem); \n" +
+ "} \n" +
+ "\n" +
+ "-keepclassmembers class * implements test.os.Parcelable { \n" +
+ " static ** CREATOR; \n" +
+ "} \n" +
+ "\n" +
+ "-keepclassmembers class **.R\$* { \n" +
+ " public static <fields>; \n" +
+ "} \n" +
+ "\n" +
+ "-keepclassmembers class * { \n" +
+ " @test.webkit.JavascriptInterface <methods>; \n" +
+ "} "
+ )
+ }
+
+ @Test fun proGuard_sample2() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "android/support/v7/"
+ )
+ .forGivenTypesMap(
+ "android/support/v7/preference/Preference" to "test/Preference"
+ )
+ .testThatGivenProGuard(
+ "-keep public class android.support.v7.preference.Preference {\n" +
+ " public <init>(android.content.Context, android.util.AttributeSet);\n" +
+ "}\n" +
+ "-keep public class * extends android.support.v7.preference.Preference {\n" +
+ " public <init>(android.content.Context, android.util.AttributeSet);\n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class test.Preference {\n" +
+ " public <init>(android.content.Context, android.util.AttributeSet);\n" +
+ "}\n" +
+ "-keep public class * extends test.Preference {\n" +
+ " public <init>(android.content.Context, android.util.AttributeSet);\n" +
+ "}"
+ )
+ }
+
+ @Test fun proGuard_sample3() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "android/support/design/",
+ "android/support/v7/"
+ )
+ .forGivenTypesMap(
+ "support/Fragment" to "test/Fragment",
+ "android/support/v7/widget/RoundRectDrawable" to "test/RoundRectDrawable"
+ )
+ .forGivenProGuardMap(
+ "android/support/design.**" to "test/design.**",
+ "android/support/design/R\$*" to "test/design/R\$*"
+ )
+ .testThatGivenProGuard(
+ "-dontwarn android.support.design.**\n" +
+ "-keep class android.support.design.** { *; }\n" +
+ "-keep interface android.support.design.** { *; }\n" +
+ "-keep public class android.support.design.R\$* { *; }\n" +
+ "-keep class android.support.v7.widget.RoundRectDrawable { *; }"
+ )
+ .rewritesTo(
+ "-dontwarn test.design.**\n" +
+ "-keep class test.design.** { *; }\n" +
+ "-keep interface test.design.** { *; }\n" +
+ "-keep public class test.design.R\$* { *; }\n" +
+ "-keep class test.RoundRectDrawable { *; }"
+ )
+ }
+
+ @Test fun proGuard_sample4() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "android/support/design/",
+ "android/support/v7/",
+ "android/support/v4/"
+ )
+ .forGivenTypesMap(
+ "android/support/v7/widget/LinearLayoutManager" to "test/LinearLayoutManager",
+ "android/support/v4/view/ActionProvider" to "test/ActionProvider"
+ )
+ .forGivenProGuardMap(
+ "android/support/v7/**" to "test/v7/**",
+ "android/support/v7/widget/**" to "test/v7/widget/**",
+ "android/support/v7/internal/widget/**" to "test/v7/internal/widget/**",
+ "android/support/v7/internal/**" to "test/v7/internal/**"
+ )
+ .testThatGivenProGuard(
+ "-dontwarn android.support.v7.**\n" +
+ "-keep public class android.support.v7.widget.** { *; }\n" +
+ "-keep public class android.support.v7.internal.widget.** { *; }\n" +
+ "-keep class android.support.v7.widget.LinearLayoutManager { *; }\n" +
+ "-keep class android.support.v7.internal.** { *; }\n" +
+ "-keep interface android.support.v7.internal.** { *; }\n" +
+ "\n" +
+ "-keep class android.support.v7.** { *; }\n" +
+ "-keep interface android.support.v7.** { *; }\n" +
+ "\n" +
+ "-keep public class * extends android.support.v4.view.ActionProvider {\n" +
+ " public <init>(android.content.Context);"
+ )
+ .rewritesTo(
+ "-dontwarn test.v7.**\n" +
+ "-keep public class test.v7.widget.** { *; }\n" +
+ "-keep public class test.v7.internal.widget.** { *; }\n" +
+ "-keep class test.LinearLayoutManager { *; }\n" +
+ "-keep class test.v7.internal.** { *; }\n" +
+ "-keep interface test.v7.internal.** { *; }\n" +
+ "\n" +
+ "-keep class test.v7.** { *; }\n" +
+ "-keep interface test.v7.** { *; }\n" +
+ "\n" +
+ "-keep public class * extends test.ActionProvider {\n" +
+ " public <init>(android.content.Context);"
+ )
+ }
+
+ @Test fun proGuard_sample5() {
+ ProGuardTester
+ .forGivenPrefixes(
+ "support/"
+ )
+ .forGivenTypesMap(
+ "support/Activity" to "test/Activity",
+ "support/Fragment" to "test/Fragment",
+ "support/Annotation" to "test/Annotation"
+ )
+ .testThatGivenProGuard(
+ "-keep public class * extends support.Activity { \n" +
+ " public static <fields>; \n" +
+ " public !static <methods>; \n" +
+ " public support.Fragment height; \n" +
+ " public static <fields>; \n" +
+ " public not.related.Type width; public support.Fragment width; \n" +
+ " ignoreMe; \n" +
+ " @support.Annotation public support.Fragment get(); \n" +
+ "}"
+ )
+ .rewritesTo(
+ "-keep public class * extends test.Activity { \n" +
+ " public static <fields>; \n" +
+ " public !static <methods>; \n" +
+ " public test.Fragment height; \n" +
+ " public static <fields>; \n" +
+ " public not.related.Type width; public test.Fragment width; \n" +
+ " ignoreMe; \n" +
+ " @test.Annotation public test.Fragment get(); \n" +
+ "}"
+ )
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformerTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformerTest.kt
new file mode 100644
index 0000000..5788b40
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformerTest.kt
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.core.transform.resource
+
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.rules.JavaType
+import android.support.tools.jetifier.core.map.TypesMap
+import android.support.tools.jetifier.core.transform.TransformationContext
+import android.support.tools.jetifier.core.transform.proguard.ProGuardTypesMap
+import com.google.common.truth.Truth
+import org.junit.Test
+import java.nio.charset.Charset
+
+class XmlResourcesTransformerTest {
+
+ @Test fun layout_noPrefix_noChange() {
+ testRewriteToTheSame(
+ givenAndExpectedXml =
+ "<android.support.v7.preference.Preference>\n" +
+ "</android.support.v7.preference.Preference>",
+ prefixes = listOf(),
+ map = mapOf(
+ "android/support/v7/preference/Preference" to "android/test/pref/Preference"
+ )
+ )
+ }
+
+ @Test fun layout_noRule_noChange() {
+ testRewriteToTheSame(
+ givenAndExpectedXml =
+ "<android.support.v7.preference.Preference>\n" +
+ "</android.support.v7.preference.Preference>",
+ prefixes = listOf("android/support/v7/"),
+ map = mapOf()
+ )
+ }
+
+ @Test fun layout_notApplicablePrefix_noChange() {
+ testRewriteToTheSame(
+ givenAndExpectedXml =
+ "<android.support.v7.preference.Preference>\n" +
+ "</android.support.v7.preference.Preference>",
+ prefixes = listOf("android/support/v14/"),
+ map = mapOf(
+ "android/support/v7/preference/Preference" to "android/test/pref/Preference"
+ )
+ )
+ }
+
+ @Test fun layout_notApplicablePrefix2_noChange() {
+ testRewriteToTheSame(
+ givenAndExpectedXml =
+ "<my.android.support.v7.preference.Preference>\n" +
+ "</my.android.support.v7.preference.Preference>",
+ prefixes = listOf("android/support/v7/"),
+ map = mapOf(
+ "android/support/v7/preference/Preference" to "android/test/pref/Preference"
+ )
+ )
+ }
+
+ @Test fun layout_notApplicableRule_noChange() {
+ testRewriteToTheSame(
+ givenAndExpectedXml =
+ "<android.support.v7.preference.Preference>\n" +
+ "</android.support.v7.preference.Preference>",
+ prefixes = listOf("android/support/"),
+ map = mapOf(
+ "android/support2/v7/preference/Preference" to "android/test/pref/Preference"
+ )
+ )
+ }
+
+ @Test fun layout_onePrefix_oneRule_oneRewrite() {
+ testRewrite(
+ givenXml =
+ "<android.support.v7.preference.Preference/>",
+ expectedXml =
+ "<android.test.pref.Preference/>",
+ prefixes = listOf("android/support/"),
+ map = mapOf(
+ "android/support/v7/preference/Preference" to "android/test/pref/Preference"
+ )
+ )
+ }
+
+ @Test fun layout_onePrefix_oneRule_attribute_oneRewrite() {
+ testRewrite(
+ givenXml =
+ "<android.support.v7.preference.Preference \n" +
+ " someAttribute=\"android.support.v7.preference.Preference\"/>",
+ expectedXml =
+ "<android.test.pref.Preference \n" +
+ " someAttribute=\"android.support.v7.preference.Preference\"/>",
+ prefixes = listOf("android/support/"),
+ map = mapOf(
+ "android/support/v7/preference/Preference" to "android/test/pref/Preference"
+ )
+ )
+ }
+
+ @Test fun layout_onePrefix_oneRule_twoRewrites() {
+ testRewrite(
+ givenXml =
+ "<android.support.v7.preference.Preference>\n" +
+ "</android.support.v7.preference.Preference>",
+ expectedXml =
+ "<android.test.pref.Preference>\n" +
+ "</android.test.pref.Preference>",
+ prefixes = listOf("android/support/"),
+ map = mapOf(
+ "android/support/v7/preference/Preference" to "android/test/pref/Preference"
+ )
+ )
+ }
+
+ @Test fun layout_onePrefix_oneRule_viewTag_simple() {
+ testRewrite(
+ givenXml =
+ "<view class=\"android.support.v7.preference.Preference\">",
+ expectedXml =
+ "<view class=\"android.test.pref.Preference\">",
+ prefixes = listOf("android/support/"),
+ map = mapOf(
+ "android/support/v7/preference/Preference" to "android/test/pref/Preference"
+ )
+ )
+ }
+
+ @Test fun layout_onePrefix_oneRule_viewTag_stuffAround() {
+ testRewrite(
+ givenXml =
+ "<view notRelated=\"true\" " +
+ " class=\"android.support.v7.preference.Preference\"" +
+ " ignoreMe=\"android.support.v7.preference.Preference\">",
+ expectedXml =
+ "<view notRelated=\"true\" " +
+ " class=\"android.test.pref.Preference\"" +
+ " ignoreMe=\"android.support.v7.preference.Preference\">",
+ prefixes = listOf("android/support/"),
+ map = mapOf(
+ "android/support/v7/preference/Preference" to "android/test/pref/Preference"
+ )
+ )
+ }
+
+ @Test fun layout_onePrefix_oneRule_viewInText_notMatched() {
+ testRewriteToTheSame(
+ givenAndExpectedXml =
+ "<test attribute=\"view\" class=\"android.support.v7.preference.Preference\">",
+ prefixes = listOf("android/support/"),
+ map = mapOf(
+ "android/support/v7/preference/Preference" to "android/test/pref/Preference"
+ )
+ )
+ }
+
+ @Test fun layout_onePrefix_oneRule_identity() {
+ testRewrite(
+ givenXml =
+ "<android.support.v7.preference.Preference>\n" +
+ "</android.support.v7.preference.Preference>",
+ expectedXml =
+ "<android.support.v7.preference.Preference>\n" +
+ "</android.support.v7.preference.Preference>",
+ prefixes = listOf("android/support/"),
+ map = mapOf(
+ "android/support/v7/preference/Preference" to "android/support/v7/preference/Preference"
+ )
+ )
+ }
+
+ @Test fun layout_twoPrefixes_threeRules_multipleRewrites() {
+ testRewrite(
+ givenXml =
+ "<android.support.v7.preference.Preference>\n" +
+ " <android.support.v14.preference.DialogPreference" +
+ " someAttribute=\"someValue\"/>\n" +
+ " <android.support.v14.preference.DialogPreference" +
+ " someAttribute=\"someValue2\"/>\n" +
+ " <!-- This one should be ignored --> \n" +
+ " <android.support.v21.preference.DialogPreference" +
+ " someAttribute=\"someValue2\"/>\n" +
+ "</android.support.v7.preference.Preference>\n" +
+ "\n" +
+ "<android.support.v7.preference.ListPreference/>",
+ expectedXml =
+ "<android.test.pref.Preference>\n" +
+ " <android.test14.pref.DialogPreference" +
+ " someAttribute=\"someValue\"/>\n" +
+ " <android.test14.pref.DialogPreference" +
+ " someAttribute=\"someValue2\"/>\n" +
+ " <!-- This one should be ignored --> \n" +
+ " <android.support.v21.preference.DialogPreference" +
+ " someAttribute=\"someValue2\"/>\n" +
+ "</android.test.pref.Preference>\n" +
+ "\n" +
+ "<android.test.pref.ListPref/>",
+ prefixes = listOf(
+ "android/support/v7/",
+ "android/support/v14/"
+ ),
+ map = mapOf(
+ "android/support/v7/preference/ListPreference" to "android/test/pref/ListPref",
+ "android/support/v7/preference/Preference" to "android/test/pref/Preference",
+ "android/support/v14/preference/DialogPreference" to "android/test14/pref/DialogPreference",
+ "android/support/v21/preference/DialogPreference" to "android/test21/pref/DialogPreference"
+ )
+ )
+ }
+
+ private fun testRewriteToTheSame(givenAndExpectedXml: String,
+ prefixes: List<String>,
+ map: Map<String, String>) {
+ testRewrite(givenAndExpectedXml, givenAndExpectedXml, prefixes, map)
+ }
+
+ private fun testRewrite(givenXml : String,
+ expectedXml : String,
+ prefixes: List<String>,
+ map: Map<String, String>) {
+ val given =
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
+ "$givenXml\n"
+
+ val expected =
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
+ "$expectedXml\n"
+
+ val typesMap = TypesMap(map.map{ JavaType(it.key) to JavaType(it.value) }.toMap(),
+ emptyMap())
+ val config = Config(prefixes, emptyList(), emptyList(), typesMap, ProGuardTypesMap.EMPTY)
+ val context = TransformationContext(config)
+ val processor = XmlResourcesTransformer(context)
+ val result = processor.transform(given.toByteArray())
+ val strResult = result.toString(Charset.defaultCharset())
+
+ Truth.assertThat(strResult).isEqualTo(expected)
+ }
+}
+
diff --git a/jetifier/jetifier/gradle-plugin/build.gradle b/jetifier/jetifier/gradle-plugin/build.gradle
new file mode 100644
index 0000000..ca24b72
--- /dev/null
+++ b/jetifier/jetifier/gradle-plugin/build.gradle
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 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
+ */
+
+version '0.1'
+
+apply plugin: 'maven-publish'
+
+dependencies {
+ compile project(':core')
+ compileOnly gradleApi()
+}
+
+// Task to create a jar with all the required dependencies bundled inside
+task fatJar(type: Jar) {
+ baseName = project.name + '-all'
+ destinationDir = rootProject.ext.distDir
+ from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } }
+ with jar
+}
+
+publishing {
+ publications {
+ mavenJava(MavenPublication) {
+ from components.java
+ }
+ }
+}
diff --git a/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifierExtension.kt b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifierExtension.kt
new file mode 100644
index 0000000..7b516ec
--- /dev/null
+++ b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifierExtension.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.plugin.gradle
+
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.artifacts.Dependency
+import org.gradle.api.file.FileCollection
+import java.nio.file.Paths
+
+/**
+ * Defines methods that can be used in gradle on the "jetifier" object and triggers [JetifyLibsTask]
+ * or [JetifyGlobalTask] based on its usage.
+ */
+open class JetifierExtension(val project: Project) {
+
+ /**
+ * Adds dependency defined via string notation to be processed by jetifyLibs task.
+ *
+ *
+ * Example usage in Gradle:
+ * dependencies {
+ * compile jetifier.process('groupId:artifactId:1.0')
+ * }
+ */
+ fun process(dependencyNotation: String): FileCollection {
+ return process(project.dependencies.create(dependencyNotation))
+ }
+
+ /**
+ * Adds dependency defined via string notation to be processed by jetifyLibs task while also
+ * applying the given exclude rules.
+ *
+ *
+ * Example usage in Gradle:
+ * dependencies {
+ * compile jetifier.processAndExclude('groupId:artifactId:1.0',
+ * [group: 'some.package', module: 'moduleName'])
+ * }
+ */
+ fun processAndExclude(
+ dependencyNotation: String,
+ vararg excludes: Map<String, String>
+ ): FileCollection {
+ return processAndExclude(project.dependencies.create(dependencyNotation), *excludes)
+ }
+
+ /**
+ * Adds dependency to be processed by jetifyLibs task.
+ */
+ fun process(dependency: Dependency): FileCollection {
+ val configuration = project.configurations.detachedConfiguration()
+ configuration.dependencies.add(dependency)
+ return process(configuration)
+ }
+
+ /**
+ * Adds dependency to be processed by jetifyLibs task while also applying the given excludes
+ * rules.
+ */
+ fun processAndExclude(
+ dependency: Dependency,
+ vararg excludes: Map<String, String>
+ ): FileCollection {
+ val configuration = project.configurations.detachedConfiguration()
+ configuration.dependencies.add(dependency)
+ excludes.forEach { configuration.exclude(it) }
+ return process(configuration)
+ }
+
+ /**
+ * Adds dependencies defined via file collection to be processed by jetifyLibs task.
+ *
+ * Example usage in Gradle for a single file:
+ * dependencies {
+ * compile jetifier.process(files('../myFile1.jar'))
+ * compile jetifier.process(files('../myFile2.jar'))
+ * }
+ *
+ * Example usage in Gradle for a configuration:
+ * configurations.create('depToRefactor')
+ *
+ * dependencies {
+ * depToRefactor 'test:myDependency:1.0'
+ * depToRefactor 'test:myDependency2:1.0'
+ * }
+ *
+ * dependencies {
+ * compile jetifier.process(configurations.depToRefactor)
+ * }
+ */
+ fun process(files: FileCollection): FileCollection {
+ return JetifyLibsTask.resolveTask(project).addFilesToProcess(files)
+ }
+
+ /**
+ * Adds a whole configuration to be processed by jetifyGlobal task. This is the recommended way
+ * if processing a set of dependencies where it is unknown which exactly need to be rewritten.
+ *
+ * This will create a new detached configuration and resolve all the dependencies = obtaining
+ * all the files. Jetifier is then run with all the files and only the files that were rewritten
+ * are added to the given configuration and the original dependencies that didn't have to be
+ * changed are kept.
+ *
+ * Advantage is that all the dependencies that didn't have to be changed are kept intact so
+ * their artifactsIds and groupIds are kept (instead of replacing them with files) which allows
+ * other steps in the build process to use the artifacts information to generate pom files
+ * and other stuff.
+ *
+ * This will NOT resolve the given configuration as the dependencies are resolved in a detached
+ * configuration. If you give it a configuration that was already resolved the process will
+ * end up with exception saying that resolved configuration cannot be changed. This is expected
+ * as Jetifier cannot add new files to an already resolved configuration.
+ *
+ *
+ * Example usage in Gradle:
+ * jetifier.addConfigurationToProcess(configurations.implementation)
+ * afterEvaluate {
+ * tasks.preBuild.dependsOn tasks.jetifyGlobal
+ * }
+ *
+ *
+ */
+ fun addConfigurationToProcess(config: Configuration) {
+ JetifyGlobalTask.resolveTask(project).addConfigurationToProcess(config)
+ }
+
+ /**
+ * Sets a custom configuration file to be used by Jetifier.
+ */
+ fun setConfigFile(configFilePath: String) {
+ TasksCommon.configFilePath = Paths.get(configFilePath)
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifierLoggerAdapter.kt b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifierLoggerAdapter.kt
new file mode 100644
index 0000000..9d85851
--- /dev/null
+++ b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifierLoggerAdapter.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.plugin.gradle
+
+import android.support.tools.jetifier.core.utils.LogConsumer
+import org.gradle.api.logging.Logger
+
+/**
+ * Logging adapter to hook jetfier logging into gradle.
+ */
+class JetifierLoggerAdapter(val gradleLogger: Logger) : LogConsumer {
+
+ override fun error(message: String) {
+ gradleLogger.error(message)
+ }
+
+ override fun info(message: String) {
+ gradleLogger.info(message)
+ }
+
+ override fun verbose(message: String) {
+ gradleLogger.info(message)
+ }
+
+ override fun debug(message: String) {
+ gradleLogger.debug(message)
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifierPlugin.kt b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifierPlugin.kt
new file mode 100644
index 0000000..109e4c4
--- /dev/null
+++ b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifierPlugin.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.plugin.gradle
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+
+/**
+ * This serves as the main entry point of this plugin and registers the extension object.
+ */
+open class JetifierPlugin : Plugin<Project> {
+
+ companion object {
+ const val GROOVY_OBJECT_NAME : String = "jetifier"
+ }
+
+ override fun apply(project: Project) {
+ project.extensions.create(GROOVY_OBJECT_NAME, JetifierExtension::class.java, project)
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifyGlobalTask.kt b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifyGlobalTask.kt
new file mode 100644
index 0000000..4d35625
--- /dev/null
+++ b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifyGlobalTask.kt
@@ -0,0 +1,136 @@
+package android.support.tools.jetifier.plugin.gradle
+
+import android.support.tools.jetifier.core.config.ConfigParser
+import org.gradle.api.DefaultTask
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.artifacts.Dependency
+import org.gradle.api.artifacts.FileCollectionDependency
+import org.gradle.api.artifacts.ProjectDependency
+import org.gradle.api.logging.LogLevel
+import org.gradle.api.tasks.TaskAction
+import java.io.File
+
+/**
+ * Task that processes whole configurations. This is the recommended way if processing a set of
+ * dependencies where it is unknown which exactly need to be rewritten.
+ *
+ * This will create a new detached configuration and resolve all the dependencies = obtaining
+ * all the files. Jetifier is then run with all the files and only the files that were rewritten
+ * are added to the given configuration and the original dependencies that didn't have to be
+ * changed are kept.
+ *
+ * Advantage is that all the dependencies that didn't have to be changed are kept intact so
+ * their artifactsIds and groupIds are kept (instead of replacing them with files) which allows
+ * other steps in the build process to use the artifacts information to generate pom files
+ * and other stuff.
+ *
+ * This will NOT resolve the given configurations as the dependencies are resolved in a detached
+ * configuration. If you give it a configuration that was already resolved the process will
+ * end up with exception saying that resolved configuration cannot be changed. This is expected
+ * as Jetifier cannot add new files to an already resolved configuration.
+ *
+ * Example usage in Gradle:
+ * jetifier.addConfigurationToProcess(configurations.implementation)
+ * afterEvaluate {
+ * tasks.preBuild.dependsOn tasks.jetifyGlobal
+ * }
+ *
+ * TODO: Add caching for this task
+ */
+open class JetifyGlobalTask : DefaultTask() {
+
+ companion object {
+ const val TASK_NAME = "jetifyGlobal"
+ const val GROUP_ID = "Pre-build"
+ // TODO: Get back to this once the name of the library is decided.
+ const val DESCRIPTION = "Rewrites input libraries to run with jetpack"
+
+ const val OUTPUT_DIR_APPENDIX = "jetifier"
+
+ fun resolveTask(project: Project) : JetifyGlobalTask {
+ val task = project.tasks.findByName(TASK_NAME) as? JetifyGlobalTask
+ if (task != null) {
+ return task
+ }
+ return project.tasks.create(TASK_NAME, JetifyGlobalTask::class.java)
+ }
+ }
+
+ private var configurationsToProcess = mutableListOf<Configuration>()
+
+ private val outputDir = File(project.buildDir, OUTPUT_DIR_APPENDIX)
+
+
+ override fun getGroup() = GROUP_ID
+
+ override fun getDescription() = DESCRIPTION
+
+ /**
+ * Add a whole configuration to be processed by Jetifier.
+ *
+ * See [JetifierExtension] for details on how to use this.
+ */
+ fun addConfigurationToProcess(config: Configuration) {
+ configurationsToProcess.add(config)
+ }
+
+ @TaskAction
+ @Throws(Exception::class)
+ fun run() {
+ val config = ConfigParser.loadConfigOrFail(TasksCommon.configFilePath)
+
+ val dependenciesMap = mutableMapOf<File, MutableSet<Dependency>>()
+ // Build a map where for each file we have a set of dependencies that pulled that file in.
+ configurationsToProcess.forEach { conf ->
+ for (dep in conf.dependencies) {
+ if (dep is ProjectDependency) {
+ project.logger.log(LogLevel.DEBUG, "Ignoring project dependency {}", dep.name)
+ continue
+ }
+
+ val fileDep = dep as? FileCollectionDependency
+ if (fileDep != null) {
+ fileDep.files.forEach {
+ dependenciesMap
+ .getOrPut(it, { mutableSetOf<Dependency>() } )
+ .add(fileDep)
+ }
+ } else {
+ if (TasksCommon.shouldSkipArtifact(dep.name, dep.group, config)) {
+ project.logger.log(
+ LogLevel.DEBUG, "Skipping rewriting of support library {}:{}:{}",
+ dep.group, dep.name, dep.version)
+ continue
+ }
+
+ val detached = project.configurations.detachedConfiguration()
+ detached.dependencies.add(dep)
+ detached.resolvedConfiguration.resolvedArtifacts.forEach {
+ dependenciesMap
+ .getOrPut(it.file, { mutableSetOf<Dependency>() } )
+ .add(dep)
+ }
+ }
+ }
+ }
+
+ // Process the files using Jetifier
+ val result = TasksCommon.processFiles(config, dependenciesMap.keys, project.logger, outputDir)
+
+ // Apply changes
+ configurationsToProcess.forEach { conf ->
+ // Apply that on our set
+ result.filesToRemove.forEach { file ->
+ dependenciesMap[file]!!.forEach {
+ conf.dependencies.remove(it)
+ }
+ }
+
+ result.filesToAdd.forEach {
+ project.dependencies.add(conf.name, project.files(it))
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifyLibsTask.kt b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifyLibsTask.kt
new file mode 100644
index 0000000..873c8ec
--- /dev/null
+++ b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifyLibsTask.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.plugin.gradle
+
+import android.support.tools.jetifier.core.config.ConfigParser
+import org.gradle.api.DefaultTask
+import org.gradle.api.Project
+import org.gradle.api.file.FileCollection
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.TaskAction
+import java.io.File
+
+/**
+ * Task that processes given file collections using Jetifier.
+ *
+ * This task also utilizes Gradle caching so it's run only when needed.
+ *
+ * Example usage in Gradle:
+ * dependencies {
+ * compile jetifier.process('groupId:artifactId:1.0')
+ * }
+ */
+open class JetifyLibsTask : DefaultTask() {
+
+ companion object {
+ const val TASK_NAME = "jetifyLibs"
+ const val GROUP_ID = "Pre-build"
+ // TODO: Get back to this once the name of the library is decided.
+ const val DESCRIPTION = "Rewrites input libraries to run with jetpack"
+
+ const val OUTPUT_DIR_APPENDIX = "jetifier"
+
+
+ fun resolveTask(project: Project) : JetifyLibsTask {
+ val task = project.tasks.findByName(TASK_NAME) as? JetifyLibsTask
+ if (task != null) {
+ return task
+ }
+ return project.tasks.create(TASK_NAME, JetifyLibsTask::class.java)
+ }
+
+ }
+
+ private var filesToProcess : FileCollection = project.files()
+
+ private val outputDir = File(project.buildDir, OUTPUT_DIR_APPENDIX)
+
+
+ override fun getGroup() = GROUP_ID
+
+ override fun getDescription() = DESCRIPTION
+
+ /**
+ * Adds individual files collection to be processed by Jetifier.
+ *
+ * See [JetifierExtension] for details on how to use this.
+ */
+ fun addFilesToProcess(files: FileCollection) : FileCollection {
+ filesToProcess = filesToProcess.plus(files)
+ return project.files(files.map { File(outputDir, it.name) }.toList())
+ }
+
+ /**
+ * Used by Gradle to figure out whether this task should be re-run. If the result of this method
+ * is different then the task is re-run.
+ */
+ @InputFiles
+ fun getInputFiles() : FileCollection {
+ return filesToProcess
+ }
+
+ /**
+ * Used by Gradle to figure out whether this task should be re-run and if other tasks that are
+ * relying on files from this directory should be re-run. Actually not having this and only
+ * having [InputFiles] annotation would disable the whole incremental mechanism for this task
+ * and lead to constant re-runs.
+ */
+ @OutputDirectory
+ fun getOutputDir() : File {
+ return outputDir
+ }
+
+ @TaskAction
+ @Throws(Exception::class)
+ fun run() {
+ val config = ConfigParser.loadConfigOrFail(TasksCommon.configFilePath)
+
+ // Process the files using Jetifier
+ TasksCommon.processFiles(config, filesToProcess.toSet(), project.logger, outputDir)
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/TasksCommon.kt b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/TasksCommon.kt
new file mode 100644
index 0000000..dcc6375
--- /dev/null
+++ b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/TasksCommon.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.plugin.gradle
+
+import android.support.tools.jetifier.core.Processor
+import android.support.tools.jetifier.core.TransformationResult
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.utils.Log
+import org.gradle.api.logging.LogLevel
+import org.gradle.api.logging.Logger
+import java.io.File
+import java.nio.file.Path
+
+class TasksCommon {
+
+ companion object {
+
+ var configFilePath: Path? = null
+
+
+ fun processFiles(config: Config, filesToProcess: Set<File>, logger: Logger, outputDir: File) : TransformationResult {
+ outputDir.mkdirs()
+
+ logger.log(LogLevel.DEBUG, "Jetifier will now process the following files:")
+ filesToProcess.forEach {
+ logger.log(LogLevel.DEBUG, it.absolutePath)
+ }
+
+ // Hook to the gradle logger
+ Log.logConsumer = JetifierLoggerAdapter(logger)
+
+ val processor = Processor(config)
+ return processor.transform(filesToProcess, outputDir.toPath())
+ }
+
+ fun shouldSkipArtifact(artifactId: String, groupId: String?, config: Config) : Boolean {
+ return config.pomRewriteRules.any {
+ it.from.artifactId == artifactId && it.from.groupId == groupId
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/gradle-plugin/src/main/resources/META-INF/gradle-plugins/androidx.tools.jetifier.properties b/jetifier/jetifier/gradle-plugin/src/main/resources/META-INF/gradle-plugins/androidx.tools.jetifier.properties
new file mode 100644
index 0000000..7ee7e73
--- /dev/null
+++ b/jetifier/jetifier/gradle-plugin/src/main/resources/META-INF/gradle-plugins/androidx.tools.jetifier.properties
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 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
+#
+
+implementation-class=android.support.tools.jetifier.plugin.gradle.JetifierPlugin
\ No newline at end of file
diff --git a/jetifier/jetifier/gradle/wrapper/gradle-wrapper.jar b/jetifier/jetifier/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..2411732
--- /dev/null
+++ b/jetifier/jetifier/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/jetifier/jetifier/gradle/wrapper/gradle-wrapper.properties b/jetifier/jetifier/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..452b52a
--- /dev/null
+++ b/jetifier/jetifier/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=../../../../../../tools/external/gradle/gradle-4.3-bin.zip
diff --git a/jetifier/jetifier/gradlew b/jetifier/jetifier/gradlew
new file mode 100755
index 0000000..04fca86
--- /dev/null
+++ b/jetifier/jetifier/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save ( ) {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when runTransform from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/jetifier/jetifier/gradlew.bat b/jetifier/jetifier/gradlew.bat
new file mode 100644
index 0000000..e95643d
--- /dev/null
+++ b/jetifier/jetifier/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/jetifier/jetifier/preprocessor/build.gradle b/jetifier/jetifier/preprocessor/build.gradle
new file mode 100644
index 0000000..b688a9d
--- /dev/null
+++ b/jetifier/jetifier/preprocessor/build.gradle
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 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
+ */
+
+version '1.0'
+
+apply plugin: "application"
+
+mainClassName = "android.support.tools.jetifier.preprocessor.MainKt"
+
+dependencies {
+ compile project(':core')
+ compile group: 'commons-cli', name: 'commons-cli', version: '1.3.1'
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh b/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh
new file mode 100644
index 0000000..d451c76
--- /dev/null
+++ b/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# Copyright (C) 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
+
+# WHAT IT DOES
+# Grabs all the support libraries and runs them through a preprocessor
+# using the default Jetifier config to generate the final mappings.
+
+ROOT_DIR=$(dirname $(readlink -f $0))
+OUT_DIR="$ROOT_DIR/out"
+TEMP_LOG="$OUT_DIR/tempLog"
+
+JETIFIER_DIR="$ROOT_DIR/../.."
+DEFAULT_CONFIG="$JETIFIER_DIR/core/src/main/resources/default.config"
+GENERATED_CONFIG="$JETIFIER_DIR/core/src/main/resources/default.generated.config"
+PREPROCESSOR_DISTRO_PATH="$JETIFIER_DIR/preprocessor/build/distributions/preprocessor-1.0.zip"
+PREPROCESSOR_BIN_PATH="$OUT_DIR/preprocessor-1.0/bin/preprocessor"
+SUPPORT_LIBS_DOWNLOADED="$OUT_DIR/supportLibs"
+
+GREEN='\033[0;32m'
+RED='\033[0;31m'
+NC='\033[0m' # No Color
+
+function exitAndFail() {
+ cat $TEMP_LOG
+ echo -e "${RED}FAILED${NC}"
+ exit 1
+}
+
+function printSectionStart() {
+ echo ""
+ echo "======================================================"
+ echo "$1"
+ echo "======================================================"
+}
+
+function printSuccess() {
+ echo -e "${GREEN}SUCCESS${NC}"
+}
+
+function buildProjectUsingGradle() {
+ cd $1
+ sh gradlew clean build $2 > $TEMP_LOG --stacktrace || exitAndFail 2>&1
+}
+
+
+rm -r $OUT_DIR
+mkdir $OUT_DIR
+echo "OUT dir is at '$OUT_DIR'"
+
+printSectionStart "Downloading all affected support libraries"
+wget -nd -i $ROOT_DIR/repo-links -P $SUPPORT_LIBS_DOWNLOADED
+
+printSectionStart "Preparing Jetifier"
+buildProjectUsingGradle $JETIFIER_DIR
+echo "[OK] Clean build done"
+
+unzip $PREPROCESSOR_DISTRO_PATH -d $OUT_DIR > /dev/null
+echo "[OK] Copied & unziped jetifier preprocessor"
+
+printSectionStart "Preprocessing mappings on support libraries"
+sh $PREPROCESSOR_BIN_PATH -i "$SUPPORT_LIBS_DOWNLOADED" -o "$GENERATED_CONFIG" -c "$DEFAULT_CONFIG" -l verbose || exitAndFail
+echo "[OK] Done, config generated into $GENERATED_CONFIG"
+
+printSuccess
diff --git a/jetifier/jetifier/preprocessor/scripts/repo-links b/jetifier/jetifier/preprocessor/scripts/repo-links
new file mode 100644
index 0000000..961c149
--- /dev/null
+++ b/jetifier/jetifier/preprocessor/scripts/repo-links
@@ -0,0 +1,52 @@
+# Copyright (C) 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
+
+https://maven.google.com/com/android/support/animated-vector-drawable/27.0.1/animated-vector-drawable-27.0.1.aar
+https://maven.google.com/com/android/support/appcompat-v7/27.0.1/appcompat-v7-27.0.1.aar
+https://maven.google.com/com/android/support/cardview-v7/27.0.1/cardview-v7-27.0.1.aar
+https://maven.google.com/com/android/support/customtabs/27.0.1/customtabs-27.0.1.aar
+https://maven.google.com/com/android/support/design/27.0.1/design-27.0.1.aar
+https://maven.google.com/com/android/support/exifinterface/27.0.1/exifinterface-27.0.1.aar
+https://maven.google.com/com/android/support/gridlayout-v7/27.0.1/gridlayout-v7-27.0.1.aar
+https://maven.google.com/com/android/support/instantvideo/26.0.0-alpha1/instantvideo-26.0.0-alpha1.aar
+https://maven.google.com/com/android/support/leanback-v17/27.0.1/leanback-v17-27.0.1.aar
+https://maven.google.com/com/android/support/mediarouter-v7/27.0.1/mediarouter-v7-27.0.1.aar
+https://maven.google.com/com/android/support/multidex/1.0.2/multidex-1.0.2.aar
+https://maven.google.com/com/android/support/multidex-instrumentation/1.0.2/multidex-instrumentation-1.0.2.aar
+https://maven.google.com/com/android/support/palette-v7/27.0.1/palette-v7-27.0.1.aar
+https://maven.google.com/com/android/support/percent/27.0.1/percent-27.0.1.aar
+https://maven.google.com/com/android/support/preference-leanback-v17/27.0.1/preference-leanback-v17-27.0.1.aar
+https://maven.google.com/com/android/support/preference-v14/27.0.1/preference-v14-27.0.1.aar
+https://maven.google.com/com/android/support/preference-v7/27.0.1/preference-v7-27.0.1.aar
+https://maven.google.com/com/android/support/recommendation/27.0.1/recommendation-27.0.1.aar
+https://maven.google.com/com/android/support/recyclerview-v7/27.0.1/recyclerview-v7-27.0.1.aar
+https://maven.google.com/com/android/support/support-annotations/27.0.1/support-annotations-27.0.1.jar
+https://maven.google.com/com/android/support/support-compat/27.0.1/support-compat-27.0.1.aar
+https://maven.google.com/com/android/support/support-content/27.0.1/support-content-27.0.1.aar
+https://maven.google.com/com/android/support/support-core-ui/27.0.1/support-core-ui-27.0.1.aar
+https://maven.google.com/com/android/support/support-core-utils/27.0.1/support-core-utils-27.0.1.aar
+https://maven.google.com/com/android/support/support-dynamic-animation/27.0.1/support-dynamic-animation-27.0.1.aar
+https://maven.google.com/com/android/support/support-emoji/27.0.1/support-emoji-27.0.1.aar
+https://maven.google.com/com/android/support/support-emoji-appcompat/27.0.1/support-emoji-appcompat-27.0.1.aar
+https://maven.google.com/com/android/support/support-emoji-bundled/27.0.1/support-emoji-bundled-27.0.1.aar
+https://maven.google.com/com/android/support/support-fragment/27.0.1/support-fragment-27.0.1.aar
+https://maven.google.com/com/android/support/support-media-compat/27.0.1/support-media-compat-27.0.1.aar
+https://maven.google.com/com/android/support/support-tv-provider/27.0.1/support-tv-provider-27.0.1.aar
+https://maven.google.com/com/android/support/support-v13/27.0.1/support-v13-27.0.1.aar
+https://maven.google.com/com/android/support/support-v4/27.0.1/support-v4-27.0.1.aar
+https://maven.google.com/com/android/support/support-vector-drawable/27.0.1/support-vector-drawable-27.0.1.aar
+https://maven.google.com/com/android/support/transition/27.0.1/transition-27.0.1.aar
+https://maven.google.com/com/android/support/wear/27.0.1/wear-27.0.1.aar
+https://maven.google.com/com/android/support/wearable/27.0.1/wearable-27.0.1.aar
+https://maven.google.com/com/android/support/constraint/constraint-layout/1.0.2/constraint-layout-1.0.2.aar
diff --git a/jetifier/jetifier/preprocessor/src/main/kotlin/android/support/tools/jetifier/preprocessor/ConfigGenerator.kt b/jetifier/jetifier/preprocessor/src/main/kotlin/android/support/tools/jetifier/preprocessor/ConfigGenerator.kt
new file mode 100644
index 0000000..ec12ac8
--- /dev/null
+++ b/jetifier/jetifier/preprocessor/src/main/kotlin/android/support/tools/jetifier/preprocessor/ConfigGenerator.kt
@@ -0,0 +1,72 @@
+package android.support.tools.jetifier.preprocessor
+
+import android.support.tools.jetifier.core.archive.Archive
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.config.ConfigParser
+import android.support.tools.jetifier.core.map.LibraryMapGenerator
+import java.io.File
+import java.nio.file.Path
+
+class ConfigGenerator {
+
+ companion object {
+ private const val LEGAL_NOTICE =
+ "# Copyright (C) 2017 The Android Open Source Project\n" +
+ "#\n" +
+ "# Licensed under the Apache License, Version 2.0 (the \"License\");\n" +
+ "# you may not use this file except in compliance with the License.\n" +
+ "# You may obtain a copy of the License at\n" +
+ "#\n" +
+ "# http://www.apache.org/licenses/LICENSE-2.0\n" +
+ "#\n" +
+ "# Unless required by applicable law or agreed to in writing, software\n" +
+ "# distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
+ "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
+ "# See the License for the specific language governing permissions and\n" +
+ "# limitations under the License\n"
+
+ private const val GEN_NOTICE =
+ "# DO NOT EDIT MANUALLY! This file was auto-generated using Jetifier preprocessor.\n" +
+ "# To make some changes in the configuration edit \"default.config\" and run\n" +
+ "# preprocessor/scripts/processDefaultConfig.sh script to update this file.\n"
+ }
+
+ fun generateMapping(
+ config: Config,
+ inputLibraries: List<File>,
+ outputConfigPath: Path) {
+
+ val mapper = LibraryMapGenerator(config)
+ inputLibraries.forEach {
+ if (it.isDirectory) {
+ it.listFiles().forEach { fileInDir ->
+ val library = Archive.Builder.extract(fileInDir)
+ mapper.scanLibrary(library)
+ }
+ } else {
+ val library = Archive.Builder.extract(it)
+ mapper.scanLibrary(library)
+ }
+ }
+
+ val map = mapper.generateMap()
+ val newConfig = config.setNewMap(map)
+
+ saveConfigToFile(newConfig, outputConfigPath.toFile())
+ }
+
+ private fun saveConfigToFile(configToSave: Config, outputFile : File) {
+ val sb = StringBuilder()
+ sb.append(LEGAL_NOTICE)
+ sb.append("\n")
+ sb.append(GEN_NOTICE)
+ sb.append("\n")
+ sb.append(ConfigParser.writeToString(configToSave))
+
+ if (outputFile.exists()) {
+ outputFile.delete()
+ }
+ outputFile.createNewFile()
+ outputFile.writeText(sb.toString())
+ }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/preprocessor/src/main/kotlin/android/support/tools/jetifier/preprocessor/Main.kt b/jetifier/jetifier/preprocessor/src/main/kotlin/android/support/tools/jetifier/preprocessor/Main.kt
new file mode 100644
index 0000000..58cb20f
--- /dev/null
+++ b/jetifier/jetifier/preprocessor/src/main/kotlin/android/support/tools/jetifier/preprocessor/Main.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.preprocessor
+
+import android.support.tools.jetifier.core.config.ConfigParser
+import android.support.tools.jetifier.core.utils.Log
+import org.apache.commons.cli.CommandLine
+import org.apache.commons.cli.DefaultParser
+import org.apache.commons.cli.HelpFormatter
+import org.apache.commons.cli.Option
+import org.apache.commons.cli.Options
+import org.apache.commons.cli.ParseException
+import java.io.File
+import java.nio.file.Paths
+
+class Main {
+
+ companion object {
+ const val TAG = "Main"
+ const val TOOL_NAME = "preprocessor"
+
+ val OPTIONS = Options()
+ val OPTION_INPUT_LIBS = createOption("i", "Input libraries paths", multiple = true)
+ val OPTION_INPUT_CONFIG = createOption("c", "Input config path")
+ val OPTION_OUTPUT_CONFIG = createOption("o", "Output config path")
+ val OPTION_LOG_LEVEL = createOption("l", "Logging level. debug, verbose, default",
+ isRequired = false)
+
+ private fun createOption(argName: String,
+ desc: String,
+ isRequired: Boolean = true,
+ multiple: Boolean = false) : Option {
+ val op = Option(argName, true, desc)
+ op.isRequired = isRequired
+ if (multiple) {
+ op.args = Option.UNLIMITED_VALUES
+ }
+ OPTIONS.addOption(op)
+ return op
+ }
+ }
+
+ fun run(args : Array<String>) {
+ val cmd = parseCmdLine(args)
+ if (cmd == null) {
+ System.exit(1)
+ return
+ }
+
+ Log.setLevel(cmd.getOptionValue(OPTION_LOG_LEVEL.opt))
+
+ val inputLibraries = cmd.getOptionValues(OPTION_INPUT_LIBS.opt).map { File(it) }
+ val inputConfigPath = Paths.get(cmd.getOptionValue(OPTION_INPUT_CONFIG.opt))
+ val outputConfigPath = Paths.get(cmd.getOptionValue(OPTION_OUTPUT_CONFIG.opt))
+
+ val config = ConfigParser.loadFromFile(inputConfigPath)
+ if (config == null) {
+ System.exit(1)
+ return
+ }
+
+ val generator = ConfigGenerator()
+ generator.generateMapping(config, inputLibraries, outputConfigPath)
+ }
+
+ private fun parseCmdLine(args : Array<String>) : CommandLine? {
+ try {
+ return DefaultParser().parse(OPTIONS, args)
+ } catch (e: ParseException) {
+ Log.e(TAG, e.message.orEmpty())
+ HelpFormatter().printHelp(TOOL_NAME, OPTIONS)
+ }
+ return null
+ }
+
+}
+
+
+fun main(args : Array<String>) {
+ Main().run(args)
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/android/support/KotlinNoOp.kt b/jetifier/jetifier/settings.gradle
similarity index 65%
rename from buildSrc/src/main/kotlin/android/support/KotlinNoOp.kt
rename to jetifier/jetifier/settings.gradle
index 968f6ca..7d13b73 100644
--- a/buildSrc/src/main/kotlin/android/support/KotlinNoOp.kt
+++ b/jetifier/jetifier/settings.gradle
@@ -1,24 +1,22 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright (C) 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
+ * 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.
+ * limitations under the License
*/
-package android.support
+rootProject.name = 'jetifier'
+include 'core'
+include 'gradle-plugin'
+include 'standalone'
+include 'preprocessor'
-class KotlinNoOp {
-
- fun noOp() {
- }
-
-}
\ No newline at end of file
diff --git a/jetifier/jetifier/standalone/build.gradle b/jetifier/jetifier/standalone/build.gradle
new file mode 100644
index 0000000..8814d50
--- /dev/null
+++ b/jetifier/jetifier/standalone/build.gradle
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 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
+ */
+
+version '1.0'
+
+apply plugin: "application"
+
+mainClassName = "android.support.tools.jetifier.standalone.MainKt"
+
+dependencies {
+ compile project(':core')
+ compile group: 'commons-cli', name: 'commons-cli', version: '1.3.1'
+}
+
diff --git a/jetifier/jetifier/standalone/src/main/kotlin/android/support/tools/jetifier/standalone/Main.kt b/jetifier/jetifier/standalone/src/main/kotlin/android/support/tools/jetifier/standalone/Main.kt
new file mode 100644
index 0000000..de310e4
--- /dev/null
+++ b/jetifier/jetifier/standalone/src/main/kotlin/android/support/tools/jetifier/standalone/Main.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 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 android.support.tools.jetifier.standalone
+
+import android.support.tools.jetifier.core.Processor
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.config.ConfigParser
+import android.support.tools.jetifier.core.utils.Log
+import org.apache.commons.cli.CommandLine
+import org.apache.commons.cli.DefaultParser
+import org.apache.commons.cli.HelpFormatter
+import org.apache.commons.cli.Option
+import org.apache.commons.cli.Options
+import org.apache.commons.cli.ParseException
+import java.io.File
+import java.nio.file.Paths
+
+class Main {
+
+ companion object {
+ const val TAG = "Main"
+ const val TOOL_NAME = "standalone"
+
+ val OPTIONS = Options()
+ val OPTION_INPUT = createOption("i", "Input libraries paths", multiple = true)
+ val OPTION_OUTPUT = createOption("o", "Output config path")
+ val OPTION_CONFIG = createOption("c", "Input config path", isRequired = false)
+ val OPTION_LOG_LEVEL = createOption("l", "Logging level. debug, verbose, default",
+ isRequired = false)
+
+ private fun createOption(argName: String,
+ desc: String,
+ isRequired: Boolean = true,
+ multiple: Boolean = false) : Option {
+ val op = Option(argName, true, desc)
+ op.isRequired = isRequired
+ if (multiple) {
+ op.args = Option.UNLIMITED_VALUES
+ }
+ OPTIONS.addOption(op)
+ return op
+ }
+ }
+
+ fun run(args : Array<String>) {
+ val cmd = parseCmdLine(args)
+ if (cmd == null) {
+ System.exit(1)
+ return
+ }
+
+ Log.setLevel(cmd.getOptionValue(OPTION_LOG_LEVEL.opt))
+
+ val inputLibraries = cmd.getOptionValues(OPTION_INPUT.opt).map { File(it) }.toSet()
+ val outputPath = Paths.get(cmd.getOptionValue(OPTION_OUTPUT.opt))
+
+ val config : Config?
+ if (cmd.hasOption(OPTION_CONFIG.opt)) {
+ val configPath = Paths.get(cmd.getOptionValue(OPTION_CONFIG.opt))
+ config = ConfigParser.loadFromFile(configPath)
+ } else {
+ config = ConfigParser.loadDefaultConfig()
+ }
+
+ if (config == null) {
+ Log.e(TAG, "Failed to load the config file")
+ System.exit(1)
+ return
+ }
+
+ val processor = Processor(config)
+ processor.transform(inputLibraries, outputPath)
+ }
+
+ private fun parseCmdLine(args : Array<String>) : CommandLine? {
+ try {
+ return DefaultParser().parse(OPTIONS, args)
+ } catch (e: ParseException) {
+ Log.e(TAG, e.message.orEmpty())
+ HelpFormatter().printHelp(TOOL_NAME, OPTIONS)
+ }
+ return null
+ }
+
+}
+
+
+fun main(args : Array<String>) {
+ Main().run(args)
+}
\ No newline at end of file
diff --git a/leanback/api/27.0.0.ignore b/leanback/api/27.0.0.ignore
new file mode 100644
index 0000000..35526be
--- /dev/null
+++ b/leanback/api/27.0.0.ignore
@@ -0,0 +1,9 @@
+5e0df8d
+9cc8101
+8be589f
+9acc564
+77de988
+3b4fb8e
+8ec3ebc
+f7a9631
+afc0ff4
diff --git a/leanback/api/current.txt b/leanback/api/current.txt
index 4a5067c..b045d8f 100644
--- a/leanback/api/current.txt
+++ b/leanback/api/current.txt
@@ -31,38 +31,6 @@
method public void startEntranceTransition();
}
- abstract deprecated class BaseRowFragment extends android.app.Fragment {
- method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
- method public final android.support.v17.leanback.widget.ItemBridgeAdapter getBridgeAdapter();
- method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
- method public int getSelectedPosition();
- method public final android.support.v17.leanback.widget.VerticalGridView getVerticalGridView();
- method public void onTransitionEnd();
- method public boolean onTransitionPrepare();
- method public void onTransitionStart();
- method public final void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
- method public void setAlignment(int);
- method public final void setPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
- method public void setSelectedPosition(int);
- method public void setSelectedPosition(int, boolean);
- }
-
- abstract class BaseRowSupportFragment extends android.support.v4.app.Fragment {
- method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
- method public final android.support.v17.leanback.widget.ItemBridgeAdapter getBridgeAdapter();
- method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
- method public int getSelectedPosition();
- method public final android.support.v17.leanback.widget.VerticalGridView getVerticalGridView();
- method public void onTransitionEnd();
- method public boolean onTransitionPrepare();
- method public void onTransitionStart();
- method public final void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
- method public void setAlignment(int);
- method public final void setPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
- method public void setSelectedPosition(int);
- method public void setSelectedPosition(int, boolean);
- }
-
public class BaseSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
method protected java.lang.Object createEntranceTransition();
method public final android.support.v17.leanback.app.ProgressBarManager getProgressBarManager();
@@ -552,9 +520,11 @@
field public static final int UI_STYLE_REPLACE = 0; // 0x0
}
- public deprecated class HeadersFragment extends android.support.v17.leanback.app.BaseRowFragment {
+ public deprecated class HeadersFragment extends android.app.Fragment {
ctor public HeadersFragment();
method public boolean isScrolling();
+ method public void onTransitionEnd();
+ method public void onTransitionStart();
method public void setOnHeaderClickedListener(android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener);
method public void setOnHeaderViewSelectedListener(android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener);
}
@@ -567,9 +537,11 @@
method public abstract void onHeaderSelected(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
}
- public class HeadersSupportFragment extends android.support.v17.leanback.app.BaseRowSupportFragment {
+ public class HeadersSupportFragment extends android.support.v4.app.Fragment {
ctor public HeadersSupportFragment();
method public boolean isScrolling();
+ method public void onTransitionEnd();
+ method public void onTransitionStart();
method public void setOnHeaderClickedListener(android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener);
method public void setOnHeaderViewSelectedListener(android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener);
}
@@ -754,7 +726,7 @@
method public void show();
}
- public deprecated class RowsFragment extends android.support.v17.leanback.app.BaseRowFragment implements android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapterProvider android.support.v17.leanback.app.BrowseFragment.MainFragmentRowsAdapterProvider {
+ public deprecated class RowsFragment extends android.app.Fragment implements android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapterProvider android.support.v17.leanback.app.BrowseFragment.MainFragmentRowsAdapterProvider {
ctor public RowsFragment();
method public deprecated void enableRowScaling(boolean);
method protected android.support.v17.leanback.widget.VerticalGridView findGridViewFromRoot(android.view.View);
@@ -765,6 +737,9 @@
method public android.support.v17.leanback.widget.BaseOnItemViewSelectedListener getOnItemViewSelectedListener();
method public android.support.v17.leanback.widget.RowPresenter.ViewHolder getRowViewHolder(int);
method public boolean isScrolling();
+ method public void onTransitionEnd();
+ method public boolean onTransitionPrepare();
+ method public void setAlignment(int);
method public void setEntranceTransitionState(boolean);
method public void setExpand(boolean);
method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
@@ -780,7 +755,7 @@
ctor public RowsFragment.MainFragmentRowsAdapter(android.support.v17.leanback.app.RowsFragment);
}
- public class RowsSupportFragment extends android.support.v17.leanback.app.BaseRowSupportFragment implements android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapterProvider android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapterProvider {
+ public class RowsSupportFragment extends android.support.v4.app.Fragment implements android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapterProvider android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapterProvider {
ctor public RowsSupportFragment();
method public deprecated void enableRowScaling(boolean);
method protected android.support.v17.leanback.widget.VerticalGridView findGridViewFromRoot(android.view.View);
@@ -791,6 +766,9 @@
method public android.support.v17.leanback.widget.BaseOnItemViewSelectedListener getOnItemViewSelectedListener();
method public android.support.v17.leanback.widget.RowPresenter.ViewHolder getRowViewHolder(int);
method public boolean isScrolling();
+ method public void onTransitionEnd();
+ method public boolean onTransitionPrepare();
+ method public void setAlignment(int);
method public void setEntranceTransitionState(boolean);
method public void setExpand(boolean);
method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
@@ -1104,11 +1082,9 @@
method public final boolean isPlaying();
method public final boolean isPrepared();
method protected static void notifyItemChanged(android.support.v17.leanback.widget.ArrayObjectAdapter, java.lang.Object);
- method public abstract void onActionClicked(android.support.v17.leanback.widget.Action);
method protected void onCreatePrimaryActions(android.support.v17.leanback.widget.ArrayObjectAdapter);
method protected abstract android.support.v17.leanback.widget.PlaybackRowPresenter onCreateRowPresenter();
method protected void onCreateSecondaryActions(android.support.v17.leanback.widget.ArrayObjectAdapter);
- method public abstract boolean onKey(android.view.View, int, android.view.KeyEvent);
method protected void onMetadataChanged();
method protected void onPlayCompleted();
method protected void onPlayStateChanged();
@@ -2826,7 +2802,7 @@
method public abstract void requestAudioPermission();
}
- public class SearchEditText extends android.support.v17.leanback.widget.StreamingTextView {
+ public class SearchEditText extends android.widget.EditText {
ctor public SearchEditText(android.content.Context);
ctor public SearchEditText(android.content.Context, android.util.AttributeSet);
ctor public SearchEditText(android.content.Context, android.util.AttributeSet, int);
@@ -2969,16 +2945,6 @@
method public abstract void recognizeSpeech();
}
- class StreamingTextView extends android.widget.EditText {
- ctor public StreamingTextView(android.content.Context, android.util.AttributeSet);
- ctor public StreamingTextView(android.content.Context, android.util.AttributeSet, int);
- method public static boolean isLayoutRtl(android.view.View);
- method public void reset();
- method public void setFinalRecognizedText(java.lang.CharSequence);
- method public void updateRecognizedText(java.lang.String, java.lang.String);
- method public void updateRecognizedText(java.lang.String, java.util.List<java.lang.Float>);
- }
-
public class TitleHelper {
ctor public TitleHelper(android.view.ViewGroup, android.view.View);
method public android.support.v17.leanback.widget.BrowseFrameLayout.OnFocusSearchListener getOnFocusSearchListener();
diff --git a/leanback/build.gradle b/leanback/build.gradle
index 4ebec71..036f08f 100644
--- a/leanback/build.gradle
+++ b/leanback/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,16 +7,16 @@
}
dependencies {
- api project(':support-compat')
- api project(':support-core-ui')
- api project(':support-media-compat')
- api project(':support-fragment')
- api project(':recyclerview-v7')
+ api(project(":support-compat"))
+ api(project(":support-core-ui"))
+ api(project(":support-media-compat"))
+ api(project(":support-fragment"))
+ api(project(":recyclerview-v7"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
}
android {
diff --git a/leanback/lint-baseline.xml b/leanback/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/leanback/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java b/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
index d7020e9..9d159ec 100644
--- a/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ b/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -2726,40 +2726,6 @@
}
}
- // Observer is registered on Adapter to invalidate saved instance state
- final RecyclerView.AdapterDataObserver mObServer = new RecyclerView.AdapterDataObserver() {
- @Override
- public void onChanged() {
- mChildrenStates.clear();
- }
-
- @Override
- public void onItemRangeChanged(int positionStart, int itemCount) {
- if (DEBUG) {
- Log.v(getTag(), "onItemRangeChanged positionStart "
- + positionStart + " itemCount " + itemCount);
- }
- for (int i = positionStart, end = positionStart + itemCount; i < end; i++) {
- mChildrenStates.remove(i);
- }
- }
-
- @Override
- public void onItemRangeInserted(int positionStart, int itemCount) {
- mChildrenStates.clear();
- }
-
- @Override
- public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
- mChildrenStates.clear();
- }
-
- @Override
- public void onItemRangeRemoved(int positionStart, int itemCount) {
- mChildrenStates.clear();
- }
- };
-
@Override
public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
if (DEBUG) Log.v(getTag(), "onItemsAdded positionStart "
@@ -2771,12 +2737,14 @@
mFocusPositionOffset += itemCount;
}
}
+ mChildrenStates.clear();
}
@Override
public void onItemsChanged(RecyclerView recyclerView) {
if (DEBUG) Log.v(getTag(), "onItemsChanged");
mFocusPositionOffset = 0;
+ mChildrenStates.clear();
}
@Override
@@ -2797,6 +2765,7 @@
}
}
}
+ mChildrenStates.clear();
}
@Override
@@ -2817,6 +2786,16 @@
mFocusPositionOffset += itemCount;
}
}
+ mChildrenStates.clear();
+ }
+
+ @Override
+ public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount) {
+ if (DEBUG) Log.v(getTag(), "onItemsUpdated positionStart "
+ + positionStart + " itemCount " + itemCount);
+ for (int i = positionStart, end = positionStart + itemCount; i < end; i++) {
+ mChildrenStates.remove(i);
+ }
}
@Override
@@ -3515,16 +3494,12 @@
mFocusPosition = NO_POSITION;
mFocusPositionOffset = 0;
mChildrenStates.clear();
- oldAdapter.unregisterAdapterDataObserver(mObServer);
}
if (newAdapter instanceof FacetProviderAdapter) {
mFacetProviderAdapter = (FacetProviderAdapter) newAdapter;
} else {
mFacetProviderAdapter = null;
}
- if (newAdapter != null) {
- newAdapter.registerAdapterDataObserver(mObServer);
- }
super.onAdapterChanged(oldAdapter, newAdapter);
}
diff --git a/leanback/src/android/support/v17/leanback/widget/WindowAlignment.java b/leanback/src/android/support/v17/leanback/widget/WindowAlignment.java
index 55fa758..c6589d4 100644
--- a/leanback/src/android/support/v17/leanback/widget/WindowAlignment.java
+++ b/leanback/src/android/support/v17/leanback/widget/WindowAlignment.java
@@ -390,11 +390,7 @@
@Override
public String toString() {
- return new StringBuffer().append("horizontal=")
- .append(horizontal.toString())
- .append("; vertical=")
- .append(vertical.toString())
- .toString();
+ return "horizontal=" + horizontal + "; vertical=" + vertical;
}
}
diff --git a/lifecycle/common-java8/build.gradle b/lifecycle/common-java8/build.gradle
index 7877b81..137ea32 100644
--- a/lifecycle/common-java8/build.gradle
+++ b/lifecycle/common-java8/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions;
import android.support.SupportLibraryExtension;
@@ -23,14 +24,12 @@
}
dependencies {
- testCompile libs.junit
- testCompile libs.mockito_core
- compile project(":lifecycle:common")
+ testCompile(JUNIT)
+ testCompile(MOCKITO_CORE)
+ compile(project(":lifecycle:common"))
compile libs.support.annotations
}
-createAndroidCheckstyle(project)
-
supportLibrary {
name = "Android Lifecycle-Common for Java 8 Language"
publish = true
diff --git a/lifecycle/common/build.gradle b/lifecycle/common/build.gradle
index a3b06dd..bc46d17 100644
--- a/lifecycle/common/build.gradle
+++ b/lifecycle/common/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions;
import android.support.SupportLibraryExtension;
@@ -23,13 +24,11 @@
}
dependencies {
- testCompile libs.junit
- testCompile libs.mockito_core
+ testCompile(JUNIT)
+ testCompile(MOCKITO_CORE)
compile libs.support.annotations
}
-createAndroidCheckstyle(project)
-
supportLibrary {
name = "Android Lifecycle-Common"
publish = true
diff --git a/lifecycle/common/src/main/java/android/arch/lifecycle/Lifecycle.java b/lifecycle/common/src/main/java/android/arch/lifecycle/Lifecycle.java
index c0a2090..e04cdb4 100644
--- a/lifecycle/common/src/main/java/android/arch/lifecycle/Lifecycle.java
+++ b/lifecycle/common/src/main/java/android/arch/lifecycle/Lifecycle.java
@@ -108,6 +108,7 @@
* @return The current state of the Lifecycle.
*/
@MainThread
+ @NonNull
public abstract State getCurrentState();
@SuppressWarnings("WeakerAccess")
diff --git a/lifecycle/compiler/build.gradle b/lifecycle/compiler/build.gradle
index edc54b0..534d1ec 100644
--- a/lifecycle/compiler/build.gradle
+++ b/lifecycle/compiler/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
import android.support.SupportLibraryExtension
@@ -10,23 +11,20 @@
// Temporary hack to stop AS to adding two guavas into test's classpath
configurations.all {
resolutionStrategy {
- force libs.guava
+ force GUAVA
}
}
dependencies {
- compile project(":lifecycle:common")
- compile libs.kotlin.stdlib
- compile libs.auto_common
- compile libs.javapoet
- testCompile libs.google_compile_testing
- testCompile libs.jsr250
+ compile(project(":lifecycle:common"))
+ compile(KOTLIN_STDLIB)
+ compile(AUTO_COMMON)
+ compile(JAVAPOET)
+ testCompile(GOOGLE_COMPILE_TESTING)
+ testCompile(JSR250)
testCompile files(org.gradle.internal.jvm.Jvm.current().getToolsJar())
}
-version = LibraryVersions.LIFECYCLES_EXT.toString()
-createKotlinCheckstyle(project)
-
// we actually need to compile :lifecycle:common, but compileJava is easier
task compileTestLibrarySource(type: JavaCompile, dependsOn: compileJava) {
source "src/tests/test-data/lib/src"
@@ -43,7 +41,7 @@
supportLibrary {
name = "Android Lifecycles Compiler"
publish = true
- mavenVersion = LibraryVersions.LIFECYCLES_CORE
+ mavenVersion = LibraryVersions.LIFECYCLES_EXT
mavenGroup = LibraryGroups.LIFECYCLE
inceptionYear = "2017"
description = "Android Lifecycles annotation processor"
diff --git a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/LifecycleProcessor.kt b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/LifecycleProcessor.kt
index 5355615..f57d2dd 100644
--- a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/LifecycleProcessor.kt
+++ b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/LifecycleProcessor.kt
@@ -19,7 +19,6 @@
import javax.annotation.processing.AbstractProcessor
import javax.annotation.processing.RoundEnvironment
import javax.annotation.processing.SupportedAnnotationTypes
-import javax.annotation.processing.SupportedSourceVersion
import javax.lang.model.SourceVersion
import javax.lang.model.element.TypeElement
diff --git a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/elements_ext.kt b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/elements_ext.kt
index ed20c54..08b6ff2 100644
--- a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/elements_ext.kt
+++ b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/elements_ext.kt
@@ -38,7 +38,7 @@
fun TypeElement.methods(): List<ExecutableElement> = ElementFilter.methodsIn(enclosedElements)
-private const val SYNTHETIC = "__synthetic_"
+private const val SYNTHETIC = "__synthetic_"
fun syntheticName(method: ExecutableElement) = "$SYNTHETIC${method.simpleName}"
diff --git a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/writer.kt b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/writer.kt
index 00549ee..5811c61 100644
--- a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/writer.kt
+++ b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/writer.kt
@@ -28,7 +28,6 @@
import com.squareup.javapoet.TypeName
import com.squareup.javapoet.TypeSpec
import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.element.ExecutableElement
import javax.lang.model.element.Modifier
import javax.lang.model.element.TypeElement
import javax.tools.StandardLocation
@@ -149,10 +148,11 @@
val adapterClass = type.getPackageQName() + "." + getAdapterName(type)
val observerClass = type.toString()
val keepRule = """# Generated keep rule for Lifecycle observer adapter.
+ |-if class $observerClass {
+ | <init>(...);
+ |}
|-keep class $adapterClass {
- | ifused class $observerClass {
- | <init>(...);
- | };
+ | <init>(...);
|}
|""".trimMargin()
@@ -178,7 +178,6 @@
addStatement("$N.$L($paramString)", receiverField,
methodName,
*takeParams(count, OWNER_PARAM, EVENT_PARAM))
-
} else {
val originalType = syntheticAccess
val paramString = generateParamString(count + 1)
@@ -195,4 +194,4 @@
private fun takeParams(count: Int, vararg params: Any) = params.take(count).toTypedArray()
-private fun generateParamString(count: Int) = (0 until count).joinToString(",") { N }
\ No newline at end of file
+private fun generateParamString(count: Int) = (0 until count).joinToString(",") { N }
diff --git a/lifecycle/extensions/build.gradle b/lifecycle/extensions/build.gradle
index 6bd1bce..38640b6 100644
--- a/lifecycle/extensions/build.gradle
+++ b/lifecycle/extensions/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
import android.support.SupportLibraryExtension
@@ -33,23 +34,21 @@
}
dependencies {
- api project(":lifecycle:runtime")
- api project(":arch:common")
- api project(":arch:runtime")
+ api(project(":lifecycle:runtime"))
+ api(project(":arch:common"))
+ api(project(":arch:runtime"))
api libs.support.fragments, libs.support_exclude_config
- api project(":lifecycle:common")
+ api(project(":lifecycle:common"))
- testImplementation project(":arch:core-testing")
- testImplementation libs.junit
- testImplementation libs.mockito_core
+ testImplementation(project(":arch:core-testing"))
+ testImplementation(JUNIT)
+ testImplementation(MOCKITO_CORE)
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
androidTestImplementation libs.support.app_compat, libs.support_exclude_config
}
-createAndroidCheckstyle(project)
-
supportLibrary {
name = "Android Lifecycle Extensions"
publish = true
diff --git a/lifecycle/extensions/lint-baseline.xml b/lifecycle/extensions/lint-baseline.xml
deleted file mode 100644
index 2cadde1..0000000
--- a/lifecycle/extensions/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0">
-
-</issues>
diff --git a/lifecycle/integration-tests/testapp/build.gradle b/lifecycle/integration-tests/testapp/build.gradle
index 64159bd..9f970a5 100644
--- a/lifecycle/integration-tests/testapp/build.gradle
+++ b/lifecycle/integration-tests/testapp/build.gradle
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-apply plugin: 'com.android.application'
+import static android.support.dependencies.DependenciesKt.*
-project.ext.noDocs = true
+apply plugin: 'com.android.application'
android {
compileSdkVersion tools.current_sdk
@@ -60,24 +60,19 @@
dependencies {
// IJ canont figure out transitive dependencies so need to declare them.
- implementation project(":lifecycle:common")
- implementation project(":lifecycle:runtime")
- implementation project(":lifecycle:extensions")
- annotationProcessor project(":lifecycle:compiler")
+ implementation(project(":lifecycle:common"))
+ implementation(project(":lifecycle:runtime"))
+ implementation(project(":lifecycle:extensions"))
+ annotationProcessor(project(":lifecycle:compiler"))
- androidTestAnnotationProcessor project(":lifecycle:compiler")
- androidTestImplementation(libs.test_runner) {
- exclude module: 'support-annotations'
- }
- androidTestImplementation(libs.espresso_core, {
- exclude group: 'com.android.support', module: 'support-annotations'
- })
+ androidTestAnnotationProcessor(project(":lifecycle:compiler"))
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
- testImplementation libs.junit
- testImplementation libs.mockito_core
- testAnnotationProcessor project(":lifecycle:compiler")
+ testImplementation(JUNIT)
+ testImplementation(MOCKITO_CORE)
+ testAnnotationProcessor(project(":lifecycle:compiler"))
}
-createAndroidCheckstyle(project)
tasks['check'].dependsOn(tasks['connectedCheck'])
diff --git a/lifecycle/reactivestreams/build.gradle b/lifecycle/reactivestreams/build.gradle
index d2beeed..511ad7a 100644
--- a/lifecycle/reactivestreams/build.gradle
+++ b/lifecycle/reactivestreams/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
import android.support.SupportLibraryExtension
@@ -28,27 +29,21 @@
}
}
-allprojects {
- dependencies {
- api project(":arch:common")
- api project(":lifecycle:common")
- api project(":lifecycle:extensions")
- api project(":lifecycle:runtime")
- api libs.support.annotations
- api libs.reactive_streams
+dependencies {
+ api(project(":arch:common"))
+ api(project(":lifecycle:common"))
+ api(project(":lifecycle:extensions"))
+ api(project(":lifecycle:runtime"))
+ api libs.support.annotations
+ api(REACTIVE_STREAMS)
- testImplementation libs.junit
- testImplementation libs.rx_java
+ testImplementation(JUNIT)
+ testImplementation(RX_JAVA)
+ testImplementation(TEST_RUNNER)
- testImplementation(libs.test_runner) {
- exclude module: 'support-annotations'
- }
- androidTestImplementation libs.support.app_compat, libs.support_exclude_config
- }
+ androidTestImplementation libs.support.app_compat, libs.support_exclude_config
}
-createAndroidCheckstyle(project)
-
supportLibrary {
name = "Android Lifecycle Reactivestreams"
publish = true
diff --git a/lifecycle/reactivestreams/lint-baseline.xml b/lifecycle/reactivestreams/lint-baseline.xml
deleted file mode 100644
index 2cadde1..0000000
--- a/lifecycle/reactivestreams/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0">
-
-</issues>
diff --git a/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java b/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java
index ba76f8e..ed3c57c 100644
--- a/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java
+++ b/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java
@@ -50,8 +50,9 @@
* will buffer the latest item and emit it to the subscriber when data is again requested. Any
* other items emitted during the time there was no backpressure requested will be dropped.
*/
+ @NonNull
public static <T> Publisher<T> toPublisher(
- final LifecycleOwner lifecycle, final LiveData<T> liveData) {
+ @NonNull LifecycleOwner lifecycle, @NonNull LiveData<T> liveData) {
return new LiveDataPublisher<>(lifecycle, liveData);
}
@@ -60,7 +61,7 @@
final LifecycleOwner mLifecycle;
final LiveData<T> mLiveData;
- LiveDataPublisher(final LifecycleOwner lifecycle, final LiveData<T> liveData) {
+ LiveDataPublisher(LifecycleOwner lifecycle, LiveData<T> liveData) {
this.mLifecycle = lifecycle;
this.mLiveData = liveData;
}
@@ -91,7 +92,7 @@
}
@Override
- public void onChanged(T t) {
+ public void onChanged(@Nullable T t) {
if (mCanceled) {
return;
}
@@ -183,7 +184,8 @@
*
* @param <T> The type of data hold by this instance.
*/
- public static <T> LiveData<T> fromPublisher(final Publisher<T> publisher) {
+ @NonNull
+ public static <T> LiveData<T> fromPublisher(@NonNull Publisher<T> publisher) {
return new PublisherLiveData<>(publisher);
}
@@ -209,10 +211,10 @@
* @param <T> The type of data hold by this instance.
*/
private static class PublisherLiveData<T> extends LiveData<T> {
- private final Publisher mPublisher;
+ private final Publisher<T> mPublisher;
final AtomicReference<LiveDataSubscriber> mSubscriber;
- PublisherLiveData(@NonNull final Publisher publisher) {
+ PublisherLiveData(@NonNull Publisher<T> publisher) {
mPublisher = publisher;
mSubscriber = new AtomicReference<>();
}
diff --git a/lifecycle/runtime/build.gradle b/lifecycle/runtime/build.gradle
index 01a8abb..44e992b 100644
--- a/lifecycle/runtime/build.gradle
+++ b/lifecycle/runtime/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
import android.support.SupportLibraryExtension
@@ -17,20 +18,18 @@
}
dependencies {
- api project(":lifecycle:common")
- api project(":arch:common")
+ api(project(":lifecycle:common"))
+ api(project(":arch:common"))
// necessary for IJ to resolve dependencies.
api libs.support.annotations
- testImplementation libs.junit
- testImplementation libs.mockito_core
+ testImplementation(JUNIT)
+ testImplementation(MOCKITO_CORE)
- androidTestImplementation libs.junit
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
+ androidTestImplementation(JUNIT)
+ androidTestImplementation(TEST_RUNNER)
}
-createAndroidCheckstyle(project)
-
supportLibrary {
name 'Android Lifecycle Runtime'
publish true
diff --git a/lifecycle/runtime/lint-baseline.xml b/lifecycle/runtime/lint-baseline.xml
deleted file mode 100644
index 2cadde1..0000000
--- a/lifecycle/runtime/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0">
-
-</issues>
diff --git a/lifecycle/runtime/src/main/java/android/arch/lifecycle/LifecycleRegistry.java b/lifecycle/runtime/src/main/java/android/arch/lifecycle/LifecycleRegistry.java
index bf8aff7..eff946b 100644
--- a/lifecycle/runtime/src/main/java/android/arch/lifecycle/LifecycleRegistry.java
+++ b/lifecycle/runtime/src/main/java/android/arch/lifecycle/LifecycleRegistry.java
@@ -225,6 +225,7 @@
return mObserverMap.size();
}
+ @NonNull
@Override
public State getCurrentState() {
return mState;
diff --git a/media-compat/build.gradle b/media-compat/build.gradle
index ec4504e..18ff5a3 100644
--- a/media-compat/build.gradle
+++ b/media-compat/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,13 +7,13 @@
}
dependencies {
- api project(':support-annotations')
- api project(':support-compat')
+ api(project(":support-annotations"))
+ api(project(":support-compat"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation project(':support-testutils')
}
diff --git a/media-compat/java/android/support/v4/media/session/IMediaSession.aidl b/media-compat/java/android/support/v4/media/session/IMediaSession.aidl
index 56c04ac..f32f449 100644
--- a/media-compat/java/android/support/v4/media/session/IMediaSession.aidl
+++ b/media-compat/java/android/support/v4/media/session/IMediaSession.aidl
@@ -30,7 +30,7 @@
import java.util.List;
/**
- * Interface to a MediaSessionCompat. This is only used on pre-Lollipop systems.
+ * Interface to a MediaSessionCompat.
* @hide
*/
interface IMediaSession {
diff --git a/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java b/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
index 2509cd4..f24da1e 100644
--- a/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
+++ b/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
@@ -1919,6 +1919,7 @@
}
} else {
synchronized (mPendingCallbacks) {
+ callback.mHasExtraCallback = false;
mPendingCallbacks.add(callback);
}
}
@@ -1931,6 +1932,7 @@
try {
ExtraCallback extraCallback = mCallbackMap.remove(callback);
if (extraCallback != null) {
+ callback.mHasExtraCallback = false;
mExtraBinder.unregisterCallbackListener(extraCallback);
}
} catch (RemoteException e) {
diff --git a/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java b/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java
index d7634b0..3b06125 100644
--- a/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java
+++ b/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java
@@ -24,6 +24,7 @@
import android.os.Parcelable;
import android.os.SystemClock;
import android.support.annotation.IntDef;
+import android.support.annotation.LongDef;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.text.TextUtils;
@@ -45,7 +46,7 @@
* @hide
*/
@RestrictTo(LIBRARY_GROUP)
- @IntDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
+ @LongDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
@@ -58,7 +59,7 @@
* @hide
*/
@RestrictTo(LIBRARY_GROUP)
- @IntDef({ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND, ACTION_SKIP_TO_PREVIOUS,
+ @LongDef({ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND, ACTION_SKIP_TO_PREVIOUS,
ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_PLAY_PAUSE})
@Retention(RetentionPolicy.SOURCE)
public @interface MediaKeyAction {}
diff --git a/media-compat/lint-baseline.xml b/media-compat/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/media-compat/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/media-compat/tests/AndroidManifest.xml b/media-compat/tests/AndroidManifest.xml
deleted file mode 100644
index 6d9a4f6..0000000
--- a/media-compat/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 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="android.support.mediacompat.test">
- <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
-
- <application android:supportsRtl="true">
- <receiver android:name="android.support.v4.media.session.MediaButtonReceiver">
- <intent-filter>
- <action android:name="android.intent.action.MEDIA_BUTTON"/>
- </intent-filter>
- </receiver>
- <service android:name="android.support.v4.media.StubMediaBrowserServiceCompat">
- <intent-filter>
- <action android:name="android.media.browse.MediaBrowserService"/>
- </intent-filter>
- </service>
- <service android:name="android.support.v4.media.StubRemoteMediaBrowserServiceCompat"
- android:process=":remote">
- <intent-filter>
- <action android:name="android.media.browse.MediaBrowserService"/>
- </intent-filter>
- </service>
- <service
- android:name="android.support.v4.media.StubMediaBrowserServiceCompatWithDelayedMediaSession">
- <intent-filter>
- <action android:name="android.media.browse.MediaBrowserService"/>
- </intent-filter>
- </service>
- </application>
-
-</manifest>
diff --git a/media-compat/tests/src/android/support/v4/media/MediaBrowserCompatTest.java b/media-compat/tests/src/android/support/v4/media/MediaBrowserCompatTest.java
deleted file mode 100644
index 6356e33..0000000
--- a/media-compat/tests/src/android/support/v4/media/MediaBrowserCompatTest.java
+++ /dev/null
@@ -1,786 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.support.v4.media;
-
-import static android.support.test.InstrumentationRegistry.getInstrumentation;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-
-import android.content.ComponentName;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
-import android.support.v4.media.MediaBrowserCompat.MediaItem;
-import android.support.v4.media.session.MediaControllerCompat;
-import android.support.v4.media.session.MediaSessionCompat;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Test {@link android.support.v4.media.MediaBrowserCompat}.
- */
-@RunWith(AndroidJUnit4.class)
-public class MediaBrowserCompatTest {
-
- // The maximum time to wait for an operation.
- private static final long TIME_OUT_MS = 3000L;
-
- /**
- * To check {@link MediaBrowserCompat#unsubscribe} works properly,
- * we notify to the browser after the unsubscription that the media items have changed.
- * Then {@link MediaBrowserCompat.SubscriptionCallback#onChildrenLoaded} should not be called.
- *
- * The measured time from calling {@link StubMediaBrowserServiceCompat#notifyChildrenChanged}
- * to {@link MediaBrowserCompat.SubscriptionCallback#onChildrenLoaded} being called is about
- * 50ms.
- * So we make the thread sleep for 100ms to properly check that the callback is not called.
- */
- private static final long SLEEP_MS = 100L;
- private static final ComponentName TEST_BROWSER_SERVICE = new ComponentName(
- "android.support.mediacompat.test",
- "android.support.v4.media.StubMediaBrowserServiceCompat");
- private static final ComponentName TEST_REMOTE_BROWSER_SERVICE = new ComponentName(
- "android.support.mediacompat.test",
- "android.support.v4.media.StubRemoteMediaBrowserServiceCompat");
- private static final ComponentName TEST_INVALID_BROWSER_SERVICE = new ComponentName(
- "invalid.package", "invalid.ServiceClassName");
-
- private MediaBrowserCompat mMediaBrowser;
- private StubConnectionCallback mConnectionCallback;
- private StubSubscriptionCallback mSubscriptionCallback;
- private StubItemCallback mItemCallback;
-
- @Before
- public void setUp() {
- mConnectionCallback = new StubConnectionCallback();
- mSubscriptionCallback = new StubSubscriptionCallback();
- mItemCallback = new StubItemCallback();
- }
-
- @Test
- @SmallTest
- public void testMediaBrowser() throws Exception {
- createMediaBrowser(TEST_BROWSER_SERVICE);
- assertFalse(mMediaBrowser.isConnected());
-
- connectMediaBrowserService();
- assertTrue(mMediaBrowser.isConnected());
-
- assertEquals(TEST_BROWSER_SERVICE, mMediaBrowser.getServiceComponent());
- assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_ROOT, mMediaBrowser.getRoot());
- assertEquals(StubMediaBrowserServiceCompat.EXTRAS_VALUE,
- mMediaBrowser.getExtras().getString(StubMediaBrowserServiceCompat.EXTRAS_KEY));
- assertEquals(StubMediaBrowserServiceCompat.sSession.getSessionToken(),
- mMediaBrowser.getSessionToken());
-
- mMediaBrowser.disconnect();
- new PollingCheck(TIME_OUT_MS) {
- @Override
- protected boolean check() {
- return !mMediaBrowser.isConnected();
- }
- }.run();
- }
-
- @Test
- @SmallTest
- public void testMediaBrowserWithRemoteService() throws Exception {
- createMediaBrowser(TEST_REMOTE_BROWSER_SERVICE);
- assertFalse(mMediaBrowser.isConnected());
-
- connectMediaBrowserService();
- assertTrue(mMediaBrowser.isConnected());
-
- assertEquals(TEST_REMOTE_BROWSER_SERVICE, mMediaBrowser.getServiceComponent());
- assertEquals(StubRemoteMediaBrowserServiceCompat.MEDIA_ID_ROOT, mMediaBrowser.getRoot());
- assertEquals(StubRemoteMediaBrowserServiceCompat.EXTRAS_VALUE,
- mMediaBrowser.getExtras().getString(
- StubRemoteMediaBrowserServiceCompat.EXTRAS_KEY));
-
- mMediaBrowser.disconnect();
- new PollingCheck(TIME_OUT_MS) {
- @Override
- protected boolean check() {
- return !mMediaBrowser.isConnected();
- }
- }.run();
- }
-
- @Test
- @SmallTest
- public void testSessionReadyWithRemoteService() throws Exception {
- if (android.os.Build.VERSION.SDK_INT < 21) {
- // This test is for API 21+
- return;
- }
-
- createMediaBrowser(TEST_REMOTE_BROWSER_SERVICE);
- assertFalse(mMediaBrowser.isConnected());
-
- connectMediaBrowserService();
- assertTrue(mMediaBrowser.isConnected());
-
- // Create a session token by removing the extra binder of the token from MediaBrowserCompat.
- final MediaSessionCompat.Token tokenWithoutExtraBinder = MediaSessionCompat.Token.fromToken(
- mMediaBrowser.getSessionToken().getToken());
-
- final MediaControllerCallback callback = new MediaControllerCallback();
- synchronized (callback.mWaitLock) {
- getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- try {
- MediaControllerCompat controller = new MediaControllerCompat(
- getInstrumentation().getTargetContext(), tokenWithoutExtraBinder);
- controller.registerCallback(callback, new Handler());
- assertFalse(controller.isSessionReady());
- } catch (Exception e) {
- fail();
- }
- }
- });
- callback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(callback.mOnSessionReadyCalled);
- }
-
- mMediaBrowser.disconnect();
- }
-
- @Test
- @SmallTest
- public void testSubscriptionWithCustomOptionsWithRemoteService() throws Exception {
- final String mediaId = "1000";
- createMediaBrowser(TEST_REMOTE_BROWSER_SERVICE);
- assertFalse(mMediaBrowser.isConnected());
-
- connectMediaBrowserService();
- assertTrue(mMediaBrowser.isConnected());
-
- MediaMetadataCompat mediaMetadataCompat = new MediaMetadataCompat.Builder()
- .putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, mediaId)
- .putString(MediaMetadataCompat.METADATA_KEY_TITLE, "title")
- .putRating(MediaMetadataCompat.METADATA_KEY_RATING,
- RatingCompat.newPercentageRating(0.5f))
- .putRating(MediaMetadataCompat.METADATA_KEY_USER_RATING,
- RatingCompat.newPercentageRating(0.8f))
- .build();
- Bundle options = new Bundle();
- options.putParcelable(
- StubRemoteMediaBrowserServiceCompat.MEDIA_METADATA, mediaMetadataCompat);
-
- // Remote MediaBrowserService will create a media item with the given MediaMetadataCompat
- mMediaBrowser.subscribe(mMediaBrowser.getRoot(), options, mSubscriptionCallback);
- synchronized (mSubscriptionCallback.mWaitLock) {
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertEquals(1, mSubscriptionCallback.mChildrenLoadedWithOptionCount);
- assertEquals(1, mSubscriptionCallback.mLastChildMediaItems.size());
- assertEquals(mediaId, mSubscriptionCallback.mLastChildMediaItems.get(0).getMediaId());
- }
- mMediaBrowser.disconnect();
- }
-
- @Test
- @SmallTest
- public void testConnectTwice() throws Exception {
- createMediaBrowser(TEST_BROWSER_SERVICE);
- connectMediaBrowserService();
- try {
- mMediaBrowser.connect();
- fail();
- } catch (IllegalStateException e) {
- // expected
- }
- mMediaBrowser.disconnect();
- }
-
- @Test
- @SmallTest
- public void testConnectionFailed() throws Exception {
- createMediaBrowser(TEST_INVALID_BROWSER_SERVICE);
-
- synchronized (mConnectionCallback.mWaitLock) {
- mMediaBrowser.connect();
- mConnectionCallback.mWaitLock.wait(TIME_OUT_MS);
- }
- assertTrue(mConnectionCallback.mConnectionFailedCount > 0);
- assertEquals(0, mConnectionCallback.mConnectedCount);
- assertEquals(0, mConnectionCallback.mConnectionSuspendedCount);
- mMediaBrowser.disconnect();
- }
-
- @Test
- @SmallTest
- public void testReconnection() throws Exception {
- createMediaBrowser(TEST_BROWSER_SERVICE);
-
- getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- mMediaBrowser.connect();
- // Reconnect before the first connection was established.
- mMediaBrowser.disconnect();
- mMediaBrowser.connect();
- }
- });
-
- synchronized (mConnectionCallback.mWaitLock) {
- mConnectionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertEquals(1, mConnectionCallback.mConnectedCount);
- }
-
- synchronized (mSubscriptionCallback.mWaitLock) {
- // Test subscribe.
- resetCallbacks();
- mMediaBrowser.subscribe(
- StubMediaBrowserServiceCompat.MEDIA_ID_ROOT, mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedCount > 0);
- assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_ROOT,
- mSubscriptionCallback.mLastParentId);
- }
-
- synchronized (mItemCallback.mWaitLock) {
- // Test getItem.
- resetCallbacks();
- mMediaBrowser.getItem(
- StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN[0], mItemCallback);
- mItemCallback.mWaitLock.wait(TIME_OUT_MS);
- assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN[0],
- mItemCallback.mLastMediaItem.getMediaId());
- }
-
- // Reconnect after connection was established.
- mMediaBrowser.disconnect();
- resetCallbacks();
- connectMediaBrowserService();
-
- synchronized (mItemCallback.mWaitLock) {
- // Test getItem.
- resetCallbacks();
- mMediaBrowser.getItem(
- StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN[0], mItemCallback);
- mItemCallback.mWaitLock.wait(TIME_OUT_MS);
- assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN[0],
- mItemCallback.mLastMediaItem.getMediaId());
- }
- mMediaBrowser.disconnect();
- }
-
- @Test
- @SmallTest
- public void testConnectionCallbackNotCalledAfterDisconnect() {
- createMediaBrowser(TEST_BROWSER_SERVICE);
-
- getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- mMediaBrowser.connect();
- mMediaBrowser.disconnect();
- resetCallbacks();
- }
- });
-
- try {
- Thread.sleep(SLEEP_MS);
- } catch (InterruptedException e) {
- fail("Unexpected InterruptedException occurred.");
- }
- assertEquals(0, mConnectionCallback.mConnectedCount);
- assertEquals(0, mConnectionCallback.mConnectionFailedCount);
- assertEquals(0, mConnectionCallback.mConnectionSuspendedCount);
- }
-
- @Test
- @SmallTest
- public void testGetServiceComponentBeforeConnection() {
- createMediaBrowser(TEST_BROWSER_SERVICE);
- try {
- ComponentName serviceComponent = mMediaBrowser.getServiceComponent();
- fail();
- } catch (IllegalStateException e) {
- // expected
- }
- }
-
- @Test
- @SmallTest
- public void testSubscribe() throws Exception {
- createMediaBrowser(TEST_BROWSER_SERVICE);
- connectMediaBrowserService();
-
- synchronized (mSubscriptionCallback.mWaitLock) {
- mMediaBrowser.subscribe(
- StubMediaBrowserServiceCompat.MEDIA_ID_ROOT, mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedCount > 0);
- assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_ROOT,
- mSubscriptionCallback.mLastParentId);
- assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN.length,
- mSubscriptionCallback.mLastChildMediaItems.size());
- for (int i = 0; i < StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN.length; ++i) {
- assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN[i],
- mSubscriptionCallback.mLastChildMediaItems.get(i).getMediaId());
- }
- }
-
- // Test unsubscribe.
- resetCallbacks();
- mMediaBrowser.unsubscribe(StubMediaBrowserServiceCompat.MEDIA_ID_ROOT);
-
- // After unsubscribing, make StubMediaBrowserServiceCompat notify that the children are
- // changed.
- StubMediaBrowserServiceCompat.sInstance.notifyChildrenChanged(
- StubMediaBrowserServiceCompat.MEDIA_ID_ROOT);
- try {
- Thread.sleep(SLEEP_MS);
- } catch (InterruptedException e) {
- fail("Unexpected InterruptedException occurred.");
- }
- // onChildrenLoaded should not be called.
- assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
- mMediaBrowser.disconnect();
- }
-
- @Test
- @SmallTest
- public void testSubscribeWithOptions() throws Exception {
- createMediaBrowser(TEST_BROWSER_SERVICE);
- connectMediaBrowserService();
- final int pageSize = 3;
- final int lastPage =
- (StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN.length - 1) / pageSize;
- Bundle options = new Bundle();
- options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
-
- synchronized (mSubscriptionCallback.mWaitLock) {
- for (int page = 0; page <= lastPage; ++page) {
- resetCallbacks();
- options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
- mMediaBrowser.subscribe(StubMediaBrowserServiceCompat.MEDIA_ID_ROOT, options,
- mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedWithOptionCount > 0);
- assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_ROOT,
- mSubscriptionCallback.mLastParentId);
- if (page != lastPage) {
- assertEquals(pageSize, mSubscriptionCallback.mLastChildMediaItems.size());
- } else {
- assertEquals(
- (StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN.length - 1) % pageSize
- + 1,
- mSubscriptionCallback.mLastChildMediaItems.size());
- }
- // Check whether all the items in the current page are loaded.
- for (int i = 0; i < mSubscriptionCallback.mLastChildMediaItems.size(); ++i) {
- assertEquals(
- StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN[page * pageSize + i],
- mSubscriptionCallback.mLastChildMediaItems.get(i).getMediaId());
- }
- }
- }
-
- // Test unsubscribe with callback argument.
- resetCallbacks();
- mMediaBrowser.unsubscribe(StubMediaBrowserServiceCompat.MEDIA_ID_ROOT,
- mSubscriptionCallback);
-
- // After unsubscribing, make StubMediaBrowserServiceCompat notify that the children are
- // changed.
- StubMediaBrowserServiceCompat.sInstance.notifyChildrenChanged(
- StubMediaBrowserServiceCompat.MEDIA_ID_ROOT);
- try {
- Thread.sleep(SLEEP_MS);
- } catch (InterruptedException e) {
- fail("Unexpected InterruptedException occurred.");
- }
- // onChildrenLoaded should not be called.
- assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
- mMediaBrowser.disconnect();
- }
-
- @Test
- @SmallTest
- public void testSubscribeInvalidItem() throws Exception {
- createMediaBrowser(TEST_BROWSER_SERVICE);
- connectMediaBrowserService();
-
- synchronized (mSubscriptionCallback.mWaitLock) {
- mMediaBrowser.subscribe(StubMediaBrowserServiceCompat.MEDIA_ID_INVALID,
- mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_INVALID,
- mSubscriptionCallback.mLastErrorId);
- }
- mMediaBrowser.disconnect();
- }
-
- @Test
- @SmallTest
- public void testSubscribeInvalidItemWithOptions() throws Exception {
- createMediaBrowser(TEST_BROWSER_SERVICE);
- connectMediaBrowserService();
-
- final int pageSize = 5;
- final int page = 2;
- Bundle options = new Bundle();
- options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
- options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
-
- synchronized (mSubscriptionCallback.mWaitLock) {
- mMediaBrowser.subscribe(StubMediaBrowserServiceCompat.MEDIA_ID_INVALID, options,
- mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_INVALID,
- mSubscriptionCallback.mLastErrorId);
- assertNotNull(mSubscriptionCallback.mLastOptions);
- assertEquals(page,
- mSubscriptionCallback.mLastOptions.getInt(MediaBrowserCompat.EXTRA_PAGE));
- assertEquals(pageSize,
- mSubscriptionCallback.mLastOptions.getInt(MediaBrowserCompat.EXTRA_PAGE_SIZE));
- }
- mMediaBrowser.disconnect();
- }
-
- @Test
- @SmallTest
- public void testUnsubscribeForMultipleSubscriptions() throws Exception {
- createMediaBrowser(TEST_BROWSER_SERVICE);
- connectMediaBrowserService();
- final List<StubSubscriptionCallback> subscriptionCallbacks = new ArrayList<>();
- final int pageSize = 1;
-
- // Subscribe four pages, one item per page.
- for (int page = 0; page < 4; page++) {
- final StubSubscriptionCallback callback = new StubSubscriptionCallback();
- subscriptionCallbacks.add(callback);
-
- Bundle options = new Bundle();
- options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
- options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
- mMediaBrowser.subscribe(StubMediaBrowserServiceCompat.MEDIA_ID_ROOT, options,
- callback);
- synchronized (callback.mWaitLock) {
- callback.mWaitLock.wait(TIME_OUT_MS);
- }
- // Each onChildrenLoaded() must be called.
- assertEquals(1, callback.mChildrenLoadedWithOptionCount);
- }
-
- // Reset callbacks and unsubscribe.
- for (StubSubscriptionCallback callback : subscriptionCallbacks) {
- callback.reset();
- }
- mMediaBrowser.unsubscribe(StubMediaBrowserServiceCompat.MEDIA_ID_ROOT);
-
- // After unsubscribing, make StubMediaBrowserServiceCompat notify that the children are
- // changed.
- StubMediaBrowserServiceCompat.sInstance.notifyChildrenChanged(
- StubMediaBrowserServiceCompat.MEDIA_ID_ROOT);
- try {
- Thread.sleep(SLEEP_MS);
- } catch (InterruptedException e) {
- fail("Unexpected InterruptedException occurred.");
- }
-
- // onChildrenLoaded should not be called.
- for (StubSubscriptionCallback callback : subscriptionCallbacks) {
- assertEquals(0, callback.mChildrenLoadedWithOptionCount);
- }
- mMediaBrowser.disconnect();
- }
-
- @Test
- @MediumTest
- public void testUnsubscribeWithSubscriptionCallbackForMultipleSubscriptions() throws Exception {
- createMediaBrowser(TEST_BROWSER_SERVICE);
- connectMediaBrowserService();
- final List<StubSubscriptionCallback> subscriptionCallbacks = new ArrayList<>();
- final int pageSize = 1;
-
- // Subscribe four pages, one item per page.
- for (int page = 0; page < 4; page++) {
- final StubSubscriptionCallback callback = new StubSubscriptionCallback();
- subscriptionCallbacks.add(callback);
-
- Bundle options = new Bundle();
- options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
- options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
- mMediaBrowser.subscribe(StubMediaBrowserServiceCompat.MEDIA_ID_ROOT, options,
- callback);
- synchronized (callback.mWaitLock) {
- callback.mWaitLock.wait(TIME_OUT_MS);
- }
- // Each onChildrenLoaded() must be called.
- assertEquals(1, callback.mChildrenLoadedWithOptionCount);
- }
-
- // Unsubscribe existing subscriptions one-by-one.
- final int[] orderOfRemovingCallbacks = {2, 0, 3, 1};
- for (int i = 0; i < orderOfRemovingCallbacks.length; i++) {
- // Reset callbacks
- for (StubSubscriptionCallback callback : subscriptionCallbacks) {
- callback.reset();
- }
-
- // Remove one subscription
- mMediaBrowser.unsubscribe(StubMediaBrowserServiceCompat.MEDIA_ID_ROOT,
- subscriptionCallbacks.get(orderOfRemovingCallbacks[i]));
-
- // Make StubMediaBrowserServiceCompat notify that the children are changed.
- StubMediaBrowserServiceCompat.sInstance.notifyChildrenChanged(
- StubMediaBrowserServiceCompat.MEDIA_ID_ROOT);
- try {
- Thread.sleep(SLEEP_MS);
- } catch (InterruptedException e) {
- fail("Unexpected InterruptedException occurred.");
- }
-
- // Only the remaining subscriptionCallbacks should be called.
- for (int j = 0; j < 4; j++) {
- int childrenLoadedWithOptionsCount = subscriptionCallbacks
- .get(orderOfRemovingCallbacks[j]).mChildrenLoadedWithOptionCount;
- if (j <= i) {
- assertEquals(0, childrenLoadedWithOptionsCount);
- } else {
- assertEquals(1, childrenLoadedWithOptionsCount);
- }
- }
- }
- mMediaBrowser.disconnect();
- }
-
- @Test
- @SmallTest
- public void testGetItem() throws Exception {
- createMediaBrowser(TEST_BROWSER_SERVICE);
- connectMediaBrowserService();
-
- synchronized (mItemCallback.mWaitLock) {
- mMediaBrowser.getItem(StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN[0],
- mItemCallback);
- mItemCallback.mWaitLock.wait(TIME_OUT_MS);
- assertNotNull(mItemCallback.mLastMediaItem);
- assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN[0],
- mItemCallback.mLastMediaItem.getMediaId());
- }
- mMediaBrowser.disconnect();
- }
-
- @Test
- @LargeTest
- public void testGetItemWhenOnLoadItemIsNotImplemented() throws Exception {
- createMediaBrowser(TEST_BROWSER_SERVICE);
- connectMediaBrowserService();
- synchronized (mItemCallback.mWaitLock) {
- mMediaBrowser.getItem(
- StubMediaBrowserServiceCompat.MEDIA_ID_ON_LOAD_ITEM_NOT_IMPLEMENTED,
- mItemCallback);
- mItemCallback.mWaitLock.wait(TIME_OUT_MS);
- assertEquals(StubMediaBrowserServiceCompat.MEDIA_ID_ON_LOAD_ITEM_NOT_IMPLEMENTED,
- mItemCallback.mLastErrorId);
- }
- mMediaBrowser.disconnect();
- }
-
- @Test
- @SmallTest
- public void testGetItemWhenMediaIdIsInvalid() throws Exception {
- mItemCallback.mLastMediaItem = new MediaItem(new MediaDescriptionCompat.Builder()
- .setMediaId("dummy_id").build(), MediaItem.FLAG_BROWSABLE);
-
- createMediaBrowser(TEST_BROWSER_SERVICE);
- connectMediaBrowserService();
- synchronized (mItemCallback.mWaitLock) {
- mMediaBrowser.getItem(StubMediaBrowserServiceCompat.MEDIA_ID_INVALID, mItemCallback);
- mItemCallback.mWaitLock.wait(TIME_OUT_MS);
- assertNull(mItemCallback.mLastMediaItem);
- assertNull(mItemCallback.mLastErrorId);
- }
- mMediaBrowser.disconnect();
- }
-
- private void createMediaBrowser(final ComponentName component) {
- getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- mMediaBrowser = new MediaBrowserCompat(getInstrumentation().getTargetContext(),
- component, mConnectionCallback, null);
- }
- });
- }
-
- private void connectMediaBrowserService() throws Exception {
- synchronized (mConnectionCallback.mWaitLock) {
- mMediaBrowser.connect();
- mConnectionCallback.mWaitLock.wait(TIME_OUT_MS);
- }
- }
-
- private void resetCallbacks() {
- mConnectionCallback.reset();
- mSubscriptionCallback.reset();
- mItemCallback.reset();
- }
-
- private class StubConnectionCallback extends MediaBrowserCompat.ConnectionCallback {
- Object mWaitLock = new Object();
- volatile int mConnectedCount;
- volatile int mConnectionFailedCount;
- volatile int mConnectionSuspendedCount;
-
- public void reset() {
- mConnectedCount = 0;
- mConnectionFailedCount = 0;
- mConnectionSuspendedCount = 0;
- }
-
- @Override
- public void onConnected() {
- synchronized (mWaitLock) {
- mConnectedCount++;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onConnectionFailed() {
- synchronized (mWaitLock) {
- mConnectionFailedCount++;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onConnectionSuspended() {
- synchronized (mWaitLock) {
- mConnectionSuspendedCount++;
- mWaitLock.notify();
- }
- }
- }
-
- private class StubSubscriptionCallback extends MediaBrowserCompat.SubscriptionCallback {
- Object mWaitLock = new Object();
- private volatile int mChildrenLoadedCount;
- private volatile int mChildrenLoadedWithOptionCount;
- private volatile String mLastErrorId;
- private volatile String mLastParentId;
- private volatile Bundle mLastOptions;
- private volatile List<MediaItem> mLastChildMediaItems;
-
- public void reset() {
- mChildrenLoadedCount = 0;
- mChildrenLoadedWithOptionCount = 0;
- mLastErrorId = null;
- mLastParentId = null;
- mLastOptions = null;
- mLastChildMediaItems = null;
- }
-
- @Override
- public void onChildrenLoaded(String parentId, List<MediaItem> children) {
- synchronized (mWaitLock) {
- mChildrenLoadedCount++;
- mLastParentId = parentId;
- mLastChildMediaItems = children;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onChildrenLoaded(String parentId, List<MediaItem> children, Bundle options) {
- synchronized (mWaitLock) {
- mChildrenLoadedWithOptionCount++;
- mLastParentId = parentId;
- mLastOptions = options;
- mLastChildMediaItems = children;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onError(String id) {
- synchronized (mWaitLock) {
- mLastErrorId = id;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onError(String id, Bundle options) {
- synchronized (mWaitLock) {
- mLastErrorId = id;
- mLastOptions = options;
- mWaitLock.notify();
- }
- }
- }
-
- private class StubItemCallback extends MediaBrowserCompat.ItemCallback {
- Object mWaitLock = new Object();
- private volatile MediaItem mLastMediaItem;
- private volatile String mLastErrorId;
-
- public void reset() {
- mLastMediaItem = null;
- mLastErrorId = null;
- }
-
- @Override
- public void onItemLoaded(MediaItem item) {
- synchronized (mWaitLock) {
- mLastMediaItem = item;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onError(String id) {
- synchronized (mWaitLock) {
- mLastErrorId = id;
- mWaitLock.notify();
- }
- }
- }
-
- private class MediaControllerCallback extends MediaControllerCompat.Callback {
- Object mWaitLock = new Object();
- private volatile boolean mOnSessionReadyCalled;
-
- @Override
- public void onSessionReady() {
- synchronized (mWaitLock) {
- mOnSessionReadyCalled = true;
- mWaitLock.notify();
- }
- }
- }
-}
diff --git a/media-compat/tests/src/android/support/v4/media/MediaBrowserServiceCompatTest.java b/media-compat/tests/src/android/support/v4/media/MediaBrowserServiceCompatTest.java
deleted file mode 100644
index 4ceac10..0000000
--- a/media-compat/tests/src/android/support/v4/media/MediaBrowserServiceCompatTest.java
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.support.v4.media;
-
-import static android.support.test.InstrumentationRegistry.getInstrumentation;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-
-import android.content.ComponentName;
-import android.os.Build;
-import android.os.Bundle;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
-import android.support.v4.media.MediaBrowserCompat.MediaItem;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-/**
- * Test {@link android.support.v4.media.MediaBrowserServiceCompat}.
- */
-@RunWith(AndroidJUnit4.class)
-public class MediaBrowserServiceCompatTest {
- // The maximum time to wait for an operation.
- private static final long TIME_OUT_MS = 3000L;
- private static final long WAIT_TIME_FOR_NO_RESPONSE_MS = 500L;
- private static final ComponentName TEST_BROWSER_SERVICE = new ComponentName(
- "android.support.mediacompat.test",
- "android.support.v4.media.StubMediaBrowserServiceCompat");
- private static final ComponentName TEST_BROWSER_SERVICE_DELAYED_MEDIA_SESSION =
- new ComponentName(
- "android.support.mediacompat.test",
- "android.support.v4.media"
- + ".StubMediaBrowserServiceCompatWithDelayedMediaSession");
- private static final String TEST_KEY_1 = "key_1";
- private static final String TEST_VALUE_1 = "value_1";
- private static final String TEST_KEY_2 = "key_2";
- private static final String TEST_VALUE_2 = "value_2";
- private static final String TEST_KEY_3 = "key_3";
- private static final String TEST_VALUE_3 = "value_3";
- private static final String TEST_KEY_4 = "key_4";
- private static final String TEST_VALUE_4 = "value_4";
- private final Object mWaitLock = new Object();
-
- private final ConnectionCallback mConnectionCallback = new ConnectionCallback();
- private final SubscriptionCallback mSubscriptionCallback = new SubscriptionCallback();
- private final ItemCallback mItemCallback = new ItemCallback();
- private final SearchCallback mSearchCallback = new SearchCallback();
-
- private MediaBrowserCompat mMediaBrowser;
- private MediaBrowserCompat mMediaBrowserForDelayedMediaSession;
- private StubMediaBrowserServiceCompat mMediaBrowserService;
- private Bundle mRootHints;
-
- @Before
- public void setUp() throws Exception {
- getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- mRootHints = new Bundle();
- mRootHints.putBoolean(MediaBrowserServiceCompat.BrowserRoot.EXTRA_RECENT, true);
- mRootHints.putBoolean(MediaBrowserServiceCompat.BrowserRoot.EXTRA_OFFLINE, true);
- mRootHints.putBoolean(MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTED, true);
- mMediaBrowser = new MediaBrowserCompat(getInstrumentation().getTargetContext(),
- TEST_BROWSER_SERVICE, mConnectionCallback, mRootHints);
- }
- });
- synchronized (mWaitLock) {
- mMediaBrowser.connect();
- mWaitLock.wait(TIME_OUT_MS);
- }
- assertNotNull(mMediaBrowserService);
- mMediaBrowserService.mCustomActionExtras = null;
- mMediaBrowserService.mCustomActionResult = null;
- }
-
- @Test
- @SmallTest
- public void testGetSessionToken() {
- assertEquals(StubMediaBrowserServiceCompat.sSession.getSessionToken(),
- mMediaBrowserService.getSessionToken());
- }
-
- @Test
- @SmallTest
- public void testNotifyChildrenChanged() throws Exception {
- synchronized (mWaitLock) {
- mSubscriptionCallback.reset();
- mMediaBrowser.subscribe(
- StubMediaBrowserServiceCompat.MEDIA_ID_ROOT, mSubscriptionCallback);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mOnChildrenLoaded);
-
- mSubscriptionCallback.reset();
- mMediaBrowserService.notifyChildrenChanged(StubMediaBrowserServiceCompat.MEDIA_ID_ROOT);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mOnChildrenLoaded);
- }
- }
-
- @Test
- @SmallTest
- public void testNotifyChildrenChangedWithPagination() throws Exception {
- synchronized (mWaitLock) {
- final int pageSize = 5;
- final int page = 2;
- Bundle options = new Bundle();
- options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
- options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
-
- mSubscriptionCallback.reset();
- mMediaBrowser.subscribe(StubMediaBrowserServiceCompat.MEDIA_ID_ROOT, options,
- mSubscriptionCallback);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mOnChildrenLoadedWithOptions);
-
- mSubscriptionCallback.reset();
- mMediaBrowserService.notifyChildrenChanged(StubMediaBrowserServiceCompat.MEDIA_ID_ROOT);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mOnChildrenLoadedWithOptions);
- }
- }
-
- @Test
- @MediumTest
- public void testDelayedNotifyChildrenChanged() throws Exception {
- synchronized (mWaitLock) {
- mSubscriptionCallback.reset();
- mMediaBrowser.subscribe(StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN_DELAYED,
- mSubscriptionCallback);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertFalse(mSubscriptionCallback.mOnChildrenLoaded);
-
- mMediaBrowserService.sendDelayedNotifyChildrenChanged();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mOnChildrenLoaded);
-
- mSubscriptionCallback.reset();
- mMediaBrowserService.notifyChildrenChanged(
- StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN_DELAYED);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertFalse(mSubscriptionCallback.mOnChildrenLoaded);
-
- mMediaBrowserService.sendDelayedNotifyChildrenChanged();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mOnChildrenLoaded);
- }
- }
-
- @Test
- @MediumTest
- public void testDelayedItem() throws Exception {
- synchronized (mWaitLock) {
- mItemCallback.reset();
- mMediaBrowser.getItem(
- StubMediaBrowserServiceCompat.MEDIA_ID_CHILDREN_DELAYED, mItemCallback);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertFalse(mItemCallback.mOnItemLoaded);
-
- mItemCallback.reset();
- mMediaBrowserService.sendDelayedItemLoaded();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mItemCallback.mOnItemLoaded);
- }
- }
-
- @Test
- @SmallTest
- public void testSearch() throws Exception {
- final String key = "test-key";
- final String val = "test-val";
-
- synchronized (mWaitLock) {
- mSearchCallback.reset();
- mMediaBrowser.search(StubMediaBrowserServiceCompat.SEARCH_QUERY_FOR_NO_RESULT, null,
- mSearchCallback);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertTrue(mSearchCallback.mOnSearchResult);
- assertTrue(mSearchCallback.mSearchResults != null
- && mSearchCallback.mSearchResults.size() == 0);
- assertEquals(null, mSearchCallback.mSearchExtras);
-
- mSearchCallback.reset();
- mMediaBrowser.search(StubMediaBrowserServiceCompat.SEARCH_QUERY_FOR_ERROR, null,
- mSearchCallback);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertTrue(mSearchCallback.mOnSearchResult);
- assertNull(mSearchCallback.mSearchResults);
- assertEquals(null, mSearchCallback.mSearchExtras);
-
- mSearchCallback.reset();
- Bundle extras = new Bundle();
- extras.putString(key, val);
- mMediaBrowser.search(StubMediaBrowserServiceCompat.SEARCH_QUERY, extras,
- mSearchCallback);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertTrue(mSearchCallback.mOnSearchResult);
- assertNotNull(mSearchCallback.mSearchResults);
- for (MediaItem item : mSearchCallback.mSearchResults) {
- assertNotNull(item.getMediaId());
- assertTrue(item.getMediaId().contains(StubMediaBrowserServiceCompat.SEARCH_QUERY));
- }
- assertNotNull(mSearchCallback.mSearchExtras);
- assertEquals(val, mSearchCallback.mSearchExtras.getString(key));
- }
- }
-
- @Test
- @SmallTest
- public void testSendCustomAction() throws Exception {
- synchronized (mWaitLock) {
- CustomActionCallback callback = new CustomActionCallback();
- Bundle extras = new Bundle();
- extras.putString(TEST_KEY_1, TEST_VALUE_1);
- mMediaBrowser.sendCustomAction(StubMediaBrowserServiceCompat.CUSTOM_ACTION, extras,
- callback);
- new PollingCheck(TIME_OUT_MS) {
- @Override
- protected boolean check() {
- return mMediaBrowserService.mCustomActionResult != null;
- }
- }.run();
- assertNotNull(mMediaBrowserService.mCustomActionResult);
- assertNotNull(mMediaBrowserService.mCustomActionExtras);
- assertEquals(TEST_VALUE_1,
- mMediaBrowserService.mCustomActionExtras.getString(TEST_KEY_1));
-
- callback.reset();
- Bundle bundle1 = new Bundle();
- bundle1.putString(TEST_KEY_2, TEST_VALUE_2);
- mMediaBrowserService.mCustomActionResult.sendProgressUpdate(bundle1);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertTrue(callback.mOnProgressUpdateCalled);
- assertNotNull(callback.mExtras);
- assertEquals(TEST_VALUE_1, callback.mExtras.getString(TEST_KEY_1));
- assertNotNull(callback.mData);
- assertEquals(TEST_VALUE_2, callback.mData.getString(TEST_KEY_2));
-
- callback.reset();
- Bundle bundle2 = new Bundle();
- bundle2.putString(TEST_KEY_3, TEST_VALUE_3);
- mMediaBrowserService.mCustomActionResult.sendProgressUpdate(bundle2);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertTrue(callback.mOnProgressUpdateCalled);
- assertNotNull(callback.mExtras);
- assertEquals(TEST_VALUE_1, callback.mExtras.getString(TEST_KEY_1));
- assertNotNull(callback.mData);
- assertEquals(TEST_VALUE_3, callback.mData.getString(TEST_KEY_3));
-
- Bundle bundle3 = new Bundle();
- bundle3.putString(TEST_KEY_4, TEST_VALUE_4);
- callback.reset();
- mMediaBrowserService.mCustomActionResult.sendResult(bundle3);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertTrue(callback.mOnResultCalled);
- assertNotNull(callback.mExtras);
- assertEquals(TEST_VALUE_1, callback.mExtras.getString(TEST_KEY_1));
- assertNotNull(callback.mData);
- assertEquals(TEST_VALUE_4, callback.mData.getString(TEST_KEY_4));
- }
- }
-
- @Test
- @SmallTest
- public void testSendCustomActionWithDetachedError() throws Exception {
- synchronized (mWaitLock) {
- CustomActionCallback callback = new CustomActionCallback();
- Bundle extras = new Bundle();
- extras.putString(TEST_KEY_1, TEST_VALUE_1);
- mMediaBrowser.sendCustomAction(StubMediaBrowserServiceCompat.CUSTOM_ACTION, extras,
- callback);
- new PollingCheck(TIME_OUT_MS) {
- @Override
- protected boolean check() {
- return mMediaBrowserService.mCustomActionResult != null;
- }
- }.run();
- assertNotNull(mMediaBrowserService.mCustomActionResult);
- assertNotNull(mMediaBrowserService.mCustomActionExtras);
- assertEquals(TEST_VALUE_1,
- mMediaBrowserService.mCustomActionExtras.getString(TEST_KEY_1));
-
- callback.reset();
- Bundle bundle1 = new Bundle();
- bundle1.putString(TEST_KEY_2, TEST_VALUE_2);
- mMediaBrowserService.mCustomActionResult.sendProgressUpdate(bundle1);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertTrue(callback.mOnProgressUpdateCalled);
- assertNotNull(callback.mExtras);
- assertEquals(TEST_VALUE_1, callback.mExtras.getString(TEST_KEY_1));
- assertNotNull(callback.mData);
- assertEquals(TEST_VALUE_2, callback.mData.getString(TEST_KEY_2));
-
- callback.reset();
- Bundle bundle2 = new Bundle();
- bundle2.putString(TEST_KEY_3, TEST_VALUE_3);
- mMediaBrowserService.mCustomActionResult.sendError(bundle2);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertTrue(callback.mOnErrorCalled);
- assertNotNull(callback.mExtras);
- assertEquals(TEST_VALUE_1, callback.mExtras.getString(TEST_KEY_1));
- assertNotNull(callback.mData);
- assertEquals(TEST_VALUE_3, callback.mData.getString(TEST_KEY_3));
- }
- }
-
- @Test
- @SmallTest
- public void testSendCustomActionWithNullCallback() throws Exception {
- Bundle extras = new Bundle();
- extras.putString(TEST_KEY_1, TEST_VALUE_1);
- mMediaBrowser.sendCustomAction(StubMediaBrowserServiceCompat.CUSTOM_ACTION, extras, null);
- new PollingCheck(TIME_OUT_MS) {
- @Override
- protected boolean check() {
- return mMediaBrowserService.mCustomActionResult != null;
- }
- }.run();
- assertNotNull(mMediaBrowserService.mCustomActionResult);
- assertNotNull(mMediaBrowserService.mCustomActionExtras);
- assertEquals(TEST_VALUE_1, mMediaBrowserService.mCustomActionExtras.getString(TEST_KEY_1));
- }
-
- @Test
- @SmallTest
- public void testSendCustomActionWithError() throws Exception {
- synchronized (mWaitLock) {
- CustomActionCallback callback = new CustomActionCallback();
- mMediaBrowser.sendCustomAction(StubMediaBrowserServiceCompat.CUSTOM_ACTION_FOR_ERROR,
- null, callback);
- new PollingCheck(TIME_OUT_MS) {
- @Override
- protected boolean check() {
- return mMediaBrowserService.mCustomActionResult != null;
- }
- }.run();
- assertNotNull(mMediaBrowserService.mCustomActionResult);
- assertNull(mMediaBrowserService.mCustomActionExtras);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertTrue(callback.mOnErrorCalled);
- }
- }
-
- @Test
- @SmallTest
- public void testBrowserRoot() {
- final String id = "test-id";
- final String key = "test-key";
- final String val = "test-val";
- final Bundle extras = new Bundle();
- extras.putString(key, val);
-
- MediaBrowserServiceCompat.BrowserRoot browserRoot =
- new MediaBrowserServiceCompat.BrowserRoot(id, extras);
- assertEquals(id, browserRoot.getRootId());
- assertEquals(val, browserRoot.getExtras().getString(key));
- }
-
- @Test
- @SmallTest
- public void testDelayedSetSessionToken() throws Exception {
- // This test has no meaning in API 21. The framework MediaBrowserService just connects to
- // the media browser without waiting setMediaSession() to be called.
- if (Build.VERSION.SDK_INT == 21) {
- return;
- }
- final ConnectionCallbackForDelayedMediaSession callback =
- new ConnectionCallbackForDelayedMediaSession();
-
- getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- mMediaBrowserForDelayedMediaSession =
- new MediaBrowserCompat(getInstrumentation().getTargetContext(),
- TEST_BROWSER_SERVICE_DELAYED_MEDIA_SESSION, callback, null);
- }
- });
-
- synchronized (mWaitLock) {
- mMediaBrowserForDelayedMediaSession.connect();
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertEquals(0, callback.mConnectedCount);
-
- StubMediaBrowserServiceCompatWithDelayedMediaSession.sInstance.callSetSessionToken();
- mWaitLock.wait(TIME_OUT_MS);
- assertEquals(1, callback.mConnectedCount);
-
- if (Build.VERSION.SDK_INT >= 21) {
- assertNotNull(
- mMediaBrowserForDelayedMediaSession.getSessionToken().getExtraBinder());
- }
- }
- }
-
- private void assertRootHints(MediaItem item) {
- Bundle rootHints = item.getDescription().getExtras();
- assertNotNull(rootHints);
- assertEquals(mRootHints.getBoolean(MediaBrowserServiceCompat.BrowserRoot.EXTRA_RECENT),
- rootHints.getBoolean(MediaBrowserServiceCompat.BrowserRoot.EXTRA_RECENT));
- assertEquals(mRootHints.getBoolean(MediaBrowserServiceCompat.BrowserRoot.EXTRA_OFFLINE),
- rootHints.getBoolean(MediaBrowserServiceCompat.BrowserRoot.EXTRA_OFFLINE));
- assertEquals(mRootHints.getBoolean(MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTED),
- rootHints.getBoolean(MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTED));
- }
-
- private class ConnectionCallback extends MediaBrowserCompat.ConnectionCallback {
- @Override
- public void onConnected() {
- synchronized (mWaitLock) {
- mMediaBrowserService = StubMediaBrowserServiceCompat.sInstance;
- mWaitLock.notify();
- }
- }
- }
-
- private class SubscriptionCallback extends MediaBrowserCompat.SubscriptionCallback {
- boolean mOnChildrenLoaded;
- boolean mOnChildrenLoadedWithOptions;
-
- @Override
- public void onChildrenLoaded(String parentId, List<MediaItem> children) {
- synchronized (mWaitLock) {
- mOnChildrenLoaded = true;
- if (children != null) {
- for (MediaItem item : children) {
- assertRootHints(item);
- }
- }
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onChildrenLoaded(String parentId, List<MediaItem> children, Bundle options) {
- synchronized (mWaitLock) {
- mOnChildrenLoadedWithOptions = true;
- if (children != null) {
- for (MediaItem item : children) {
- assertRootHints(item);
- }
- }
- mWaitLock.notify();
- }
- }
-
- public void reset() {
- mOnChildrenLoaded = false;
- mOnChildrenLoadedWithOptions = false;
- }
- }
-
- private class ItemCallback extends MediaBrowserCompat.ItemCallback {
- boolean mOnItemLoaded;
-
- @Override
- public void onItemLoaded(MediaItem item) {
- synchronized (mWaitLock) {
- mOnItemLoaded = true;
- assertRootHints(item);
- mWaitLock.notify();
- }
- }
-
- public void reset() {
- mOnItemLoaded = false;
- }
- }
-
- private class SearchCallback extends MediaBrowserCompat.SearchCallback {
- boolean mOnSearchResult;
- Bundle mSearchExtras;
- List<MediaItem> mSearchResults;
-
- @Override
- public void onSearchResult(String query, Bundle extras, List<MediaItem> items) {
- synchronized (mWaitLock) {
- mOnSearchResult = true;
- mSearchResults = items;
- mSearchExtras = extras;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onError(String query, Bundle extras) {
- synchronized (mWaitLock) {
- mOnSearchResult = true;
- mSearchResults = null;
- mSearchExtras = extras;
- mWaitLock.notify();
- }
- }
-
- public void reset() {
- mOnSearchResult = false;
- mSearchExtras = null;
- mSearchResults = null;
- }
- }
-
- private class CustomActionCallback extends MediaBrowserCompat.CustomActionCallback {
- String mAction;
- Bundle mExtras;
- Bundle mData;
- boolean mOnProgressUpdateCalled;
- boolean mOnResultCalled;
- boolean mOnErrorCalled;
-
- @Override
- public void onProgressUpdate(String action, Bundle extras, Bundle data) {
- synchronized (mWaitLock) {
- mOnProgressUpdateCalled = true;
- mAction = action;
- mExtras = extras;
- mData = data;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onResult(String action, Bundle extras, Bundle resultData) {
- synchronized (mWaitLock) {
- mOnResultCalled = true;
- mAction = action;
- mExtras = extras;
- mData = resultData;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onError(String action, Bundle extras, Bundle data) {
- synchronized (mWaitLock) {
- mOnErrorCalled = true;
- mAction = action;
- mExtras = extras;
- mData = data;
- mWaitLock.notify();
- }
- }
-
- public void reset() {
- mOnResultCalled = false;
- mOnProgressUpdateCalled = false;
- mOnErrorCalled = false;
- mAction = null;
- mExtras = null;
- mData = null;
- }
- }
-
- private class ConnectionCallbackForDelayedMediaSession extends
- MediaBrowserCompat.ConnectionCallback {
- private int mConnectedCount = 0;
-
- @Override
- public void onConnected() {
- synchronized (mWaitLock) {
- mConnectedCount++;
- mWaitLock.notify();
- }
- }
- }
-}
diff --git a/media-compat/tests/src/android/support/v4/media/StubMediaBrowserServiceCompat.java b/media-compat/tests/src/android/support/v4/media/StubMediaBrowserServiceCompat.java
deleted file mode 100644
index c817dce..0000000
--- a/media-compat/tests/src/android/support/v4/media/StubMediaBrowserServiceCompat.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.support.v4.media;
-
-import android.os.Bundle;
-import android.support.v4.media.MediaBrowserCompat.MediaItem;
-import android.support.v4.media.session.MediaSessionCompat;
-
-import junit.framework.Assert;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Stub implementation of {@link android.support.v4.media.MediaBrowserServiceCompat}.
- */
-public class StubMediaBrowserServiceCompat extends MediaBrowserServiceCompat {
- static final String EXTRAS_KEY = "test_extras_key";
- static final String EXTRAS_VALUE = "test_extras_value";
-
- static final String MEDIA_ID = "test_media_id";
- static final String MEDIA_ID_INVALID = "test_media_id_invalid";
- static final String MEDIA_ID_ROOT = "test_media_id_root";
- static final String MEDIA_ID_CHILDREN_DELAYED = "test_media_id_children_delayed";
- static final String MEDIA_ID_ON_LOAD_ITEM_NOT_IMPLEMENTED =
- "test_media_id_on_load_item_not_implemented";
-
- static final String[] MEDIA_ID_CHILDREN = new String[]{
- "test_media_id_children_0", "test_media_id_children_1",
- "test_media_id_children_2", "test_media_id_children_3",
- MEDIA_ID_CHILDREN_DELAYED
- };
-
- static final String SEARCH_QUERY = "children_2";
- static final String SEARCH_QUERY_FOR_NO_RESULT = "query no result";
- static final String SEARCH_QUERY_FOR_ERROR = "query for error";
-
- static final String CUSTOM_ACTION = "CUSTOM_ACTION";
- static final String CUSTOM_ACTION_FOR_ERROR = "CUSTOM_ACTION_FOR_ERROR";
-
- static StubMediaBrowserServiceCompat sInstance;
-
- /* package private */ static MediaSessionCompat sSession;
- private Bundle mExtras;
- private Result<List<MediaItem>> mPendingLoadChildrenResult;
- private Result<MediaItem> mPendingLoadItemResult;
- private Bundle mPendingRootHints;
-
- /* package private */ Bundle mCustomActionExtras;
- /* package private */ Result<Bundle> mCustomActionResult;
-
- @Override
- public void onCreate() {
- super.onCreate();
- sInstance = this;
- sSession = new MediaSessionCompat(this, "StubMediaBrowserServiceCompat");
- setSessionToken(sSession.getSessionToken());
- }
-
- @Override
- public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
- mExtras = new Bundle();
- mExtras.putString(EXTRAS_KEY, EXTRAS_VALUE);
- return new BrowserRoot(MEDIA_ID_ROOT, mExtras);
- }
-
- @Override
- public void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result) {
- List<MediaItem> mediaItems = new ArrayList<>();
- if (MEDIA_ID_ROOT.equals(parentMediaId)) {
- Bundle rootHints = getBrowserRootHints();
- for (String id : MEDIA_ID_CHILDREN) {
- mediaItems.add(createMediaItem(id));
- }
- result.sendResult(mediaItems);
- } else if (MEDIA_ID_CHILDREN_DELAYED.equals(parentMediaId)) {
- Assert.assertNull(mPendingLoadChildrenResult);
- mPendingLoadChildrenResult = result;
- mPendingRootHints = getBrowserRootHints();
- result.detach();
- } else if (MEDIA_ID_INVALID.equals(parentMediaId)) {
- result.sendResult(null);
- }
- }
-
- @Override
- public void onLoadItem(String itemId, Result<MediaItem> result) {
- if (MEDIA_ID_CHILDREN_DELAYED.equals(itemId)) {
- mPendingLoadItemResult = result;
- mPendingRootHints = getBrowserRootHints();
- result.detach();
- return;
- }
-
- if (MEDIA_ID_INVALID.equals(itemId)) {
- result.sendResult(null);
- return;
- }
-
- for (String id : MEDIA_ID_CHILDREN) {
- if (id.equals(itemId)) {
- result.sendResult(createMediaItem(id));
- return;
- }
- }
-
- // Test the case where onLoadItem is not implemented.
- super.onLoadItem(itemId, result);
- }
-
- @Override
- public void onSearch(String query, Bundle extras, Result<List<MediaItem>> result) {
- if (SEARCH_QUERY_FOR_NO_RESULT.equals(query)) {
- result.sendResult(Collections.<MediaItem>emptyList());
- } else if (SEARCH_QUERY_FOR_ERROR.equals(query)) {
- result.sendResult(null);
- } else if (SEARCH_QUERY.equals(query)) {
- List<MediaItem> items = new ArrayList<>();
- for (String id : MEDIA_ID_CHILDREN) {
- if (id.contains(query)) {
- items.add(createMediaItem(id));
- }
- }
- result.sendResult(items);
- }
- }
-
- @Override
- public void onCustomAction(String action, Bundle extras,
- Result<Bundle> result) {
- mCustomActionResult = result;
- mCustomActionExtras = extras;
- if (CUSTOM_ACTION_FOR_ERROR.equals(action)) {
- result.sendError(null);
- } else if (CUSTOM_ACTION.equals(action)) {
- result.detach();
- }
- }
-
- public void sendDelayedNotifyChildrenChanged() {
- if (mPendingLoadChildrenResult != null) {
- mPendingLoadChildrenResult.sendResult(Collections.<MediaItem>emptyList());
- mPendingRootHints = null;
- mPendingLoadChildrenResult = null;
- }
- }
-
- public void sendDelayedItemLoaded() {
- if (mPendingLoadItemResult != null) {
- mPendingLoadItemResult.sendResult(new MediaItem(new MediaDescriptionCompat.Builder()
- .setMediaId(MEDIA_ID_CHILDREN_DELAYED).setExtras(mPendingRootHints).build(),
- MediaItem.FLAG_BROWSABLE));
- mPendingRootHints = null;
- mPendingLoadItemResult = null;
- }
- }
-
- private MediaItem createMediaItem(String id) {
- return new MediaItem(new MediaDescriptionCompat.Builder()
- .setMediaId(id).setExtras(getBrowserRootHints()).build(),
- MediaItem.FLAG_BROWSABLE);
- }
-}
diff --git a/media-compat/tests/src/android/support/v4/media/StubMediaBrowserServiceCompatWithDelayedMediaSession.java b/media-compat/tests/src/android/support/v4/media/StubMediaBrowserServiceCompatWithDelayedMediaSession.java
deleted file mode 100644
index e93c940..0000000
--- a/media-compat/tests/src/android/support/v4/media/StubMediaBrowserServiceCompatWithDelayedMediaSession.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 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 android.support.v4.media;
-
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.media.session.MediaSessionCompat;
-
-import java.util.List;
-
-/**
- * Stub implementation of {@link MediaBrowserServiceCompat}.
- * This implementation does not call
- * {@link MediaBrowserServiceCompat#setSessionToken(MediaSessionCompat.Token)} in its
- * {@link android.app.Service#onCreate}.
- */
-public class StubMediaBrowserServiceCompatWithDelayedMediaSession extends
- MediaBrowserServiceCompat {
-
- static StubMediaBrowserServiceCompatWithDelayedMediaSession sInstance;
- private MediaSessionCompat mSession;
-
- @Override
- public void onCreate() {
- super.onCreate();
- sInstance = this;
- mSession = new MediaSessionCompat(
- this, "StubMediaBrowserServiceCompatWithDelayedMediaSession");
- }
-
- @Nullable
- @Override
- public BrowserRoot onGetRoot(@NonNull String clientPackageName,
- int clientUid, @Nullable Bundle rootHints) {
- return new BrowserRoot("StubRootId", null);
- }
-
- @Override
- public void onLoadChildren(@NonNull String parentId,
- @NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
- result.detach();
- }
-
- void callSetSessionToken() {
- setSessionToken(mSession.getSessionToken());
- }
-}
diff --git a/media-compat/tests/src/android/support/v4/media/StubRemoteMediaBrowserServiceCompat.java b/media-compat/tests/src/android/support/v4/media/StubRemoteMediaBrowserServiceCompat.java
deleted file mode 100644
index 8e03ab2..0000000
--- a/media-compat/tests/src/android/support/v4/media/StubRemoteMediaBrowserServiceCompat.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 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 android.support.v4.media;
-
-import android.os.Bundle;
-import android.support.v4.media.MediaBrowserCompat.MediaItem;
-import android.support.v4.media.session.MediaSessionCompat;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Stub implementation of {@link android.support.v4.media.MediaBrowserServiceCompat}.
- */
-public class StubRemoteMediaBrowserServiceCompat extends MediaBrowserServiceCompat {
- static final String EXTRAS_KEY = "test_extras_key";
- static final String EXTRAS_VALUE = "test_extras_value";
-
- static final String MEDIA_ID_ROOT = "test_media_id_root";
- static final String MEDIA_METADATA = "test_media_metadata";
-
- static final String[] MEDIA_ID_CHILDREN = new String[]{
- "test_media_id_children_0", "test_media_id_children_1",
- "test_media_id_children_2", "test_media_id_children_3"
- };
-
- private static MediaSessionCompat mSession;
- private Bundle mExtras;
-
- @Override
- public void onCreate() {
- super.onCreate();
- mSession = new MediaSessionCompat(this, "StubRemoteMediaBrowserServiceCompat");
- setSessionToken(mSession.getSessionToken());
- }
-
- @Override
- public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
- mExtras = new Bundle();
- mExtras.putString(EXTRAS_KEY, EXTRAS_VALUE);
- return new BrowserRoot(MEDIA_ID_ROOT, mExtras);
- }
-
- @Override
- public void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result) {
- List<MediaItem> mediaItems = new ArrayList<>();
- if (MEDIA_ID_ROOT.equals(parentMediaId)) {
- Bundle rootHints = getBrowserRootHints();
- for (String id : MEDIA_ID_CHILDREN) {
- mediaItems.add(createMediaItem(id));
- }
- result.sendResult(mediaItems);
- }
- }
-
- @Override
- public void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result,
- final Bundle options) {
- MediaMetadataCompat metadata = options.getParcelable(MEDIA_METADATA);
- if (metadata == null) {
- super.onLoadChildren(parentMediaId, result, options);
- } else {
- List<MediaItem> mediaItems = new ArrayList<>();
- mediaItems.add(new MediaItem(metadata.getDescription(), MediaItem.FLAG_PLAYABLE));
- result.sendResult(mediaItems);
- }
- }
-
- private MediaItem createMediaItem(String id) {
- return new MediaItem(new MediaDescriptionCompat.Builder()
- .setMediaId(id).setExtras(getBrowserRootHints()).build(),
- MediaItem.FLAG_BROWSABLE);
- }
-}
diff --git a/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java b/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java
deleted file mode 100644
index b197a42..0000000
--- a/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java
+++ /dev/null
@@ -1,795 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.support.v4.media.session;
-
-import static android.support.test.InstrumentationRegistry.getContext;
-import static android.support.test.InstrumentationRegistry.getInstrumentation;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.media.AudioManager;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.ResultReceiver;
-import android.os.SystemClock;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.media.MediaDescriptionCompat;
-import android.support.v4.media.RatingCompat;
-import android.support.v4.media.VolumeProviderCompat;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Test {@link MediaControllerCompat}.
- */
-@RunWith(AndroidJUnit4.class)
-public class MediaControllerCompatTest {
- // The maximum time to wait for an operation.
- private static final long TIME_OUT_MS = 3000L;
- private static final String SESSION_TAG = "test-session";
- private static final String EXTRAS_KEY = "test-key";
- private static final String EXTRAS_VALUE = "test-val";
- private static final float DELTA = 1e-4f;
- private static final boolean ENABLED = true;
- private static final boolean DISABLED = false;
- private static final long TEST_POSITION = 1000000L;
- private static final float TEST_PLAYBACK_SPEED = 3.0f;
-
-
- private final Object mWaitLock = new Object();
- private Handler mHandler = new Handler(Looper.getMainLooper());
- private MediaSessionCompat mSession;
- private MediaSessionCallback mCallback = new MediaSessionCallback();
- private MediaControllerCompat mController;
-
- @Before
- public void setUp() throws Exception {
- getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- mSession = new MediaSessionCompat(getContext(), SESSION_TAG);
- mSession.setCallback(mCallback, mHandler);
- mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS);
- mController = mSession.getController();
- }
- });
- }
-
- @After
- public void tearDown() throws Exception {
- mSession.release();
- }
-
- @Test
- @SmallTest
- public void testGetPackageName() {
- assertEquals(getContext().getPackageName(), mController.getPackageName());
- }
-
- @Test
- @SmallTest
- public void testGetRatingType() {
- assertEquals("Default rating type of a session must be RatingCompat.RATING_NONE",
- RatingCompat.RATING_NONE, mController.getRatingType());
-
- mSession.setRatingType(RatingCompat.RATING_5_STARS);
- assertEquals(RatingCompat.RATING_5_STARS, mController.getRatingType());
- }
-
- @Test
- @SmallTest
- public void testGetSessionToken() throws Exception {
- assertEquals(mSession.getSessionToken(), mController.getSessionToken());
- }
-
- @Test
- @SmallTest
- public void testIsSessionReady() throws Exception {
- // mController already has the extra binder since it was created with the session token
- // which holds the extra binder.
- assertTrue(mController.isSessionReady());
- }
-
- @Test
- @SmallTest
- public void testSendCommand() throws Exception {
- synchronized (mWaitLock) {
- mCallback.reset();
- final String command = "test-command";
- final Bundle extras = new Bundle();
- extras.putString(EXTRAS_KEY, EXTRAS_VALUE);
- mController.sendCommand(command, extras, new ResultReceiver(null));
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnCommandCalled);
- assertNotNull(mCallback.mCommandCallback);
- assertEquals(command, mCallback.mCommand);
- assertEquals(EXTRAS_VALUE, mCallback.mExtras.getString(EXTRAS_KEY));
- }
- }
-
- @Test
- @SmallTest
- public void testAddRemoveQueueItems() throws Exception {
- final String mediaId1 = "media_id_1";
- final String mediaTitle1 = "media_title_1";
- MediaDescriptionCompat itemDescription1 = new MediaDescriptionCompat.Builder()
- .setMediaId(mediaId1).setTitle(mediaTitle1).build();
-
- final String mediaId2 = "media_id_2";
- final String mediaTitle2 = "media_title_2";
- MediaDescriptionCompat itemDescription2 = new MediaDescriptionCompat.Builder()
- .setMediaId(mediaId2).setTitle(mediaTitle2).build();
-
- synchronized (mWaitLock) {
- mCallback.reset();
- mController.addQueueItem(itemDescription1);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnAddQueueItemCalled);
- assertEquals(-1, mCallback.mQueueIndex);
- assertEquals(mediaId1, mCallback.mQueueDescription.getMediaId());
- assertEquals(mediaTitle1, mCallback.mQueueDescription.getTitle());
-
- mCallback.reset();
- mController.addQueueItem(itemDescription2, 0);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnAddQueueItemAtCalled);
- assertEquals(0, mCallback.mQueueIndex);
- assertEquals(mediaId2, mCallback.mQueueDescription.getMediaId());
- assertEquals(mediaTitle2, mCallback.mQueueDescription.getTitle());
-
- mCallback.reset();
- mController.removeQueueItemAt(0);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnRemoveQueueItemCalled);
- assertEquals(mediaId2, mCallback.mQueueDescription.getMediaId());
- assertEquals(mediaTitle2, mCallback.mQueueDescription.getTitle());
-
- mCallback.reset();
- mController.removeQueueItem(itemDescription1);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnRemoveQueueItemCalled);
- assertEquals(mediaId1, mCallback.mQueueDescription.getMediaId());
- assertEquals(mediaTitle1, mCallback.mQueueDescription.getTitle());
-
- // Try to modify the queue when the session does not support queue management.
- mSession.setFlags(0);
- try {
- mController.addQueueItem(itemDescription1);
- fail();
- } catch (UnsupportedOperationException e) {
- // Expected.
- }
- }
- }
-
- // TODO: Uncomment after fixing this test. This test causes an Exception on System UI.
- // @Test
- // @SmallTest
- public void testVolumeControl() throws Exception {
- VolumeProviderCompat vp =
- new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE, 11, 5) {
- @Override
- public void onSetVolumeTo(int volume) {
- synchronized (mWaitLock) {
- setCurrentVolume(volume);
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onAdjustVolume(int direction) {
- synchronized (mWaitLock) {
- switch (direction) {
- case AudioManager.ADJUST_LOWER:
- setCurrentVolume(getCurrentVolume() - 1);
- break;
- case AudioManager.ADJUST_RAISE:
- setCurrentVolume(getCurrentVolume() + 1);
- break;
- }
- mWaitLock.notify();
- }
- }
- };
- mSession.setPlaybackToRemote(vp);
-
- synchronized (mWaitLock) {
- // test setVolumeTo
- mController.setVolumeTo(7, 0);
- mWaitLock.wait(TIME_OUT_MS);
- assertEquals(7, vp.getCurrentVolume());
-
- // test adjustVolume
- mController.adjustVolume(AudioManager.ADJUST_LOWER, 0);
- mWaitLock.wait(TIME_OUT_MS);
- assertEquals(6, vp.getCurrentVolume());
-
- mController.adjustVolume(AudioManager.ADJUST_RAISE, 0);
- mWaitLock.wait(TIME_OUT_MS);
- assertEquals(7, vp.getCurrentVolume());
- }
- }
-
- @Test
- @SmallTest
- public void testTransportControlsAndMediaSessionCallback() throws Exception {
- MediaControllerCompat.TransportControls controls = mController.getTransportControls();
- synchronized (mWaitLock) {
- mCallback.reset();
- controls.play();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPlayCalled);
-
- mCallback.reset();
- controls.pause();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPauseCalled);
-
- mCallback.reset();
- controls.stop();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnStopCalled);
-
- mCallback.reset();
- controls.fastForward();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnFastForwardCalled);
-
- mCallback.reset();
- controls.rewind();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnRewindCalled);
-
- mCallback.reset();
- controls.skipToPrevious();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSkipToPreviousCalled);
-
- mCallback.reset();
- controls.skipToNext();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSkipToNextCalled);
-
- mCallback.reset();
- final long seekPosition = 1000;
- controls.seekTo(seekPosition);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSeekToCalled);
- assertEquals(seekPosition, mCallback.mSeekPosition);
-
- mCallback.reset();
- final RatingCompat rating =
- RatingCompat.newStarRating(RatingCompat.RATING_5_STARS, 3f);
- controls.setRating(rating);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetRatingCalled);
- assertEquals(rating.getRatingStyle(), mCallback.mRating.getRatingStyle());
- assertEquals(rating.getStarRating(), mCallback.mRating.getStarRating(), DELTA);
-
- mCallback.reset();
- final Bundle extras = new Bundle();
- extras.putString(EXTRAS_KEY, EXTRAS_VALUE);
- controls.setRating(rating, extras);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetRatingCalled);
- assertEquals(rating.getRatingStyle(), mCallback.mRating.getRatingStyle());
- assertEquals(rating.getStarRating(), mCallback.mRating.getStarRating(), DELTA);
- assertEquals(EXTRAS_VALUE, mCallback.mExtras.getString(EXTRAS_KEY));
-
- mCallback.reset();
- final String mediaId = "test-media-id";
- controls.playFromMediaId(mediaId, extras);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPlayFromMediaIdCalled);
- assertEquals(mediaId, mCallback.mMediaId);
- assertEquals(EXTRAS_VALUE, mCallback.mExtras.getString(EXTRAS_KEY));
-
- mCallback.reset();
- final String query = "test-query";
- controls.playFromSearch(query, extras);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPlayFromSearchCalled);
- assertEquals(query, mCallback.mQuery);
- assertEquals(EXTRAS_VALUE, mCallback.mExtras.getString(EXTRAS_KEY));
-
- mCallback.reset();
- final Uri uri = Uri.parse("content://test/popcorn.mod");
- controls.playFromUri(uri, extras);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPlayFromUriCalled);
- assertEquals(uri, mCallback.mUri);
- assertEquals(EXTRAS_VALUE, mCallback.mExtras.getString(EXTRAS_KEY));
-
- mCallback.reset();
- final String action = "test-action";
- controls.sendCustomAction(action, extras);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnCustomActionCalled);
- assertEquals(action, mCallback.mAction);
- assertEquals(EXTRAS_VALUE, mCallback.mExtras.getString(EXTRAS_KEY));
-
- mCallback.reset();
- mCallback.mOnCustomActionCalled = false;
- final PlaybackStateCompat.CustomAction customAction =
- new PlaybackStateCompat.CustomAction.Builder(action, action, -1)
- .setExtras(extras)
- .build();
- controls.sendCustomAction(customAction, extras);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnCustomActionCalled);
- assertEquals(action, mCallback.mAction);
- assertEquals(EXTRAS_VALUE, mCallback.mExtras.getString(EXTRAS_KEY));
-
- mCallback.reset();
- final long queueItemId = 1000;
- controls.skipToQueueItem(queueItemId);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSkipToQueueItemCalled);
- assertEquals(queueItemId, mCallback.mQueueItemId);
-
- mCallback.reset();
- controls.prepare();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPrepareCalled);
-
- mCallback.reset();
- controls.prepareFromMediaId(mediaId, extras);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPrepareFromMediaIdCalled);
- assertEquals(mediaId, mCallback.mMediaId);
- assertEquals(EXTRAS_VALUE, mCallback.mExtras.getString(EXTRAS_KEY));
-
- mCallback.reset();
- controls.prepareFromSearch(query, extras);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPrepareFromSearchCalled);
- assertEquals(query, mCallback.mQuery);
- assertEquals(EXTRAS_VALUE, mCallback.mExtras.getString(EXTRAS_KEY));
-
- mCallback.reset();
- controls.prepareFromUri(uri, extras);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPrepareFromUriCalled);
- assertEquals(uri, mCallback.mUri);
- assertEquals(EXTRAS_VALUE, mCallback.mExtras.getString(EXTRAS_KEY));
-
- mCallback.reset();
- controls.setCaptioningEnabled(ENABLED);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetCaptioningEnabledCalled);
- assertEquals(ENABLED, mCallback.mCaptioningEnabled);
-
- mCallback.reset();
- final int repeatMode = PlaybackStateCompat.REPEAT_MODE_ALL;
- controls.setRepeatMode(repeatMode);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetRepeatModeCalled);
- assertEquals(repeatMode, mCallback.mRepeatMode);
-
- mCallback.reset();
- controls.setShuffleMode(PlaybackStateCompat.SHUFFLE_MODE_ALL);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetShuffleModeCalled);
- assertEquals(PlaybackStateCompat.SHUFFLE_MODE_ALL, mCallback.mShuffleMode);
- }
- }
-
- @Test
- @SmallTest
- public void testPlaybackInfo() {
- final int playbackType = MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_LOCAL;
- final int volumeControl = VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE;
- final int maxVolume = 10;
- final int currentVolume = 3;
-
- int audioStream = 77;
- MediaControllerCompat.PlaybackInfo info = new MediaControllerCompat.PlaybackInfo(
- playbackType, audioStream, volumeControl, maxVolume, currentVolume);
-
- assertEquals(playbackType, info.getPlaybackType());
- assertEquals(audioStream, info.getAudioStream());
- assertEquals(volumeControl, info.getVolumeControl());
- assertEquals(maxVolume, info.getMaxVolume());
- assertEquals(currentVolume, info.getCurrentVolume());
- }
-
- @Test
- @SmallTest
- public void testGetPlaybackStateWithPositionUpdate() throws InterruptedException {
- final long stateSetTime = SystemClock.elapsedRealtime();
- PlaybackStateCompat stateIn = new PlaybackStateCompat.Builder()
- .setState(PlaybackStateCompat.STATE_PLAYING, TEST_POSITION, TEST_PLAYBACK_SPEED,
- stateSetTime)
- .build();
- mSession.setPlaybackState(stateIn);
-
- final long waitDuration = 100L;
- Thread.sleep(waitDuration);
-
- final long expectedUpdateTime = waitDuration + stateSetTime;
- final long expectedPosition = (long) (TEST_PLAYBACK_SPEED * waitDuration) + TEST_POSITION;
-
- final double updateTimeTolerance = 50L;
- final double positionTolerance = updateTimeTolerance * TEST_PLAYBACK_SPEED;
-
- PlaybackStateCompat stateOut = mSession.getController().getPlaybackState();
- assertEquals(expectedUpdateTime, stateOut.getLastPositionUpdateTime(), updateTimeTolerance);
- assertEquals(expectedPosition, stateOut.getPosition(), positionTolerance);
-
- // Compare the result with MediaController.getPlaybackState().
- if (Build.VERSION.SDK_INT >= 21) {
- MediaController controller = new MediaController(
- getContext(), (MediaSession.Token) mSession.getSessionToken().getToken());
- PlaybackState state = controller.getPlaybackState();
- assertEquals(state.getLastPositionUpdateTime(), stateOut.getLastPositionUpdateTime(),
- updateTimeTolerance);
- assertEquals(state.getPosition(), stateOut.getPosition(), positionTolerance);
- }
- }
-
- private class MediaSessionCallback extends MediaSessionCompat.Callback {
- private long mSeekPosition;
- private long mQueueItemId;
- private RatingCompat mRating;
- private String mMediaId;
- private String mQuery;
- private Uri mUri;
- private String mAction;
- private String mCommand;
- private Bundle mExtras;
- private ResultReceiver mCommandCallback;
- private boolean mCaptioningEnabled;
- private int mRepeatMode;
- private int mShuffleMode;
- private int mQueueIndex;
- private MediaDescriptionCompat mQueueDescription;
- private List<MediaSessionCompat.QueueItem> mQueue = new ArrayList<>();
-
- private boolean mOnPlayCalled;
- private boolean mOnPauseCalled;
- private boolean mOnStopCalled;
- private boolean mOnFastForwardCalled;
- private boolean mOnRewindCalled;
- private boolean mOnSkipToPreviousCalled;
- private boolean mOnSkipToNextCalled;
- private boolean mOnSeekToCalled;
- private boolean mOnSkipToQueueItemCalled;
- private boolean mOnSetRatingCalled;
- private boolean mOnPlayFromMediaIdCalled;
- private boolean mOnPlayFromSearchCalled;
- private boolean mOnPlayFromUriCalled;
- private boolean mOnCustomActionCalled;
- private boolean mOnCommandCalled;
- private boolean mOnPrepareCalled;
- private boolean mOnPrepareFromMediaIdCalled;
- private boolean mOnPrepareFromSearchCalled;
- private boolean mOnPrepareFromUriCalled;
- private boolean mOnSetCaptioningEnabledCalled;
- private boolean mOnSetRepeatModeCalled;
- private boolean mOnSetShuffleModeCalled;
- private boolean mOnAddQueueItemCalled;
- private boolean mOnAddQueueItemAtCalled;
- private boolean mOnRemoveQueueItemCalled;
-
- public void reset() {
- mSeekPosition = -1;
- mQueueItemId = -1;
- mRating = null;
- mMediaId = null;
- mQuery = null;
- mUri = null;
- mAction = null;
- mExtras = null;
- mCommand = null;
- mCommandCallback = null;
- mCaptioningEnabled = false;
- mRepeatMode = PlaybackStateCompat.REPEAT_MODE_NONE;
- mShuffleMode = PlaybackStateCompat.SHUFFLE_MODE_NONE;
- mQueueIndex = -1;
- mQueueDescription = null;
-
- mOnPlayCalled = false;
- mOnPauseCalled = false;
- mOnStopCalled = false;
- mOnFastForwardCalled = false;
- mOnRewindCalled = false;
- mOnSkipToPreviousCalled = false;
- mOnSkipToNextCalled = false;
- mOnSkipToQueueItemCalled = false;
- mOnSeekToCalled = false;
- mOnSetRatingCalled = false;
- mOnPlayFromMediaIdCalled = false;
- mOnPlayFromSearchCalled = false;
- mOnPlayFromUriCalled = false;
- mOnCustomActionCalled = false;
- mOnCommandCalled = false;
- mOnPrepareCalled = false;
- mOnPrepareFromMediaIdCalled = false;
- mOnPrepareFromSearchCalled = false;
- mOnPrepareFromUriCalled = false;
- mOnSetCaptioningEnabledCalled = false;
- mOnSetRepeatModeCalled = false;
- mOnSetShuffleModeCalled = false;
- mOnAddQueueItemCalled = false;
- mOnAddQueueItemAtCalled = false;
- mOnRemoveQueueItemCalled = false;
- }
-
- @Override
- public void onPlay() {
- synchronized (mWaitLock) {
- mOnPlayCalled = true;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onPause() {
- synchronized (mWaitLock) {
- mOnPauseCalled = true;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onStop() {
- synchronized (mWaitLock) {
- mOnStopCalled = true;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onFastForward() {
- synchronized (mWaitLock) {
- mOnFastForwardCalled = true;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onRewind() {
- synchronized (mWaitLock) {
- mOnRewindCalled = true;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onSkipToPrevious() {
- synchronized (mWaitLock) {
- mOnSkipToPreviousCalled = true;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onSkipToNext() {
- synchronized (mWaitLock) {
- mOnSkipToNextCalled = true;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onSeekTo(long pos) {
- synchronized (mWaitLock) {
- mOnSeekToCalled = true;
- mSeekPosition = pos;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onSetRating(RatingCompat rating) {
- synchronized (mWaitLock) {
- mOnSetRatingCalled = true;
- mRating = rating;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onSetRating(RatingCompat rating, Bundle extras) {
- synchronized (mWaitLock) {
- mOnSetRatingCalled = true;
- mRating = rating;
- mExtras = extras;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onPlayFromMediaId(String mediaId, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPlayFromMediaIdCalled = true;
- mMediaId = mediaId;
- mExtras = extras;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onPlayFromSearch(String query, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPlayFromSearchCalled = true;
- mQuery = query;
- mExtras = extras;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onPlayFromUri(Uri uri, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPlayFromUriCalled = true;
- mUri = uri;
- mExtras = extras;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onCustomAction(String action, Bundle extras) {
- synchronized (mWaitLock) {
- mOnCustomActionCalled = true;
- mAction = action;
- mExtras = extras;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onSkipToQueueItem(long id) {
- synchronized (mWaitLock) {
- mOnSkipToQueueItemCalled = true;
- mQueueItemId = id;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onCommand(String command, Bundle extras, ResultReceiver cb) {
- synchronized (mWaitLock) {
- mOnCommandCalled = true;
- mCommand = command;
- mExtras = extras;
- mCommandCallback = cb;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onPrepare() {
- synchronized (mWaitLock) {
- mOnPrepareCalled = true;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onPrepareFromMediaId(String mediaId, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPrepareFromMediaIdCalled = true;
- mMediaId = mediaId;
- mExtras = extras;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onPrepareFromSearch(String query, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPrepareFromSearchCalled = true;
- mQuery = query;
- mExtras = extras;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onPrepareFromUri(Uri uri, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPrepareFromUriCalled = true;
- mUri = uri;
- mExtras = extras;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onSetRepeatMode(int repeatMode) {
- synchronized (mWaitLock) {
- mOnSetRepeatModeCalled = true;
- mRepeatMode = repeatMode;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onAddQueueItem(MediaDescriptionCompat description) {
- synchronized (mWaitLock) {
- mOnAddQueueItemCalled = true;
- mQueueDescription = description;
- mQueue.add(new MediaSessionCompat.QueueItem(description, mQueue.size()));
- mSession.setQueue(mQueue);
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onAddQueueItem(MediaDescriptionCompat description, int index) {
- synchronized (mWaitLock) {
- mOnAddQueueItemAtCalled = true;
- mQueueIndex = index;
- mQueueDescription = description;
- mQueue.add(index, new MediaSessionCompat.QueueItem(description, mQueue.size()));
- mSession.setQueue(mQueue);
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onRemoveQueueItem(MediaDescriptionCompat description) {
- synchronized (mWaitLock) {
- mOnRemoveQueueItemCalled = true;
- String mediaId = description.getMediaId();
- for (int i = mQueue.size() - 1; i >= 0; --i) {
- if (mediaId.equals(mQueue.get(i).getDescription().getMediaId())) {
- mQueueDescription = mQueue.remove(i).getDescription();
- mSession.setQueue(mQueue);
- break;
- }
- }
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onSetCaptioningEnabled(boolean enabled) {
- synchronized (mWaitLock) {
- mOnSetCaptioningEnabledCalled = true;
- mCaptioningEnabled = enabled;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onSetShuffleMode(int shuffleMode) {
- synchronized (mWaitLock) {
- mOnSetShuffleModeCalled = true;
- mShuffleMode = shuffleMode;
- mWaitLock.notify();
- }
- }
- }
-}
diff --git a/media-compat/tests/src/android/support/v4/media/session/MediaSessionCompatTest.java b/media-compat/tests/src/android/support/v4/media/session/MediaSessionCompatTest.java
deleted file mode 100644
index 9911c11..0000000
--- a/media-compat/tests/src/android/support/v4/media/session/MediaSessionCompatTest.java
+++ /dev/null
@@ -1,1038 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.support.v4.media.session;
-
-import static android.support.test.InstrumentationRegistry.getContext;
-import static android.support.test.InstrumentationRegistry.getInstrumentation;
-import static android.support.v4.media.MediaMetadataCompat.METADATA_KEY_RATING;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.media.AudioManager;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.media.MediaDescriptionCompat;
-import android.support.v4.media.MediaMetadataCompat;
-import android.support.v4.media.RatingCompat;
-import android.support.v4.media.VolumeProviderCompat;
-import android.view.KeyEvent;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Test {@link MediaSessionCompat}.
- */
-@RunWith(AndroidJUnit4.class)
-public class MediaSessionCompatTest {
- // The maximum time to wait for an operation, that is expected to happen.
- private static final long TIME_OUT_MS = 3000L;
- // The maximum time to wait for an operation, that is expected not to happen.
- private static final long WAIT_TIME_MS = 30L;
- private static final int MAX_AUDIO_INFO_CHANGED_CALLBACK_COUNT = 10;
- private static final String TEST_SESSION_TAG = "test-session-tag";
- private static final String TEST_KEY = "test-key";
- private static final String TEST_VALUE = "test-val";
- private static final Bundle TEST_BUNDLE = createTestBundle();
- private static final String TEST_SESSION_EVENT = "test-session-event";
- private static final int TEST_CURRENT_VOLUME = 10;
- private static final int TEST_MAX_VOLUME = 11;
- private static final long TEST_QUEUE_ID = 12L;
- private static final long TEST_ACTION = 55L;
- private static final int TEST_ERROR_CODE =
- PlaybackStateCompat.ERROR_CODE_AUTHENTICATION_EXPIRED;
- private static final String TEST_ERROR_MSG = "test-error-msg";
-
- private static Bundle createTestBundle() {
- Bundle bundle = new Bundle();
- bundle.putString(TEST_KEY, TEST_VALUE);
- return bundle;
- }
-
- private AudioManager mAudioManager;
- private Handler mHandler = new Handler(Looper.getMainLooper());
- private Object mWaitLock = new Object();
- private MediaControllerCallback mCallback = new MediaControllerCallback();
- private MediaSessionCompat mSession;
-
- @Before
- public void setUp() throws Exception {
- getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
- mSession = new MediaSessionCompat(getContext(), TEST_SESSION_TAG);
- }
- });
- }
-
- @After
- public void tearDown() throws Exception {
- // It is OK to call release() twice.
- mSession.release();
- mSession = null;
- }
-
- /**
- * Tests that a session can be created and that all the fields are
- * initialized correctly.
- */
- @Test
- @SmallTest
- public void testCreateSession() throws Exception {
- assertNotNull(mSession.getSessionToken());
- assertFalse("New session should not be active", mSession.isActive());
-
- // Verify by getting the controller and checking all its fields
- MediaControllerCompat controller = mSession.getController();
- assertNotNull(controller);
- verifyNewSession(controller, TEST_SESSION_TAG);
- }
-
- /**
- * Tests that a session can be created from the framework session object and the callback
- * set on the framework session object before fromSession() is called works properly.
- */
- @Test
- @SmallTest
- public void testFromSession() throws Exception {
- if (android.os.Build.VERSION.SDK_INT < 21) {
- // MediaSession was introduced from API level 21.
- return;
- }
- MediaSessionCallback callback = new MediaSessionCallback();
- callback.reset(1);
- mSession.setCallback(callback, new Handler(Looper.getMainLooper()));
- MediaSessionCompat session = MediaSessionCompat.fromMediaSession(
- getContext(), mSession.getMediaSession());
- assertEquals(session.getSessionToken(), mSession.getSessionToken());
- synchronized (mWaitLock) {
- session.getController().getTransportControls().play();
- mWaitLock.wait(TIME_OUT_MS);
- assertEquals(1, callback.mOnPlayCalledCount);
- }
- }
-
- /**
- * Tests MediaSessionCompat.Token created in the constructor of MediaSessionCompat.
- */
- @Test
- @SmallTest
- public void testSessionToken() throws Exception {
- MediaSessionCompat.Token sessionToken = mSession.getSessionToken();
-
- assertNotNull(sessionToken);
- assertEquals(0, sessionToken.describeContents());
-
- // Test writeToParcel
- Parcel p = Parcel.obtain();
- sessionToken.writeToParcel(p, 0);
- p.setDataPosition(0);
- MediaSessionCompat.Token token = MediaSessionCompat.Token.CREATOR.createFromParcel(p);
- assertEquals(token, sessionToken);
- p.recycle();
- }
-
- /**
- * Tests {@link MediaSessionCompat#setExtras}.
- */
- @Test
- @SmallTest
- public void testSetExtras() throws Exception {
- final Bundle extras = new Bundle();
- MediaControllerCompat controller = mSession.getController();
- controller.registerCallback(mCallback, mHandler);
- synchronized (mWaitLock) {
- mCallback.resetLocked();
- mSession.setExtras(TEST_BUNDLE);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnExtraChangedCalled);
-
- Bundle extrasOut = mCallback.mExtras;
- assertNotNull(extrasOut);
- assertEquals(TEST_VALUE, extrasOut.get(TEST_KEY));
-
- extrasOut = controller.getExtras();
- assertNotNull(extrasOut);
- assertEquals(TEST_VALUE, extrasOut.get(TEST_KEY));
- }
- }
-
- /**
- * Tests {@link MediaSessionCompat#setFlags}.
- */
- @Test
- @SmallTest
- public void testSetFlags() throws Exception {
- MediaControllerCompat controller = mSession.getController();
- controller.registerCallback(mCallback, mHandler);
- synchronized (mWaitLock) {
- mCallback.resetLocked();
- mSession.setFlags(5);
- assertEquals(5, controller.getFlags());
- }
- }
-
- /**
- * Tests {@link MediaSessionCompat#setMetadata}.
- */
- @Test
- @SmallTest
- public void testSetMetadata() throws Exception {
- MediaControllerCompat controller = mSession.getController();
- controller.registerCallback(mCallback, mHandler);
- synchronized (mWaitLock) {
- mCallback.resetLocked();
- RatingCompat rating = RatingCompat.newHeartRating(true);
- MediaMetadataCompat metadata = new MediaMetadataCompat.Builder()
- .putString(TEST_KEY, TEST_VALUE)
- .putRating(METADATA_KEY_RATING, rating)
- .build();
- mSession.setActive(true);
- mSession.setMetadata(metadata);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnMetadataChangedCalled);
-
- MediaMetadataCompat metadataOut = mCallback.mMediaMetadata;
- assertNotNull(metadataOut);
- assertEquals(TEST_VALUE, metadataOut.getString(TEST_KEY));
-
- metadataOut = controller.getMetadata();
- assertNotNull(metadataOut);
- assertEquals(TEST_VALUE, metadataOut.getString(TEST_KEY));
-
- assertNotNull(metadataOut.getRating(METADATA_KEY_RATING));
- RatingCompat ratingOut = metadataOut.getRating(METADATA_KEY_RATING);
- assertEquals(rating.getRatingStyle(), ratingOut.getRatingStyle());
- assertEquals(rating.getPercentRating(), ratingOut.getPercentRating(), 0.0f);
- }
- }
-
- /**
- * Tests {@link MediaSessionCompat#setMetadata} with artwork bitmaps.
- */
- @Test
- @SmallTest
- public void testSetMetadataWithArtworks() throws Exception {
- MediaControllerCompat controller = mSession.getController();
- final Bitmap bitmapSmall = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
- final Bitmap bitmapLarge = Bitmap.createBitmap(1000, 1000, Bitmap.Config.ALPHA_8);
-
- controller.registerCallback(mCallback, mHandler);
- mSession.setActive(true);
- synchronized (mWaitLock) {
- mCallback.resetLocked();
- MediaMetadataCompat metadata = new MediaMetadataCompat.Builder()
- .putString(TEST_KEY, TEST_VALUE)
- .putBitmap(MediaMetadataCompat.METADATA_KEY_ART, bitmapSmall)
- .build();
- mSession.setMetadata(metadata);
- mWaitLock.wait(TIME_OUT_MS);
-
- assertTrue(mCallback.mOnMetadataChangedCalled);
- MediaMetadataCompat metadataOut = mCallback.mMediaMetadata;
- assertNotNull(metadataOut);
- assertEquals(TEST_VALUE, metadataOut.getString(TEST_KEY));
- Bitmap bitmapSmallOut = metadataOut.getBitmap(MediaMetadataCompat.METADATA_KEY_ART);
- assertNotNull(bitmapSmallOut);
- assertEquals(bitmapSmall.getHeight(), bitmapSmallOut.getHeight());
- assertEquals(bitmapSmall.getWidth(), bitmapSmallOut.getWidth());
- assertEquals(bitmapSmall.getConfig(), bitmapSmallOut.getConfig());
-
- metadata = new MediaMetadataCompat.Builder()
- .putString(TEST_KEY, TEST_VALUE)
- .putBitmap(MediaMetadataCompat.METADATA_KEY_ART, bitmapLarge)
- .build();
- mSession.setMetadata(metadata);
- mWaitLock.wait(TIME_OUT_MS);
-
- assertTrue(mCallback.mOnMetadataChangedCalled);
- metadataOut = mCallback.mMediaMetadata;
- assertNotNull(metadataOut);
- assertEquals(TEST_VALUE, metadataOut.getString(TEST_KEY));
- Bitmap bitmapLargeOut = metadataOut.getBitmap(MediaMetadataCompat.METADATA_KEY_ART);
- assertNotNull(bitmapLargeOut);
- // Don't check size here because large bitmaps can be scaled down.
- assertEquals(bitmapLarge.getConfig(), bitmapLargeOut.getConfig());
-
- assertFalse(bitmapSmall.isRecycled());
- assertFalse(bitmapLarge.isRecycled());
- assertFalse(bitmapSmallOut.isRecycled());
- assertFalse(bitmapLargeOut.isRecycled());
- bitmapSmallOut.recycle();
- bitmapLargeOut.recycle();
- }
- bitmapSmall.recycle();
- bitmapLarge.recycle();
- }
-
- /**
- * Tests {@link MediaSessionCompat#setPlaybackState}.
- */
- @Test
- @SmallTest
- public void testSetPlaybackState() throws Exception {
- MediaControllerCompat controller = mSession.getController();
- controller.registerCallback(mCallback, mHandler);
- synchronized (mWaitLock) {
- mCallback.resetLocked();
- PlaybackStateCompat state =
- new PlaybackStateCompat.Builder()
- .setActions(TEST_ACTION)
- .setErrorMessage(TEST_ERROR_CODE, TEST_ERROR_MSG)
- .build();
- mSession.setPlaybackState(state);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPlaybackStateChangedCalled);
-
- PlaybackStateCompat stateOut = mCallback.mPlaybackState;
- assertNotNull(stateOut);
- assertEquals(TEST_ACTION, stateOut.getActions());
- assertEquals(TEST_ERROR_CODE, stateOut.getErrorCode());
- assertEquals(TEST_ERROR_MSG, stateOut.getErrorMessage().toString());
-
- stateOut = controller.getPlaybackState();
- assertNotNull(stateOut);
- assertEquals(TEST_ACTION, stateOut.getActions());
- assertEquals(TEST_ERROR_CODE, stateOut.getErrorCode());
- assertEquals(TEST_ERROR_MSG, stateOut.getErrorMessage().toString());
- }
- }
-
- /**
- * Tests {@link MediaSessionCompat#setQueue} and {@link MediaSessionCompat#setQueueTitle}.
- */
- @Test
- @SmallTest
- public void testSetQueueAndSetQueueTitle() throws Exception {
- MediaControllerCompat controller = mSession.getController();
- controller.registerCallback(mCallback, mHandler);
- synchronized (mWaitLock) {
- mCallback.resetLocked();
- List<MediaSessionCompat.QueueItem> queue = new ArrayList<>();
- MediaSessionCompat.QueueItem item = new MediaSessionCompat.QueueItem(
- new MediaDescriptionCompat.Builder()
- .setMediaId(TEST_VALUE)
- .setTitle("title")
- .build(),
- TEST_QUEUE_ID);
- queue.add(item);
- mSession.setQueue(queue);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnQueueChangedCalled);
-
- mSession.setQueueTitle(TEST_VALUE);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnQueueTitleChangedCalled);
-
- assertEquals(TEST_VALUE, mCallback.mTitle);
- assertEquals(queue.size(), mCallback.mQueue.size());
- assertEquals(TEST_QUEUE_ID, mCallback.mQueue.get(0).getQueueId());
- assertEquals(TEST_VALUE, mCallback.mQueue.get(0).getDescription().getMediaId());
-
- assertEquals(TEST_VALUE, controller.getQueueTitle());
- assertEquals(queue.size(), controller.getQueue().size());
- assertEquals(TEST_QUEUE_ID, controller.getQueue().get(0).getQueueId());
- assertEquals(TEST_VALUE, controller.getQueue().get(0).getDescription().getMediaId());
-
- mCallback.resetLocked();
- mSession.setQueue(null);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnQueueChangedCalled);
-
- mSession.setQueueTitle(null);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnQueueTitleChangedCalled);
-
- assertNull(mCallback.mTitle);
- assertNull(mCallback.mQueue);
- assertNull(controller.getQueueTitle());
- assertNull(controller.getQueue());
- }
- }
-
- /**
- * Tests {@link MediaSessionCompat#setSessionActivity}.
- */
- @Test
- @SmallTest
- public void testSessionActivity() throws Exception {
- MediaControllerCompat controller = mSession.getController();
- synchronized (mWaitLock) {
- Intent intent = new Intent("cts.MEDIA_SESSION_ACTION");
- PendingIntent pi = PendingIntent.getActivity(getContext(), 555, intent, 0);
- mSession.setSessionActivity(pi);
- assertEquals(pi, controller.getSessionActivity());
- }
- }
-
- /**
- * Tests {@link MediaSessionCompat#setCaptioningEnabled}.
- */
- @Test
- @SmallTest
- public void testSetCaptioningEnabled() throws Exception {
- MediaControllerCompat controller = mSession.getController();
- controller.registerCallback(mCallback, mHandler);
- synchronized (mWaitLock) {
- mCallback.resetLocked();
- mSession.setCaptioningEnabled(true);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnCaptioningEnabledChangedCalled);
- assertEquals(true, mCallback.mCaptioningEnabled);
- assertEquals(true, controller.isCaptioningEnabled());
-
- mCallback.resetLocked();
- mSession.setCaptioningEnabled(false);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnCaptioningEnabledChangedCalled);
- assertEquals(false, mCallback.mCaptioningEnabled);
- assertEquals(false, controller.isCaptioningEnabled());
- }
- }
-
- /**
- * Tests {@link MediaSessionCompat#setRepeatMode}.
- */
- @Test
- @SmallTest
- public void testSetRepeatMode() throws Exception {
- MediaControllerCompat controller = mSession.getController();
- controller.registerCallback(mCallback, mHandler);
- synchronized (mWaitLock) {
- mCallback.resetLocked();
- final int repeatMode = PlaybackStateCompat.REPEAT_MODE_ALL;
- mSession.setRepeatMode(repeatMode);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnRepeatModeChangedCalled);
- assertEquals(repeatMode, mCallback.mRepeatMode);
- assertEquals(repeatMode, controller.getRepeatMode());
- }
- }
-
- /**
- * Tests {@link MediaSessionCompat#setShuffleMode}.
- */
- @Test
- @SmallTest
- public void testSetShuffleMode() throws Exception {
- final int shuffleMode = PlaybackStateCompat.SHUFFLE_MODE_ALL;
- MediaControllerCompat controller = mSession.getController();
- controller.registerCallback(mCallback, mHandler);
- synchronized (mWaitLock) {
- mCallback.resetLocked();
- mSession.setShuffleMode(shuffleMode);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnShuffleModeChangedCalled);
- assertEquals(shuffleMode, mCallback.mShuffleMode);
- assertEquals(shuffleMode, controller.getShuffleMode());
- }
- }
-
- /**
- * Tests {@link MediaSessionCompat#sendSessionEvent}.
- */
- @Test
- @SmallTest
- public void testSendSessionEvent() throws Exception {
- MediaControllerCompat controller = mSession.getController();
- controller.registerCallback(mCallback, mHandler);
- synchronized (mWaitLock) {
- mCallback.resetLocked();
- mSession.sendSessionEvent(TEST_SESSION_EVENT, TEST_BUNDLE);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSessionEventCalled);
- assertEquals(TEST_SESSION_EVENT, mCallback.mEvent);
- assertEquals(TEST_VALUE, mCallback.mExtras.getString(TEST_KEY));
- }
- }
-
- /**
- * Tests {@link MediaSessionCompat#setActive} and {@link MediaSessionCompat#release}.
- */
- @Test
- @SmallTest
- public void testSetActiveAndRelease() throws Exception {
- MediaControllerCompat controller = mSession.getController();
- controller.registerCallback(mCallback, mHandler);
- synchronized (mWaitLock) {
- mSession.setActive(true);
- assertTrue(mSession.isActive());
-
- mCallback.resetLocked();
- mSession.release();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSessionDestroyedCalled);
- }
- }
-
- /**
- * Tests {@link MediaSessionCompat#setCallback} with {@code null}. No callback will be called
- * once {@code setCallback(null)} is done.
- */
- @Test
- @SmallTest
- public void testSetCallbackWithNull() throws Exception {
- MediaSessionCallback sessionCallback = new MediaSessionCallback();
- mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
- mSession.setActive(true);
- mSession.setCallback(sessionCallback, mHandler);
-
- MediaControllerCompat controller = mSession.getController();
- setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
-
- sessionCallback.reset(1);
- mSession.setCallback(null, mHandler);
-
- controller.getTransportControls().pause();
- assertFalse(sessionCallback.await(WAIT_TIME_MS));
- assertFalse("Callback shouldn't be called.", sessionCallback.mOnPauseCalled);
- }
-
- /**
- * Tests {@link MediaSessionCompat#setPlaybackToLocal} and
- * {@link MediaSessionCompat#setPlaybackToRemote}.
- */
- @Test
- @SmallTest
- public void testPlaybackToLocalAndRemote() throws Exception {
- MediaControllerCompat controller = mSession.getController();
- controller.registerCallback(mCallback, mHandler);
- synchronized (mWaitLock) {
- // test setPlaybackToRemote, do this before testing setPlaybackToLocal
- // to ensure it switches correctly.
- mCallback.resetLocked();
- try {
- mSession.setPlaybackToRemote(null);
- fail("Expected IAE for setPlaybackToRemote(null)");
- } catch (IllegalArgumentException e) {
- // expected
- }
- VolumeProviderCompat vp = new VolumeProviderCompat(
- VolumeProviderCompat.VOLUME_CONTROL_FIXED,
- TEST_MAX_VOLUME,
- TEST_CURRENT_VOLUME) {};
- mSession.setPlaybackToRemote(vp);
-
- MediaControllerCompat.PlaybackInfo info = null;
- for (int i = 0; i < MAX_AUDIO_INFO_CHANGED_CALLBACK_COUNT; ++i) {
- mCallback.mOnAudioInfoChangedCalled = false;
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnAudioInfoChangedCalled);
- info = mCallback.mPlaybackInfo;
- if (info != null && info.getCurrentVolume() == TEST_CURRENT_VOLUME
- && info.getMaxVolume() == TEST_MAX_VOLUME
- && info.getVolumeControl() == VolumeProviderCompat.VOLUME_CONTROL_FIXED
- && info.getPlaybackType()
- == MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
- break;
- }
- }
- assertNotNull(info);
- assertEquals(MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
- info.getPlaybackType());
- assertEquals(TEST_MAX_VOLUME, info.getMaxVolume());
- assertEquals(TEST_CURRENT_VOLUME, info.getCurrentVolume());
- assertEquals(VolumeProviderCompat.VOLUME_CONTROL_FIXED,
- info.getVolumeControl());
-
- info = controller.getPlaybackInfo();
- assertNotNull(info);
- assertEquals(MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
- info.getPlaybackType());
- assertEquals(TEST_MAX_VOLUME, info.getMaxVolume());
- assertEquals(TEST_CURRENT_VOLUME, info.getCurrentVolume());
- assertEquals(VolumeProviderCompat.VOLUME_CONTROL_FIXED, info.getVolumeControl());
-
- // test setPlaybackToLocal
- mSession.setPlaybackToLocal(AudioManager.STREAM_RING);
- info = controller.getPlaybackInfo();
- assertNotNull(info);
- assertEquals(MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_LOCAL,
- info.getPlaybackType());
- }
- }
-
- /**
- * Tests {@link MediaSessionCompat.Callback#onMediaButtonEvent}.
- */
- @Test
- @SmallTest
- public void testCallbackOnMediaButtonEvent() throws Exception {
- MediaSessionCallback sessionCallback = new MediaSessionCallback();
- mSession.setCallback(sessionCallback, new Handler(Looper.getMainLooper()));
- mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS);
- mSession.setActive(true);
-
- Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON).setComponent(
- new ComponentName(getContext(), getContext().getClass()));
- PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, mediaButtonIntent, 0);
- mSession.setMediaButtonReceiver(pi);
-
- // Set state to STATE_PLAYING to get higher priority.
- setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
-
- sessionCallback.reset(1);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY);
- assertTrue(sessionCallback.await(TIME_OUT_MS));
- assertEquals(1, sessionCallback.mOnPlayCalledCount);
-
- sessionCallback.reset(1);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PAUSE);
- assertTrue(sessionCallback.await(TIME_OUT_MS));
- assertTrue(sessionCallback.mOnPauseCalled);
-
- sessionCallback.reset(1);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_NEXT);
- assertTrue(sessionCallback.await(TIME_OUT_MS));
- assertTrue(sessionCallback.mOnSkipToNextCalled);
-
- sessionCallback.reset(1);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
- assertTrue(sessionCallback.await(TIME_OUT_MS));
- assertTrue(sessionCallback.mOnSkipToPreviousCalled);
-
- sessionCallback.reset(1);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_STOP);
- assertTrue(sessionCallback.await(TIME_OUT_MS));
- assertTrue(sessionCallback.mOnStopCalled);
-
- sessionCallback.reset(1);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD);
- assertTrue(sessionCallback.await(TIME_OUT_MS));
- assertTrue(sessionCallback.mOnFastForwardCalled);
-
- sessionCallback.reset(1);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_REWIND);
- assertTrue(sessionCallback.await(TIME_OUT_MS));
- assertTrue(sessionCallback.mOnRewindCalled);
-
- // Test PLAY_PAUSE button twice.
- // First, send PLAY_PAUSE button event while in STATE_PAUSED.
- sessionCallback.reset(1);
- setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
- assertTrue(sessionCallback.await(TIME_OUT_MS));
- assertEquals(1, sessionCallback.mOnPlayCalledCount);
-
- // Next, send PLAY_PAUSE button event while in STATE_PLAYING.
- sessionCallback.reset(1);
- setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
- assertTrue(sessionCallback.await(TIME_OUT_MS));
- assertTrue(sessionCallback.mOnPauseCalled);
-
- // Double tap of PLAY_PAUSE is the next track.
- sessionCallback.reset(2);
- setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
- assertFalse(sessionCallback.await(WAIT_TIME_MS));
- assertTrue(sessionCallback.mOnSkipToNextCalled);
- assertEquals(0, sessionCallback.mOnPlayCalledCount);
- assertFalse(sessionCallback.mOnPauseCalled);
-
- // Test PLAY_PAUSE button long-press.
- // It should be the same as the single short-press.
- sessionCallback.reset(1);
- setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, true);
- assertTrue(sessionCallback.await(TIME_OUT_MS));
- assertEquals(1, sessionCallback.mOnPlayCalledCount);
-
- // Double tap of PLAY_PAUSE should be handled once.
- // Initial down event from the second press within double tap time-out will make
- // onSkipToNext() to be called, so further down events shouldn't be handled again.
- sessionCallback.reset(2);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, true);
- assertFalse(sessionCallback.await(WAIT_TIME_MS));
- assertTrue(sessionCallback.mOnSkipToNextCalled);
- assertEquals(0, sessionCallback.mOnPlayCalledCount);
- assertFalse(sessionCallback.mOnPauseCalled);
-
- // Test PLAY_PAUSE button short-press followed by the long-press.
- // Initial long-press of the PLAY_PAUSE is considered as the single short-press already,
- // so it shouldn't be used as the first tap of the double tap.
- sessionCallback.reset(2);
- setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, true);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
- assertTrue(sessionCallback.await(TIME_OUT_MS));
- // onMediaButtonEvent() calls either onPlay() or onPause() depending on the playback state,
- // so onPlay() should be called twice while onPause() isn't called.
- assertEquals(1, sessionCallback.mOnPlayCalledCount);
- assertTrue(sessionCallback.mOnPauseCalled);
- assertFalse(sessionCallback.mOnSkipToNextCalled);
-
- // If another media key is pressed while the double tap of PLAY_PAUSE,
- // PLAY_PAUSE should be handles as normal.
- sessionCallback.reset(3);
- setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_STOP);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
- assertTrue(sessionCallback.await(TIME_OUT_MS));
- assertFalse(sessionCallback.mOnSkipToNextCalled);
- assertTrue(sessionCallback.mOnStopCalled);
- assertEquals(2, sessionCallback.mOnPlayCalledCount);
-
- // Test if media keys are handled in order.
- sessionCallback.reset(2);
- setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
- sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_STOP);
- assertTrue(sessionCallback.await(TIME_OUT_MS));
- assertEquals(1, sessionCallback.mOnPlayCalledCount);
- assertTrue(sessionCallback.mOnStopCalled);
- synchronized (mWaitLock) {
- assertEquals(PlaybackStateCompat.STATE_STOPPED,
- mSession.getController().getPlaybackState().getState());
- }
- }
-
- private void setPlaybackState(int state) {
- final long allActions = PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE
- | PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_STOP
- | PlaybackStateCompat.ACTION_SKIP_TO_NEXT
- | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
- | PlaybackStateCompat.ACTION_FAST_FORWARD | PlaybackStateCompat.ACTION_REWIND;
- PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder().setActions(allActions)
- .setState(state, 0L, 0.0f).build();
- synchronized (mWaitLock) {
- mSession.setPlaybackState(playbackState);
- }
- }
-
- /**
- * Tests {@link MediaSessionCompat.QueueItem}.
- */
- @Test
- @SmallTest
- public void testQueueItem() {
- MediaSessionCompat.QueueItem item = new MediaSessionCompat.QueueItem(
- new MediaDescriptionCompat.Builder()
- .setMediaId("media-id")
- .setTitle("title")
- .build(),
- TEST_QUEUE_ID);
- assertEquals(TEST_QUEUE_ID, item.getQueueId());
- assertEquals("media-id", item.getDescription().getMediaId());
- assertEquals("title", item.getDescription().getTitle());
- assertEquals(0, item.describeContents());
-
- Parcel p = Parcel.obtain();
- item.writeToParcel(p, 0);
- p.setDataPosition(0);
- MediaSessionCompat.QueueItem other =
- MediaSessionCompat.QueueItem.CREATOR.createFromParcel(p);
- assertEquals(item.toString(), other.toString());
- p.recycle();
- }
-
- /**
- * Verifies that a new session hasn't had any configuration bits set yet.
- *
- * @param controller The controller for the session
- */
- private void verifyNewSession(MediaControllerCompat controller, String tag) {
- assertEquals("New session has unexpected configuration", 0L, controller.getFlags());
- assertNull("New session has unexpected configuration", controller.getExtras());
- assertNull("New session has unexpected configuration", controller.getMetadata());
- assertEquals("New session has unexpected configuration",
- getContext().getPackageName(), controller.getPackageName());
- assertNull("New session has unexpected configuration", controller.getPlaybackState());
- assertNull("New session has unexpected configuration", controller.getQueue());
- assertNull("New session has unexpected configuration", controller.getQueueTitle());
- assertEquals("New session has unexpected configuration", RatingCompat.RATING_NONE,
- controller.getRatingType());
- assertNull("New session has unexpected configuration", controller.getSessionActivity());
-
- assertNotNull(controller.getSessionToken());
- assertNotNull(controller.getTransportControls());
-
- MediaControllerCompat.PlaybackInfo info = controller.getPlaybackInfo();
- assertNotNull(info);
- assertEquals(MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_LOCAL,
- info.getPlaybackType());
- assertEquals(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC),
- info.getCurrentVolume());
- }
-
- private void sendMediaKeyInputToController(int keyCode) {
- sendMediaKeyInputToController(keyCode, false);
- }
-
- private void sendMediaKeyInputToController(int keyCode, boolean isLongPress) {
- MediaControllerCompat controller = mSession.getController();
- long currentTimeMs = System.currentTimeMillis();
- KeyEvent down = new KeyEvent(
- currentTimeMs, currentTimeMs, KeyEvent.ACTION_DOWN, keyCode, 0);
- controller.dispatchMediaButtonEvent(down);
- if (isLongPress) {
- KeyEvent longPress = new KeyEvent(
- currentTimeMs, System.currentTimeMillis(), KeyEvent.ACTION_DOWN, keyCode, 1);
- controller.dispatchMediaButtonEvent(longPress);
- }
- KeyEvent up = new KeyEvent(
- currentTimeMs, System.currentTimeMillis(), KeyEvent.ACTION_UP, keyCode, 0);
- controller.dispatchMediaButtonEvent(up);
- }
-
- private class MediaControllerCallback extends MediaControllerCompat.Callback {
- private volatile boolean mOnPlaybackStateChangedCalled;
- private volatile boolean mOnMetadataChangedCalled;
- private volatile boolean mOnQueueChangedCalled;
- private volatile boolean mOnQueueTitleChangedCalled;
- private volatile boolean mOnExtraChangedCalled;
- private volatile boolean mOnAudioInfoChangedCalled;
- private volatile boolean mOnSessionDestroyedCalled;
- private volatile boolean mOnSessionEventCalled;
- private volatile boolean mOnCaptioningEnabledChangedCalled;
- private volatile boolean mOnRepeatModeChangedCalled;
- private volatile boolean mOnShuffleModeChangedCalled;
-
- private volatile PlaybackStateCompat mPlaybackState;
- private volatile MediaMetadataCompat mMediaMetadata;
- private volatile List<MediaSessionCompat.QueueItem> mQueue;
- private volatile CharSequence mTitle;
- private volatile String mEvent;
- private volatile Bundle mExtras;
- private volatile MediaControllerCompat.PlaybackInfo mPlaybackInfo;
- private volatile boolean mCaptioningEnabled;
- private volatile int mRepeatMode;
- private volatile int mShuffleMode;
-
- public void resetLocked() {
- mOnPlaybackStateChangedCalled = false;
- mOnMetadataChangedCalled = false;
- mOnQueueChangedCalled = false;
- mOnQueueTitleChangedCalled = false;
- mOnExtraChangedCalled = false;
- mOnAudioInfoChangedCalled = false;
- mOnSessionDestroyedCalled = false;
- mOnSessionEventCalled = false;
- mOnRepeatModeChangedCalled = false;
- mOnShuffleModeChangedCalled = false;
-
- mPlaybackState = null;
- mMediaMetadata = null;
- mQueue = null;
- mTitle = null;
- mExtras = null;
- mPlaybackInfo = null;
- mCaptioningEnabled = false;
- mRepeatMode = PlaybackStateCompat.REPEAT_MODE_NONE;
- mShuffleMode = PlaybackStateCompat.SHUFFLE_MODE_NONE;
- }
-
- @Override
- public void onPlaybackStateChanged(PlaybackStateCompat state) {
- synchronized (mWaitLock) {
- mOnPlaybackStateChangedCalled = true;
- mPlaybackState = state;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onMetadataChanged(MediaMetadataCompat metadata) {
- synchronized (mWaitLock) {
- mOnMetadataChangedCalled = true;
- mMediaMetadata = metadata;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onQueueChanged(List<MediaSessionCompat.QueueItem> queue) {
- synchronized (mWaitLock) {
- mOnQueueChangedCalled = true;
- mQueue = queue;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onQueueTitleChanged(CharSequence title) {
- synchronized (mWaitLock) {
- mOnQueueTitleChangedCalled = true;
- mTitle = title;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onExtrasChanged(Bundle extras) {
- synchronized (mWaitLock) {
- mOnExtraChangedCalled = true;
- mExtras = extras;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onAudioInfoChanged(MediaControllerCompat.PlaybackInfo info) {
- synchronized (mWaitLock) {
- mOnAudioInfoChangedCalled = true;
- mPlaybackInfo = info;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onSessionDestroyed() {
- synchronized (mWaitLock) {
- mOnSessionDestroyedCalled = true;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onSessionEvent(String event, Bundle extras) {
- synchronized (mWaitLock) {
- mOnSessionEventCalled = true;
- mEvent = event;
- mExtras = (Bundle) extras.clone();
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onCaptioningEnabledChanged(boolean enabled) {
- synchronized (mWaitLock) {
- mOnCaptioningEnabledChangedCalled = true;
- mCaptioningEnabled = enabled;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onRepeatModeChanged(int repeatMode) {
- synchronized (mWaitLock) {
- mOnRepeatModeChangedCalled = true;
- mRepeatMode = repeatMode;
- mWaitLock.notify();
- }
- }
-
- @Override
- public void onShuffleModeChanged(int shuffleMode) {
- synchronized (mWaitLock) {
- mOnShuffleModeChangedCalled = true;
- mShuffleMode = shuffleMode;
- mWaitLock.notify();
- }
- }
- }
-
- private class MediaSessionCallback extends MediaSessionCompat.Callback {
- private CountDownLatch mLatch;
- private int mOnPlayCalledCount;
- private boolean mOnPauseCalled;
- private boolean mOnStopCalled;
- private boolean mOnFastForwardCalled;
- private boolean mOnRewindCalled;
- private boolean mOnSkipToPreviousCalled;
- private boolean mOnSkipToNextCalled;
-
- public void reset(int count) {
- mLatch = new CountDownLatch(count);
- mOnPlayCalledCount = 0;
- mOnPauseCalled = false;
- mOnStopCalled = false;
- mOnFastForwardCalled = false;
- mOnRewindCalled = false;
- mOnSkipToPreviousCalled = false;
- mOnSkipToNextCalled = false;
- }
-
- public boolean await(long timeoutMs) {
- try {
- return mLatch.await(timeoutMs, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- return false;
- }
- }
-
- @Override
- public void onPlay() {
- mOnPlayCalledCount++;
- setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
- mLatch.countDown();
- }
-
- @Override
- public void onPause() {
- mOnPauseCalled = true;
- setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
- mLatch.countDown();
- }
-
- @Override
- public void onStop() {
- mOnStopCalled = true;
- setPlaybackState(PlaybackStateCompat.STATE_STOPPED);
- mLatch.countDown();
- }
-
- @Override
- public void onFastForward() {
- mOnFastForwardCalled = true;
- mLatch.countDown();
- }
-
- @Override
- public void onRewind() {
- mOnRewindCalled = true;
- mLatch.countDown();
- }
-
- @Override
- public void onSkipToPrevious() {
- mOnSkipToPreviousCalled = true;
- mLatch.countDown();
- }
-
- @Override
- public void onSkipToNext() {
- mOnSkipToNextCalled = true;
- mLatch.countDown();
- }
- }
-}
diff --git a/media-compat/version-compat-tests/current/client/build.gradle b/media-compat/version-compat-tests/current/client/build.gradle
index d6f0e7d..aeb82c1 100644
--- a/media-compat/version-compat-tests/current/client/build.gradle
+++ b/media-compat/version-compat-tests/current/client/build.gradle
@@ -14,15 +14,17 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
+
plugins {
id("SupportAndroidLibraryPlugin")
}
dependencies {
- androidTestImplementation project(':support-media-compat')
- androidTestImplementation project(':support-media-compat-test-lib')
+ androidTestImplementation(project(":support-media-compat"))
+ androidTestImplementation(project(":support-media-compat-test-lib"))
- androidTestImplementation(libs.test_runner)
+ androidTestImplementation(TEST_RUNNER)
}
android {
diff --git a/media-compat/tests/src/android/support/v4/media/AudioAttributesCompatTest.java b/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/AudioAttributesCompatTest.java
similarity index 97%
rename from media-compat/tests/src/android/support/v4/media/AudioAttributesCompatTest.java
rename to media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/AudioAttributesCompatTest.java
index d66c7fc..675c0fc 100644
--- a/media-compat/tests/src/android/support/v4/media/AudioAttributesCompatTest.java
+++ b/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/AudioAttributesCompatTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.support.v4.media;
+package android.support.mediacompat.client;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.core.IsNot.not;
@@ -25,6 +25,7 @@
import android.support.test.filters.SdkSuppress;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.media.AudioAttributesCompat;
import org.junit.After;
import org.junit.Before;
diff --git a/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/ClientBroadcastReceiver.java b/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/ClientBroadcastReceiver.java
index 3166e55..3227482 100644
--- a/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/ClientBroadcastReceiver.java
+++ b/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/ClientBroadcastReceiver.java
@@ -19,6 +19,7 @@
import static android.support.mediacompat.testlib.MediaControllerConstants.ADD_QUEUE_ITEM;
import static android.support.mediacompat.testlib.MediaControllerConstants
.ADD_QUEUE_ITEM_WITH_INDEX;
+import static android.support.mediacompat.testlib.MediaControllerConstants.ADJUST_VOLUME;
import static android.support.mediacompat.testlib.MediaControllerConstants.FAST_FORWARD;
import static android.support.mediacompat.testlib.MediaControllerConstants.PAUSE;
import static android.support.mediacompat.testlib.MediaControllerConstants.PLAY;
@@ -40,6 +41,7 @@
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_RATING;
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_REPEAT_MODE;
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_SHUFFLE_MODE;
+import static android.support.mediacompat.testlib.MediaControllerConstants.SET_VOLUME_TO;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_NEXT;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_PREVIOUS;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_QUEUE_ITEM;
@@ -105,6 +107,12 @@
controller.removeQueueItem(
(MediaDescriptionCompat) extras.getParcelable(KEY_ARGUMENT));
break;
+ case SET_VOLUME_TO:
+ controller.setVolumeTo(extras.getInt(KEY_ARGUMENT), 0);
+ break;
+ case ADJUST_VOLUME:
+ controller.adjustVolume(extras.getInt(KEY_ARGUMENT), 0);
+ break;
}
} else if (ACTION_CALL_TRANSPORT_CONTROLS_METHOD.equals(intent.getAction())
&& extras != null) {
diff --git a/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaBrowserCompatTest.java b/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaBrowserCompatTest.java
index 31bdb7a..6144ede 100644
--- a/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaBrowserCompatTest.java
+++ b/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaBrowserCompatTest.java
@@ -26,10 +26,12 @@
import static android.support.mediacompat.testlib.MediaBrowserConstants.EXTRAS_VALUE;
import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_CHILDREN;
import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_CHILDREN_DELAYED;
+import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_INCLUDE_METADATA;
import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_INVALID;
import static android.support.mediacompat.testlib.MediaBrowserConstants
.MEDIA_ID_ON_LOAD_ITEM_NOT_IMPLEMENTED;
import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_ROOT;
+import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_METADATA;
import static android.support.mediacompat.testlib.MediaBrowserConstants.NOTIFY_CHILDREN_CHANGED;
import static android.support.mediacompat.testlib.MediaBrowserConstants.SEARCH_QUERY;
import static android.support.mediacompat.testlib.MediaBrowserConstants.SEARCH_QUERY_FOR_ERROR;
@@ -47,6 +49,8 @@
import static android.support.mediacompat.testlib.MediaBrowserConstants.TEST_VALUE_3;
import static android.support.mediacompat.testlib.MediaBrowserConstants.TEST_VALUE_4;
import static android.support.mediacompat.testlib.VersionConstants.KEY_SERVICE_VERSION;
+import static android.support.mediacompat.testlib.VersionConstants.VERSION_TOT;
+import static android.support.mediacompat.testlib.util.IntentUtil.SERVICE_PACKAGE_NAME;
import static android.support.mediacompat.testlib.util.IntentUtil.callMediaBrowserServiceMethod;
import static android.support.test.InstrumentationRegistry.getArguments;
import static android.support.test.InstrumentationRegistry.getContext;
@@ -56,6 +60,7 @@
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertSame;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@@ -71,6 +76,8 @@
import android.support.v4.media.MediaBrowserCompat.MediaItem;
import android.support.v4.media.MediaBrowserServiceCompat;
import android.support.v4.media.MediaDescriptionCompat;
+import android.support.v4.media.MediaMetadataCompat;
+import android.support.v4.media.RatingCompat;
import android.util.Log;
import org.junit.After;
@@ -80,6 +87,8 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Test {@link android.support.v4.media.MediaBrowserCompat}.
@@ -105,13 +114,15 @@
*/
private static final long SLEEP_MS = 100L;
private static final ComponentName TEST_BROWSER_SERVICE = new ComponentName(
- "android.support.mediacompat.service.test",
+ SERVICE_PACKAGE_NAME,
"android.support.mediacompat.service.StubMediaBrowserServiceCompat");
private static final ComponentName TEST_BROWSER_SERVICE_DELAYED_MEDIA_SESSION =
new ComponentName(
- "android.support.mediacompat.service.test",
+ SERVICE_PACKAGE_NAME,
"android.support.mediacompat.service"
+ ".StubMediaBrowserServiceCompatWithDelayedMediaSession");
+ private static final ComponentName TEST_INVALID_BROWSER_SERVICE = new ComponentName(
+ "invalid.package", "invalid.ServiceClassName");
private String mServiceVersion;
private MediaBrowserCompat mMediaBrowser;
@@ -157,6 +168,21 @@
@Test
@SmallTest
+ public void testBrowserRoot() {
+ final String id = "test-id";
+ final String key = "test-key";
+ final String val = "test-val";
+ final Bundle extras = new Bundle();
+ extras.putString(key, val);
+
+ MediaBrowserServiceCompat.BrowserRoot browserRoot =
+ new MediaBrowserServiceCompat.BrowserRoot(id, extras);
+ assertEquals(id, browserRoot.getRootId());
+ assertEquals(val, browserRoot.getExtras().getString(key));
+ }
+
+ @Test
+ @SmallTest
public void testMediaBrowser() throws Exception {
assertFalse(mMediaBrowser.isConnected());
@@ -178,6 +204,37 @@
@Test
@SmallTest
+ public void testGetServiceComponentBeforeConnection() {
+ try {
+ ComponentName serviceComponent = mMediaBrowser.getServiceComponent();
+ fail();
+ } catch (IllegalStateException e) {
+ // expected
+ }
+ }
+
+ @Test
+ @SmallTest
+ public void testConnectionFailed() throws Exception {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mMediaBrowser = new MediaBrowserCompat(getInstrumentation().getTargetContext(),
+ TEST_INVALID_BROWSER_SERVICE, mConnectionCallback, mRootHints);
+ }
+ });
+
+ synchronized (mConnectionCallback.mWaitLock) {
+ mMediaBrowser.connect();
+ mConnectionCallback.mWaitLock.wait(TIME_OUT_MS);
+ }
+ assertEquals(1, mConnectionCallback.mConnectionFailedCount);
+ assertEquals(0, mConnectionCallback.mConnectedCount);
+ assertEquals(0, mConnectionCallback.mConnectionSuspendedCount);
+ }
+
+ @Test
+ @SmallTest
public void testConnectTwice() throws Exception {
connectMediaBrowserService();
try {
@@ -206,18 +263,16 @@
assertEquals(1, mConnectionCallback.mConnectedCount);
}
- synchronized (mSubscriptionCallback.mWaitLock) {
- // Test subscribe.
- resetCallbacks();
- mMediaBrowser.subscribe(MEDIA_ID_ROOT, mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedCount > 0);
- assertEquals(MEDIA_ID_ROOT, mSubscriptionCallback.mLastParentId);
- }
+ // Test subscribe.
+ mSubscriptionCallback.reset(1);
+ mMediaBrowser.subscribe(MEDIA_ID_ROOT, mSubscriptionCallback);
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(1, mSubscriptionCallback.mChildrenLoadedCount);
+ assertEquals(MEDIA_ID_ROOT, mSubscriptionCallback.mLastParentId);
synchronized (mItemCallback.mWaitLock) {
// Test getItem.
- resetCallbacks();
+ mItemCallback.reset();
mMediaBrowser.getItem(MEDIA_ID_CHILDREN[0], mItemCallback);
mItemCallback.mWaitLock.wait(TIME_OUT_MS);
assertEquals(MEDIA_ID_CHILDREN[0], mItemCallback.mLastMediaItem.getMediaId());
@@ -225,12 +280,11 @@
// Reconnect after connection was established.
mMediaBrowser.disconnect();
- resetCallbacks();
connectMediaBrowserService();
synchronized (mItemCallback.mWaitLock) {
// Test getItem.
- resetCallbacks();
+ mItemCallback.reset();
mMediaBrowser.getItem(MEDIA_ID_CHILDREN[0], mItemCallback);
mItemCallback.mWaitLock.wait(TIME_OUT_MS);
assertEquals(MEDIA_ID_CHILDREN[0], mItemCallback.mLastMediaItem.getMediaId());
@@ -245,7 +299,7 @@
public void run() {
mMediaBrowser.connect();
mMediaBrowser.disconnect();
- resetCallbacks();
+ mConnectionCallback.reset();
}
});
@@ -259,48 +313,43 @@
assertEquals(0, mConnectionCallback.mConnectionSuspendedCount);
}
-// @Test
-// @MediumTest
+ @Test
+ @MediumTest
public void testSubscribe() throws Exception {
connectMediaBrowserService();
- synchronized (mSubscriptionCallback.mWaitLock) {
- mMediaBrowser.subscribe(MEDIA_ID_ROOT, mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedCount > 0);
- assertEquals(MEDIA_ID_ROOT, mSubscriptionCallback.mLastParentId);
- assertEquals(MEDIA_ID_CHILDREN.length,
- mSubscriptionCallback.mLastChildMediaItems.size());
- for (int i = 0; i < MEDIA_ID_CHILDREN.length; ++i) {
- assertEquals(MEDIA_ID_CHILDREN[i],
- mSubscriptionCallback.mLastChildMediaItems.get(i).getMediaId());
- }
-
- // Test MediaBrowserServiceCompat.notifyChildrenChanged()
- mSubscriptionCallback.reset();
- callMediaBrowserServiceMethod(NOTIFY_CHILDREN_CHANGED, MEDIA_ID_ROOT, getContext());
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedCount > 0);
+ mSubscriptionCallback.reset(1);
+ mMediaBrowser.subscribe(MEDIA_ID_ROOT, mSubscriptionCallback);
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(1, mSubscriptionCallback.mChildrenLoadedCount);
+ assertEquals(MEDIA_ID_ROOT, mSubscriptionCallback.mLastParentId);
+ assertEquals(MEDIA_ID_CHILDREN.length, mSubscriptionCallback.mLastChildMediaItems.size());
+ for (int i = 0; i < MEDIA_ID_CHILDREN.length; ++i) {
+ assertEquals(MEDIA_ID_CHILDREN[i],
+ mSubscriptionCallback.mLastChildMediaItems.get(i).getMediaId());
}
+ // Test MediaBrowserServiceCompat.notifyChildrenChanged()
+ mSubscriptionCallback.reset(1);
+ callMediaBrowserServiceMethod(NOTIFY_CHILDREN_CHANGED, MEDIA_ID_ROOT, getContext());
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(1, mSubscriptionCallback.mChildrenLoadedCount);
+
// Test unsubscribe.
- resetCallbacks();
+ mSubscriptionCallback.reset(1);
mMediaBrowser.unsubscribe(MEDIA_ID_ROOT);
// After unsubscribing, make StubMediaBrowserServiceCompat notify that the children are
// changed.
callMediaBrowserServiceMethod(NOTIFY_CHILDREN_CHANGED, MEDIA_ID_ROOT, getContext());
- try {
- Thread.sleep(SLEEP_MS);
- } catch (InterruptedException e) {
- fail("Unexpected InterruptedException occurred.");
- }
+ mSubscriptionCallback.await(WAIT_TIME_FOR_NO_RESPONSE_MS);
+
// onChildrenLoaded should not be called.
assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
}
-// @Test
-// @MediumTest
+ @Test
+ @MediumTest
public void testSubscribeWithOptions() throws Exception {
connectMediaBrowserService();
final int pageSize = 3;
@@ -308,36 +357,34 @@
Bundle options = new Bundle();
options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
- synchronized (mSubscriptionCallback.mWaitLock) {
- for (int page = 0; page <= lastPage; ++page) {
- resetCallbacks();
- options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
- mMediaBrowser.subscribe(MEDIA_ID_ROOT, options, mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedWithOptionCount > 0);
- assertEquals(MEDIA_ID_ROOT, mSubscriptionCallback.mLastParentId);
- if (page != lastPage) {
- assertEquals(pageSize, mSubscriptionCallback.mLastChildMediaItems.size());
- } else {
- assertEquals((MEDIA_ID_CHILDREN.length - 1) % pageSize + 1,
- mSubscriptionCallback.mLastChildMediaItems.size());
- }
- // Check whether all the items in the current page are loaded.
- for (int i = 0; i < mSubscriptionCallback.mLastChildMediaItems.size(); ++i) {
- assertEquals(MEDIA_ID_CHILDREN[page * pageSize + i],
- mSubscriptionCallback.mLastChildMediaItems.get(i).getMediaId());
- }
+ for (int page = 0; page <= lastPage; ++page) {
+ mSubscriptionCallback.reset(1);
+ options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
+ mMediaBrowser.subscribe(MEDIA_ID_ROOT, options, mSubscriptionCallback);
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(1, mSubscriptionCallback.mChildrenLoadedWithOptionCount);
+ assertEquals(MEDIA_ID_ROOT, mSubscriptionCallback.mLastParentId);
+ if (page != lastPage) {
+ assertEquals(pageSize, mSubscriptionCallback.mLastChildMediaItems.size());
+ } else {
+ assertEquals((MEDIA_ID_CHILDREN.length - 1) % pageSize + 1,
+ mSubscriptionCallback.mLastChildMediaItems.size());
+ }
+ // Check whether all the items in the current page are loaded.
+ for (int i = 0; i < mSubscriptionCallback.mLastChildMediaItems.size(); ++i) {
+ assertEquals(MEDIA_ID_CHILDREN[page * pageSize + i],
+ mSubscriptionCallback.mLastChildMediaItems.get(i).getMediaId());
}
// Test MediaBrowserServiceCompat.notifyChildrenChanged()
- mSubscriptionCallback.reset();
+ mSubscriptionCallback.reset(page + 1);
callMediaBrowserServiceMethod(NOTIFY_CHILDREN_CHANGED, MEDIA_ID_ROOT, getContext());
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedWithOptionCount > 0);
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(page + 1, mSubscriptionCallback.mChildrenLoadedWithOptionCount);
}
// Test unsubscribe with callback argument.
- resetCallbacks();
+ mSubscriptionCallback.reset(1);
mMediaBrowser.unsubscribe(MEDIA_ID_ROOT, mSubscriptionCallback);
// After unsubscribing, make StubMediaBrowserServiceCompat notify that the children are
@@ -353,20 +400,61 @@
}
@Test
+ @SmallTest
+ public void testSubscribeWithOptionsIncludingCompatParcelables() throws Exception {
+ if (Build.VERSION.SDK_INT >= 26 && !VERSION_TOT.equals(mServiceVersion)) {
+ // This test will fail on API 26 or newer APIs if the service application uses
+ // support library v27.0.1 or lower versions.
+ return;
+ }
+ connectMediaBrowserService();
+
+ final String mediaId = "1000";
+ final RatingCompat percentageRating = RatingCompat.newPercentageRating(0.5f);
+ final RatingCompat starRating =
+ RatingCompat.newStarRating(RatingCompat.RATING_5_STARS, 4.0f);
+ MediaMetadataCompat mediaMetadataCompat = new MediaMetadataCompat.Builder()
+ .putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, mediaId)
+ .putString(MediaMetadataCompat.METADATA_KEY_TITLE, "title")
+ .putRating(MediaMetadataCompat.METADATA_KEY_RATING, percentageRating)
+ .putRating(MediaMetadataCompat.METADATA_KEY_USER_RATING, starRating)
+ .build();
+ Bundle options = new Bundle();
+ options.putParcelable(MEDIA_METADATA, mediaMetadataCompat);
+
+ // Remote MediaBrowserService will create a media item with the given MediaMetadataCompat.
+ mSubscriptionCallback.reset(1);
+ mMediaBrowser.subscribe(MEDIA_ID_INCLUDE_METADATA, options, mSubscriptionCallback);
+ mSubscriptionCallback.await(TIME_OUT_MS);
+
+ assertEquals(1, mSubscriptionCallback.mChildrenLoadedWithOptionCount);
+ assertEquals(1, mSubscriptionCallback.mLastChildMediaItems.size());
+ assertEquals(mediaId, mSubscriptionCallback.mLastChildMediaItems.get(0).getMediaId());
+
+ MediaMetadataCompat metadataOut = mSubscriptionCallback.mLastOptions
+ .getParcelable(MEDIA_METADATA);
+ assertEquals(mediaId, metadataOut.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID));
+ assertEquals("title", metadataOut.getString(MediaMetadataCompat.METADATA_KEY_TITLE));
+ assertRatingEquals(percentageRating,
+ metadataOut.getRating(MediaMetadataCompat.METADATA_KEY_RATING));
+ assertRatingEquals(starRating,
+ metadataOut.getRating(MediaMetadataCompat.METADATA_KEY_USER_RATING));
+ }
+
+ @Test
@MediumTest
public void testSubscribeDelayedItems() throws Exception {
connectMediaBrowserService();
- synchronized (mSubscriptionCallback.mWaitLock) {
- mSubscriptionCallback.reset();
- mMediaBrowser.subscribe(MEDIA_ID_CHILDREN_DELAYED, mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
- callMediaBrowserServiceMethod(
- SEND_DELAYED_NOTIFY_CHILDREN_CHANGED, MEDIA_ID_CHILDREN_DELAYED, getContext());
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedCount > 0);
- }
+ mSubscriptionCallback.reset(1);
+ mMediaBrowser.subscribe(MEDIA_ID_CHILDREN_DELAYED, mSubscriptionCallback);
+ mSubscriptionCallback.await(WAIT_TIME_FOR_NO_RESPONSE_MS);
+ assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
+
+ callMediaBrowserServiceMethod(
+ SEND_DELAYED_NOTIFY_CHILDREN_CHANGED, MEDIA_ID_CHILDREN_DELAYED, getContext());
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(1, mSubscriptionCallback.mChildrenLoadedCount);
}
@Test
@@ -374,11 +462,10 @@
public void testSubscribeInvalidItem() throws Exception {
connectMediaBrowserService();
- synchronized (mSubscriptionCallback.mWaitLock) {
- mMediaBrowser.subscribe(MEDIA_ID_INVALID, mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertEquals(MEDIA_ID_INVALID, mSubscriptionCallback.mLastErrorId);
- }
+ mSubscriptionCallback.reset(1);
+ mMediaBrowser.subscribe(MEDIA_ID_INVALID, mSubscriptionCallback);
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(MEDIA_ID_INVALID, mSubscriptionCallback.mLastErrorId);
}
@Test
@@ -392,16 +479,15 @@
options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
- synchronized (mSubscriptionCallback.mWaitLock) {
- mMediaBrowser.subscribe(MEDIA_ID_INVALID, options, mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertEquals(MEDIA_ID_INVALID, mSubscriptionCallback.mLastErrorId);
- assertNotNull(mSubscriptionCallback.mLastOptions);
- assertEquals(page,
- mSubscriptionCallback.mLastOptions.getInt(MediaBrowserCompat.EXTRA_PAGE));
- assertEquals(pageSize,
- mSubscriptionCallback.mLastOptions.getInt(MediaBrowserCompat.EXTRA_PAGE_SIZE));
- }
+ mSubscriptionCallback.reset(1);
+ mMediaBrowser.subscribe(MEDIA_ID_INVALID, options, mSubscriptionCallback);
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(MEDIA_ID_INVALID, mSubscriptionCallback.mLastErrorId);
+ assertNotNull(mSubscriptionCallback.mLastOptions);
+ assertEquals(page,
+ mSubscriptionCallback.mLastOptions.getInt(MediaBrowserCompat.EXTRA_PAGE));
+ assertEquals(pageSize,
+ mSubscriptionCallback.mLastOptions.getInt(MediaBrowserCompat.EXTRA_PAGE_SIZE));
}
@Test
@@ -419,17 +505,17 @@
Bundle options = new Bundle();
options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
+ callback.reset(1);
mMediaBrowser.subscribe(MEDIA_ID_ROOT, options, callback);
- synchronized (callback.mWaitLock) {
- callback.mWaitLock.wait(TIME_OUT_MS);
- }
+ callback.await(TIME_OUT_MS);
+
// Each onChildrenLoaded() must be called.
assertEquals(1, callback.mChildrenLoadedWithOptionCount);
}
// Reset callbacks and unsubscribe.
for (StubSubscriptionCallback callback : subscriptionCallbacks) {
- callback.reset();
+ callback.reset(1);
}
mMediaBrowser.unsubscribe(MEDIA_ID_ROOT);
@@ -448,8 +534,8 @@
}
}
-// @Test
-// @MediumTest
+ @Test
+ @MediumTest
public void testUnsubscribeWithSubscriptionCallbackForMultipleSubscriptions() throws Exception {
connectMediaBrowserService();
final List<StubSubscriptionCallback> subscriptionCallbacks = new ArrayList<>();
@@ -463,10 +549,10 @@
Bundle options = new Bundle();
options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
+ callback.reset(1);
mMediaBrowser.subscribe(MEDIA_ID_ROOT, options, callback);
- synchronized (callback.mWaitLock) {
- callback.mWaitLock.wait(TIME_OUT_MS);
- }
+ callback.await(TIME_OUT_MS);
+
// Each onChildrenLoaded() must be called.
assertEquals(1, callback.mChildrenLoadedWithOptionCount);
}
@@ -476,7 +562,7 @@
for (int i = 0; i < orderOfRemovingCallbacks.length; i++) {
// Reset callbacks
for (StubSubscriptionCallback callback : subscriptionCallbacks) {
- callback.reset();
+ callback.reset(1);
}
// Remove one subscription
@@ -611,6 +697,7 @@
customActionExtras.putString(TEST_KEY_1, TEST_VALUE_1);
mMediaBrowser.sendCustomAction(
CUSTOM_ACTION, customActionExtras, mCustomActionCallback);
+ mCustomActionCallback.mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
mCustomActionCallback.reset();
Bundle data1 = new Bundle();
@@ -701,6 +788,8 @@
Bundle customActionExtras = new Bundle();
customActionExtras.putString(TEST_KEY_1, TEST_VALUE_1);
mMediaBrowser.sendCustomAction(CUSTOM_ACTION, customActionExtras, null);
+ // Wait some time so that the service can get a result receiver for the custom action.
+ Thread.sleep(WAIT_TIME_FOR_NO_RESPONSE_MS);
// These calls should not make any exceptions.
callMediaBrowserServiceMethod(CUSTOM_ACTION_SEND_PROGRESS_UPDATE, new Bundle(),
@@ -768,10 +857,20 @@
}
}
- private void resetCallbacks() {
- mConnectionCallback.reset();
- mSubscriptionCallback.reset();
- mItemCallback.reset();
+ private void assertRatingEquals(RatingCompat expected, RatingCompat observed) {
+ if (expected == null || observed == null) {
+ assertSame(expected, observed);
+ }
+ assertEquals(expected.getRatingStyle(), observed.getRatingStyle());
+
+ if (expected.getRatingStyle() == RatingCompat.RATING_PERCENTAGE) {
+ assertEquals(expected.getPercentRating(), observed.getPercentRating());
+ } else if (expected.getRatingStyle() == RatingCompat.RATING_5_STARS) {
+ assertEquals(expected.getStarRating(), observed.getStarRating());
+ } else {
+ // Currently, we use only star and percentage rating.
+ fail("Rating style should be either percentage rating or star rating.");
+ }
}
private class StubConnectionCallback extends MediaBrowserCompat.ConnectionCallback {
@@ -812,7 +911,7 @@
}
private class StubSubscriptionCallback extends MediaBrowserCompat.SubscriptionCallback {
- final Object mWaitLock = new Object();
+ private CountDownLatch mLatch;
private volatile int mChildrenLoadedCount;
private volatile int mChildrenLoadedWithOptionCount;
private volatile String mLastErrorId;
@@ -820,7 +919,8 @@
private volatile Bundle mLastOptions;
private volatile List<MediaItem> mLastChildMediaItems;
- public void reset() {
+ public void reset(int count) {
+ mLatch = new CountDownLatch(count);
mChildrenLoadedCount = 0;
mChildrenLoadedWithOptionCount = 0;
mLastErrorId = null;
@@ -829,43 +929,43 @@
mLastChildMediaItems = null;
}
+ public boolean await(long timeoutMs) {
+ try {
+ return mLatch.await(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+
@Override
public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children) {
- synchronized (mWaitLock) {
- mChildrenLoadedCount++;
- mLastParentId = parentId;
- mLastChildMediaItems = children;
- mWaitLock.notify();
- }
+ mChildrenLoadedCount++;
+ mLastParentId = parentId;
+ mLastChildMediaItems = children;
+ mLatch.countDown();
}
@Override
public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children,
@NonNull Bundle options) {
- synchronized (mWaitLock) {
- mChildrenLoadedWithOptionCount++;
- mLastParentId = parentId;
- mLastOptions = options;
- mLastChildMediaItems = children;
- mWaitLock.notify();
- }
+ mChildrenLoadedWithOptionCount++;
+ mLastParentId = parentId;
+ mLastOptions = options;
+ mLastChildMediaItems = children;
+ mLatch.countDown();
}
@Override
public void onError(@NonNull String id) {
- synchronized (mWaitLock) {
- mLastErrorId = id;
- mWaitLock.notify();
- }
+ mLastErrorId = id;
+ mLatch.countDown();
}
@Override
public void onError(@NonNull String id, @NonNull Bundle options) {
- synchronized (mWaitLock) {
- mLastErrorId = id;
- mLastOptions = options;
- mWaitLock.notify();
- }
+ mLastErrorId = id;
+ mLastOptions = options;
+ mLatch.countDown();
}
}
diff --git a/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java b/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
index 79993ef..4b845c1 100644
--- a/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
+++ b/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
@@ -46,6 +46,7 @@
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_SESSION_EVENT;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_VALUE;
import static android.support.mediacompat.testlib.VersionConstants.KEY_SERVICE_VERSION;
+import static android.support.mediacompat.testlib.util.IntentUtil.SERVICE_PACKAGE_NAME;
import static android.support.mediacompat.testlib.util.IntentUtil.callMediaSessionMethod;
import static android.support.mediacompat.testlib.util.TestUtil.assertBundleEquals;
import static android.support.test.InstrumentationRegistry.getArguments;
@@ -55,9 +56,11 @@
import static android.support.v4.media.MediaMetadataCompat.METADATA_KEY_RATING;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -84,8 +87,6 @@
import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
-import junit.framework.Assert;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -107,7 +108,7 @@
private static final int MAX_AUDIO_INFO_CHANGED_CALLBACK_COUNT = 10;
private static final ComponentName TEST_BROWSER_SERVICE = new ComponentName(
- "android.support.mediacompat.service.test",
+ SERVICE_PACKAGE_NAME,
"android.support.mediacompat.service.StubMediaBrowserServiceCompat");
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -119,6 +120,7 @@
private MediaBrowserCompat mMediaBrowser;
private ConnectionCallback mConnectionCallback = new ConnectionCallback();
+ private MediaSessionCompat.Token mSessionToken;
private MediaControllerCompat mController;
private MediaControllerCallback mMediaControllerCallback = new MediaControllerCallback();
@@ -140,11 +142,11 @@
mMediaBrowser.connect();
mConnectionCallback.mWaitLock.wait(TIME_OUT_MS);
if (!mMediaBrowser.isConnected()) {
- Assert.fail("Browser failed to connect!");
+ fail("Browser failed to connect!");
}
}
- mController =
- new MediaControllerCompat(getTargetContext(), mMediaBrowser.getSessionToken());
+ mSessionToken = mMediaBrowser.getSessionToken();
+ mController = new MediaControllerCompat(getTargetContext(), mSessionToken);
mController.registerCallback(mMediaControllerCallback, mHandler);
}
@@ -155,6 +157,20 @@
}
}
+ @Test
+ @SmallTest
+ public void testGetPackageName() {
+ assertEquals(SERVICE_PACKAGE_NAME, mController.getPackageName());
+ }
+
+ @Test
+ @SmallTest
+ public void testIsSessionReady() throws Exception {
+ // mController already has the extra binder since it was created with the session token
+ // which holds the extra binder.
+ assertTrue(mController.isSessionReady());
+ }
+
/**
* Tests {@link MediaSessionCompat#setExtras}.
*/
@@ -541,6 +557,36 @@
}.run();
}
+ @Test
+ @SmallTest
+ public void testSessionReady() throws Exception {
+ if (android.os.Build.VERSION.SDK_INT < 21) {
+ return;
+ }
+
+ final MediaSessionCompat.Token tokenWithoutExtraBinder =
+ MediaSessionCompat.Token.fromToken(mSessionToken.getToken());
+
+ final MediaControllerCallback callback = new MediaControllerCallback();
+ synchronized (mWaitLock) {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ MediaControllerCompat controller = new MediaControllerCompat(
+ getInstrumentation().getTargetContext(), tokenWithoutExtraBinder);
+ controller.registerCallback(callback, new Handler());
+ assertFalse(controller.isSessionReady());
+ } catch (Exception e) {
+ fail();
+ }
+ }
+ });
+ mWaitLock.wait(TIME_OUT_MS);
+ assertTrue(callback.mOnSessionReadyCalled);
+ }
+ }
+
private void assertQueueEquals(List<QueueItem> expected, List<QueueItem> observed) {
if (expected == null || observed == null) {
assertTrue(expected == observed);
@@ -570,6 +616,7 @@
private volatile boolean mOnCaptioningEnabledChangedCalled;
private volatile boolean mOnRepeatModeChangedCalled;
private volatile boolean mOnShuffleModeChangedCalled;
+ private volatile boolean mOnSessionReadyCalled;
private volatile PlaybackStateCompat mPlaybackState;
private volatile MediaMetadataCompat mMediaMetadata;
@@ -703,6 +750,14 @@
mWaitLock.notify();
}
}
+
+ @Override
+ public void onSessionReady() {
+ synchronized (mWaitLock) {
+ mOnSessionReadyCalled = true;
+ mWaitLock.notify();
+ }
+ }
}
private class ConnectionCallback extends MediaBrowserCompat.ConnectionCallback {
diff --git a/media-compat/tests/src/android/support/v4/media/MediaItemTest.java b/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaItemTest.java
similarity index 94%
rename from media-compat/tests/src/android/support/v4/media/MediaItemTest.java
rename to media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaItemTest.java
index bd2565f..179a178 100644
--- a/media-compat/tests/src/android/support/v4/media/MediaItemTest.java
+++ b/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaItemTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.support.v4.media;
+package android.support.mediacompat.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -22,11 +22,12 @@
import android.os.Parcel;
import android.support.test.filters.SmallTest;
import android.support.v4.media.MediaBrowserCompat.MediaItem;
+import android.support.v4.media.MediaDescriptionCompat;
import org.junit.Test;
/**
- * Test {@link MediaBrowserCompat.MediaItem}.
+ * Test {@link MediaItem}.
*/
public class MediaItemTest {
private static final String DESCRIPTION = "test_description";
diff --git a/media-compat/tests/src/android/support/v4/media/session/PlaybackStateCompatTest.java b/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/PlaybackStateCompatTest.java
similarity index 97%
rename from media-compat/tests/src/android/support/v4/media/session/PlaybackStateCompatTest.java
rename to media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/PlaybackStateCompatTest.java
index 9e320cd..7962731 100644
--- a/media-compat/tests/src/android/support/v4/media/session/PlaybackStateCompatTest.java
+++ b/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/PlaybackStateCompatTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v4.media.session;
+package android.support.mediacompat.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -24,6 +24,8 @@
import android.os.Parcel;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/media-compat/version-compat-tests/current/service/build.gradle b/media-compat/version-compat-tests/current/service/build.gradle
index 2cfa5ce..cf82918 100644
--- a/media-compat/version-compat-tests/current/service/build.gradle
+++ b/media-compat/version-compat-tests/current/service/build.gradle
@@ -14,15 +14,17 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
+
plugins {
id("SupportAndroidLibraryPlugin")
}
dependencies {
- androidTestImplementation project(':support-media-compat')
- androidTestImplementation project(':support-media-compat-test-lib')
+ androidTestImplementation(project(":support-media-compat"))
+ androidTestImplementation(project(":support-media-compat-test-lib"))
- androidTestImplementation(libs.test_runner)
+ androidTestImplementation(TEST_RUNNER)
}
android {
diff --git a/media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java b/media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
index d36eba3..5c5a432 100644
--- a/media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
+++ b/media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
@@ -18,6 +18,7 @@
import static android.support.mediacompat.testlib.MediaControllerConstants.ADD_QUEUE_ITEM;
import static android.support.mediacompat.testlib.MediaControllerConstants
.ADD_QUEUE_ITEM_WITH_INDEX;
+import static android.support.mediacompat.testlib.MediaControllerConstants.ADJUST_VOLUME;
import static android.support.mediacompat.testlib.MediaControllerConstants.FAST_FORWARD;
import static android.support.mediacompat.testlib.MediaControllerConstants.PAUSE;
import static android.support.mediacompat.testlib.MediaControllerConstants.PLAY;
@@ -39,12 +40,18 @@
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_RATING;
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_REPEAT_MODE;
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_SHUFFLE_MODE;
+import static android.support.mediacompat.testlib.MediaControllerConstants.SET_VOLUME_TO;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_NEXT;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_PREVIOUS;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_QUEUE_ITEM;
import static android.support.mediacompat.testlib.MediaControllerConstants.STOP;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_COMMAND;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_KEY;
+import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_MEDIA_ID_1;
+import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_MEDIA_ID_2;
+import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_MEDIA_TITLE_1;
+import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_MEDIA_TITLE_2;
+import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_QUEUE_ID_1;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_SESSION_TAG;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_VALUE;
import static android.support.mediacompat.testlib.VersionConstants.KEY_CLIENT_VERSION;
@@ -57,21 +64,38 @@
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
+import android.os.Parcel;
import android.os.ResultReceiver;
+import android.os.SystemClock;
+import android.support.test.filters.MediumTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.RatingCompat;
+import android.support.v4.media.VolumeProviderCompat;
+import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
+import android.view.KeyEvent;
import org.junit.After;
import org.junit.Before;
@@ -80,6 +104,8 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Test {@link MediaSessionCompat.Callback}.
@@ -91,6 +117,10 @@
// The maximum time to wait for an operation.
private static final long TIME_OUT_MS = 3000L;
+ private static final long WAIT_TIME_FOR_NO_RESPONSE_MS = 300L;
+
+ private static final long TEST_POSITION = 1000000L;
+ private static final float TEST_PLAYBACK_SPEED = 3.0f;
private static final float DELTA = 1e-4f;
private static final boolean ENABLED = true;
@@ -99,6 +129,7 @@
private String mClientVersion;
private MediaSessionCompat mSession;
private MediaSessionCallback mCallback = new MediaSessionCallback();
+ private AudioManager mAudioManager;
@Before
public void setUp() throws Exception {
@@ -109,9 +140,9 @@
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
+ mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mSession = new MediaSessionCompat(getTargetContext(), TEST_SESSION_TAG);
mSession.setCallback(mCallback, mHandler);
- mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS);
}
});
}
@@ -121,277 +152,662 @@
mSession.release();
}
+ /**
+ * Tests that a session can be created and that all the fields are initialized correctly.
+ */
+ @Test
+ @SmallTest
+ public void testCreateSession() throws Exception {
+ assertNotNull(mSession.getSessionToken());
+ assertFalse("New session should not be active", mSession.isActive());
+
+ // Verify by getting the controller and checking all its fields
+ MediaControllerCompat controller = mSession.getController();
+ assertNotNull(controller);
+
+ final String errorMsg = "New session has unexpected configuration.";
+ assertEquals(errorMsg, 0L, controller.getFlags());
+ assertNull(errorMsg, controller.getExtras());
+ assertNull(errorMsg, controller.getMetadata());
+ assertEquals(errorMsg, getContext().getPackageName(), controller.getPackageName());
+ assertNull(errorMsg, controller.getPlaybackState());
+ assertNull(errorMsg, controller.getQueue());
+ assertNull(errorMsg, controller.getQueueTitle());
+ assertEquals(errorMsg, RatingCompat.RATING_NONE, controller.getRatingType());
+ assertNull(errorMsg, controller.getSessionActivity());
+
+ assertNotNull(controller.getSessionToken());
+ assertNotNull(controller.getTransportControls());
+
+ MediaControllerCompat.PlaybackInfo info = controller.getPlaybackInfo();
+ assertNotNull(info);
+ assertEquals(errorMsg, MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_LOCAL,
+ info.getPlaybackType());
+ assertEquals(errorMsg, mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC),
+ info.getCurrentVolume());
+ }
+
+ @Test
+ @SmallTest
+ public void testGetSessionToken() throws Exception {
+ assertEquals(mSession.getSessionToken(), mSession.getController().getSessionToken());
+ }
+
+ /**
+ * Tests that a session can be created from the framework session object and the callback
+ * set on the framework session object before fromSession() is called works properly.
+ */
+ @Test
+ @SmallTest
+ public void testFromSession() throws Exception {
+ if (android.os.Build.VERSION.SDK_INT < 21) {
+ // MediaSession was introduced from API level 21.
+ return;
+ }
+ mCallback.reset(1);
+ mSession.setCallback(mCallback, new Handler(Looper.getMainLooper()));
+ MediaSessionCompat session = MediaSessionCompat.fromMediaSession(
+ getContext(), mSession.getMediaSession());
+ assertEquals(session.getSessionToken(), mSession.getSessionToken());
+
+ session.getController().getTransportControls().play();
+ mCallback.await(TIME_OUT_MS);
+ assertEquals(1, mCallback.mOnPlayCalledCount);
+ }
+
+ /**
+ * Tests {@link MediaSessionCompat.Token} created in the constructor of MediaSessionCompat.
+ */
+ @Test
+ @SmallTest
+ public void testSessionToken() throws Exception {
+ MediaSessionCompat.Token sessionToken = mSession.getSessionToken();
+
+ assertNotNull(sessionToken);
+ assertEquals(0, sessionToken.describeContents());
+
+ // Test writeToParcel
+ Parcel p = Parcel.obtain();
+ sessionToken.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ MediaSessionCompat.Token token = MediaSessionCompat.Token.CREATOR.createFromParcel(p);
+ assertEquals(token, sessionToken);
+ p.recycle();
+ }
+
+ /**
+ * Tests {@link MediaSessionCompat.QueueItem}.
+ */
+ @Test
+ @SmallTest
+ public void testQueueItem() {
+ MediaSessionCompat.QueueItem item = new MediaSessionCompat.QueueItem(
+ new MediaDescriptionCompat.Builder()
+ .setMediaId(TEST_MEDIA_ID_1)
+ .setTitle(TEST_MEDIA_TITLE_1)
+ .build(),
+ TEST_QUEUE_ID_1);
+ assertEquals(TEST_QUEUE_ID_1, item.getQueueId());
+ assertEquals(TEST_MEDIA_ID_1, item.getDescription().getMediaId());
+ assertEquals(TEST_MEDIA_TITLE_1, item.getDescription().getTitle());
+ assertEquals(0, item.describeContents());
+
+ Parcel p = Parcel.obtain();
+ item.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ MediaSessionCompat.QueueItem other =
+ MediaSessionCompat.QueueItem.CREATOR.createFromParcel(p);
+ assertEquals(item.toString(), other.toString());
+ p.recycle();
+ }
+
+ /**
+ * Tests {@link MediaSessionCompat#setActive}.
+ */
+ @Test
+ @SmallTest
+ public void testSetActive() throws Exception {
+ mSession.setActive(true);
+ assertTrue(mSession.isActive());
+ }
+
+ @Test
+ @SmallTest
+ public void testGetPlaybackStateWithPositionUpdate() throws InterruptedException {
+ final long stateSetTime = SystemClock.elapsedRealtime();
+ PlaybackStateCompat stateIn = new PlaybackStateCompat.Builder()
+ .setState(PlaybackStateCompat.STATE_PLAYING, TEST_POSITION, TEST_PLAYBACK_SPEED,
+ stateSetTime)
+ .build();
+ mSession.setPlaybackState(stateIn);
+
+ final long waitDuration = 100L;
+ Thread.sleep(waitDuration);
+
+ final long expectedUpdateTime = waitDuration + stateSetTime;
+ final long expectedPosition = (long) (TEST_PLAYBACK_SPEED * waitDuration) + TEST_POSITION;
+
+ final double updateTimeTolerance = 50L;
+ final double positionTolerance = updateTimeTolerance * TEST_PLAYBACK_SPEED;
+
+ PlaybackStateCompat stateOut = mSession.getController().getPlaybackState();
+ assertEquals(expectedUpdateTime, stateOut.getLastPositionUpdateTime(), updateTimeTolerance);
+ assertEquals(expectedPosition, stateOut.getPosition(), positionTolerance);
+
+ // Compare the result with MediaController.getPlaybackState().
+ if (Build.VERSION.SDK_INT >= 21) {
+ MediaController controller = new MediaController(
+ getContext(), (MediaSession.Token) mSession.getSessionToken().getToken());
+ PlaybackState state = controller.getPlaybackState();
+ assertEquals(state.getLastPositionUpdateTime(), stateOut.getLastPositionUpdateTime(),
+ updateTimeTolerance);
+ assertEquals(state.getPosition(), stateOut.getPosition(), positionTolerance);
+ }
+ }
+
+ /**
+ * Tests {@link MediaSessionCompat#setCallback} with {@code null}.
+ * No callback should be called once {@code setCallback(null)} is done.
+ */
+ @Test
+ @SmallTest
+ public void testSetCallbackWithNull() throws Exception {
+ mSession.setActive(true);
+ mCallback.reset(1);
+ callTransportControlsMethod(PLAY, null, getContext(), mSession.getSessionToken());
+ mSession.setCallback(null, mHandler);
+ mCallback.await(WAIT_TIME_FOR_NO_RESPONSE_MS);
+ assertEquals("Callback shouldn't be called.", 0, mCallback.mOnPlayCalledCount);
+ }
+
@Test
@SmallTest
public void testSendCommand() throws Exception {
- synchronized (mWaitLock) {
- mCallback.reset();
+ mCallback.reset(1);
- Bundle arguments = new Bundle();
- arguments.putString("command", TEST_COMMAND);
- Bundle extras = new Bundle();
- extras.putString(TEST_KEY, TEST_VALUE);
- arguments.putBundle("extras", extras);
- callMediaControllerMethod(
- SEND_COMMAND, arguments, getContext(), mSession.getSessionToken());
+ Bundle arguments = new Bundle();
+ arguments.putString("command", TEST_COMMAND);
+ Bundle extras = new Bundle();
+ extras.putString(TEST_KEY, TEST_VALUE);
+ arguments.putBundle("extras", extras);
+ callMediaControllerMethod(
+ SEND_COMMAND, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnCommandCalled);
- assertNotNull(mCallback.mCommandCallback);
- assertEquals(TEST_COMMAND, mCallback.mCommand);
- assertBundleEquals(extras, mCallback.mExtras);
- }
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnCommandCalled);
+ assertNotNull(mCallback.mCommandCallback);
+ assertEquals(TEST_COMMAND, mCallback.mCommand);
+ assertBundleEquals(extras, mCallback.mExtras);
}
@Test
@SmallTest
public void testAddRemoveQueueItems() throws Exception {
- final String mediaId1 = "media_id_1";
- final String mediaTitle1 = "media_title_1";
+ mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS);
+
MediaDescriptionCompat itemDescription1 = new MediaDescriptionCompat.Builder()
- .setMediaId(mediaId1).setTitle(mediaTitle1).build();
+ .setMediaId(TEST_MEDIA_ID_1).setTitle(TEST_MEDIA_TITLE_1).build();
- final String mediaId2 = "media_id_2";
- final String mediaTitle2 = "media_title_2";
MediaDescriptionCompat itemDescription2 = new MediaDescriptionCompat.Builder()
- .setMediaId(mediaId2).setTitle(mediaTitle2).build();
+ .setMediaId(TEST_MEDIA_ID_2).setTitle(TEST_MEDIA_TITLE_2).build();
- synchronized (mWaitLock) {
- mCallback.reset();
- callMediaControllerMethod(
- ADD_QUEUE_ITEM, itemDescription1, getContext(), mSession.getSessionToken());
+ mCallback.reset(1);
+ callMediaControllerMethod(
+ ADD_QUEUE_ITEM, itemDescription1, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnAddQueueItemCalled);
- assertEquals(-1, mCallback.mQueueIndex);
- assertEquals(mediaId1, mCallback.mQueueDescription.getMediaId());
- assertEquals(mediaTitle1, mCallback.mQueueDescription.getTitle());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnAddQueueItemCalled);
+ assertEquals(-1, mCallback.mQueueIndex);
+ assertEquals(TEST_MEDIA_ID_1, mCallback.mQueueDescription.getMediaId());
+ assertEquals(TEST_MEDIA_TITLE_1, mCallback.mQueueDescription.getTitle());
- mCallback.reset();
- Bundle arguments = new Bundle();
- arguments.putParcelable("description", itemDescription2);
- arguments.putInt("index", 0);
- callMediaControllerMethod(
- ADD_QUEUE_ITEM_WITH_INDEX, arguments, getContext(), mSession.getSessionToken());
+ mCallback.reset(1);
+ Bundle arguments = new Bundle();
+ arguments.putParcelable("description", itemDescription2);
+ arguments.putInt("index", 0);
+ callMediaControllerMethod(
+ ADD_QUEUE_ITEM_WITH_INDEX, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnAddQueueItemAtCalled);
- assertEquals(0, mCallback.mQueueIndex);
- assertEquals(mediaId2, mCallback.mQueueDescription.getMediaId());
- assertEquals(mediaTitle2, mCallback.mQueueDescription.getTitle());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnAddQueueItemAtCalled);
+ assertEquals(0, mCallback.mQueueIndex);
+ assertEquals(TEST_MEDIA_ID_2, mCallback.mQueueDescription.getMediaId());
+ assertEquals(TEST_MEDIA_TITLE_2, mCallback.mQueueDescription.getTitle());
- mCallback.reset();
- callMediaControllerMethod(
- REMOVE_QUEUE_ITEM, itemDescription1, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnRemoveQueueItemCalled);
- assertEquals(mediaId1, mCallback.mQueueDescription.getMediaId());
- assertEquals(mediaTitle1, mCallback.mQueueDescription.getTitle());
- }
+ mCallback.reset(1);
+ callMediaControllerMethod(
+ REMOVE_QUEUE_ITEM, itemDescription1, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnRemoveQueueItemCalled);
+ assertEquals(TEST_MEDIA_ID_1, mCallback.mQueueDescription.getMediaId());
+ assertEquals(TEST_MEDIA_TITLE_1, mCallback.mQueueDescription.getTitle());
}
@Test
@SmallTest
public void testTransportControlsAndMediaSessionCallback() throws Exception {
+ mCallback.reset(1);
+ callTransportControlsMethod(PLAY, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertEquals(1, mCallback.mOnPlayCalledCount);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(PAUSE, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPauseCalled);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(STOP, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnStopCalled);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(
+ FAST_FORWARD, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnFastForwardCalled);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(REWIND, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnRewindCalled);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(
+ SKIP_TO_PREVIOUS, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSkipToPreviousCalled);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(
+ SKIP_TO_NEXT, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSkipToNextCalled);
+
+ mCallback.reset(1);
+ final long seekPosition = 1000;
+ callTransportControlsMethod(
+ SEEK_TO, seekPosition, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSeekToCalled);
+ assertEquals(seekPosition, mCallback.mSeekPosition);
+
+ mCallback.reset(1);
+ final RatingCompat rating =
+ RatingCompat.newStarRating(RatingCompat.RATING_5_STARS, 3f);
+ callTransportControlsMethod(
+ SET_RATING, rating, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSetRatingCalled);
+ assertEquals(rating.getRatingStyle(), mCallback.mRating.getRatingStyle());
+ assertEquals(rating.getStarRating(), mCallback.mRating.getStarRating(), DELTA);
+
+ mCallback.reset(1);
+ final Bundle extras = new Bundle();
+ extras.putString(TEST_KEY, TEST_VALUE);
+ Bundle arguments = new Bundle();
+ arguments.putString("mediaId", TEST_MEDIA_ID_1);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ PLAY_FROM_MEDIA_ID, arguments, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPlayFromMediaIdCalled);
+ assertEquals(TEST_MEDIA_ID_1, mCallback.mMediaId);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ final String query = "test-query";
+ arguments = new Bundle();
+ arguments.putString("query", query);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ PLAY_FROM_SEARCH, arguments, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPlayFromSearchCalled);
+ assertEquals(query, mCallback.mQuery);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ final Uri uri = Uri.parse("content://test/popcorn.mod");
+ arguments = new Bundle();
+ arguments.putParcelable("uri", uri);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ PLAY_FROM_URI, arguments, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPlayFromUriCalled);
+ assertEquals(uri, mCallback.mUri);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ final String action = "test-action";
+ arguments = new Bundle();
+ arguments.putString("action", action);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ SEND_CUSTOM_ACTION, arguments, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnCustomActionCalled);
+ assertEquals(action, mCallback.mAction);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ mCallback.mOnCustomActionCalled = false;
+ final PlaybackStateCompat.CustomAction customAction =
+ new PlaybackStateCompat.CustomAction.Builder(action, action, -1)
+ .setExtras(extras)
+ .build();
+ arguments = new Bundle();
+ arguments.putParcelable("action", customAction);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ SEND_CUSTOM_ACTION_PARCELABLE,
+ arguments,
+ getContext(),
+ mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnCustomActionCalled);
+ assertEquals(action, mCallback.mAction);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ final long queueItemId = 1000;
+ callTransportControlsMethod(
+ SKIP_TO_QUEUE_ITEM, queueItemId, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSkipToQueueItemCalled);
+ assertEquals(queueItemId, mCallback.mQueueItemId);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(
+ PREPARE, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPrepareCalled);
+
+ mCallback.reset(1);
+ arguments = new Bundle();
+ arguments.putString("mediaId", TEST_MEDIA_ID_2);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ PREPARE_FROM_MEDIA_ID, arguments, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPrepareFromMediaIdCalled);
+ assertEquals(TEST_MEDIA_ID_2, mCallback.mMediaId);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ arguments = new Bundle();
+ arguments.putString("query", query);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ PREPARE_FROM_SEARCH, arguments, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPrepareFromSearchCalled);
+ assertEquals(query, mCallback.mQuery);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ arguments = new Bundle();
+ arguments.putParcelable("uri", uri);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ PREPARE_FROM_URI, arguments, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPrepareFromUriCalled);
+ assertEquals(uri, mCallback.mUri);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(
+ SET_CAPTIONING_ENABLED, ENABLED, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSetCaptioningEnabledCalled);
+ assertEquals(ENABLED, mCallback.mCaptioningEnabled);
+
+ mCallback.reset(1);
+ final int repeatMode = PlaybackStateCompat.REPEAT_MODE_ALL;
+ callTransportControlsMethod(
+ SET_REPEAT_MODE, repeatMode, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSetRepeatModeCalled);
+ assertEquals(repeatMode, mCallback.mRepeatMode);
+
+ mCallback.reset(1);
+ final int shuffleMode = PlaybackStateCompat.SHUFFLE_MODE_ALL;
+ callTransportControlsMethod(
+ SET_SHUFFLE_MODE, shuffleMode, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSetShuffleModeCalled);
+ assertEquals(shuffleMode, mCallback.mShuffleMode);
+ }
+
+ /**
+ * Tests {@link MediaSessionCompat.Callback#onMediaButtonEvent}.
+ */
+ @Test
+ @MediumTest
+ public void testCallbackOnMediaButtonEvent() throws Exception {
+ mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS);
+ mSession.setActive(true);
+
+ final long waitTimeForNoResponse = 30L;
+
+ Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON)
+ .setComponent(new ComponentName(getContext(), getContext().getClass()));
+ PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, mediaButtonIntent, 0);
+ mSession.setMediaButtonReceiver(pi);
+
+ // Set state to STATE_PLAYING to get higher priority.
+ setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
+
+ mCallback.reset(1);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertEquals(1, mCallback.mOnPlayCalledCount);
+
+ mCallback.reset(1);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PAUSE);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertTrue(mCallback.mOnPauseCalled);
+
+ mCallback.reset(1);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_NEXT);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertTrue(mCallback.mOnSkipToNextCalled);
+
+ mCallback.reset(1);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertTrue(mCallback.mOnSkipToPreviousCalled);
+
+ mCallback.reset(1);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_STOP);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertTrue(mCallback.mOnStopCalled);
+
+ mCallback.reset(1);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertTrue(mCallback.mOnFastForwardCalled);
+
+ mCallback.reset(1);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_REWIND);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertTrue(mCallback.mOnRewindCalled);
+
+ // Test PLAY_PAUSE button twice.
+ // First, send PLAY_PAUSE button event while in STATE_PAUSED.
+ mCallback.reset(1);
+ setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertEquals(1, mCallback.mOnPlayCalledCount);
+
+ // Next, send PLAY_PAUSE button event while in STATE_PLAYING.
+ mCallback.reset(1);
+ setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertTrue(mCallback.mOnPauseCalled);
+
+ // Double tap of PLAY_PAUSE is the next track.
+ mCallback.reset(2);
+ setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ assertFalse(mCallback.await(waitTimeForNoResponse));
+ assertTrue(mCallback.mOnSkipToNextCalled);
+ assertEquals(0, mCallback.mOnPlayCalledCount);
+ assertFalse(mCallback.mOnPauseCalled);
+
+ // Test PLAY_PAUSE button long-press.
+ // It should be the same as the single short-press.
+ mCallback.reset(1);
+ setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, true);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertEquals(1, mCallback.mOnPlayCalledCount);
+
+ // Double tap of PLAY_PAUSE should be handled once.
+ // Initial down event from the second press within double tap time-out will make
+ // onSkipToNext() to be called, so further down events shouldn't be handled again.
+ mCallback.reset(2);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, true);
+ assertFalse(mCallback.await(waitTimeForNoResponse));
+ assertTrue(mCallback.mOnSkipToNextCalled);
+ assertEquals(0, mCallback.mOnPlayCalledCount);
+ assertFalse(mCallback.mOnPauseCalled);
+
+ // Test PLAY_PAUSE button long-press followed by the short-press.
+ // Initial long-press of the PLAY_PAUSE is considered as the single short-press already,
+ // so it shouldn't be used as the first tap of the double tap.
+ mCallback.reset(2);
+ setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, true);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ // onMediaButtonEvent() calls either onPlay() or onPause() depending on the playback state,
+ // so onPlay() should be called once and onPause() also should be called once.
+ assertEquals(1, mCallback.mOnPlayCalledCount);
+ assertTrue(mCallback.mOnPauseCalled);
+ assertFalse(mCallback.mOnSkipToNextCalled);
+
+ // If another media key is pressed while the double tap of PLAY_PAUSE,
+ // PLAY_PAUSE should be handled as normal.
+ mCallback.reset(3);
+ setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_STOP);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertFalse(mCallback.mOnSkipToNextCalled);
+ assertTrue(mCallback.mOnStopCalled);
+ assertEquals(2, mCallback.mOnPlayCalledCount);
+
+ // Test if media keys are handled in order.
+ mCallback.reset(2);
+ setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_STOP);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertEquals(1, mCallback.mOnPlayCalledCount);
+ assertTrue(mCallback.mOnStopCalled);
synchronized (mWaitLock) {
- mCallback.reset();
- callTransportControlsMethod(PLAY, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPlayCalled);
-
- mCallback.reset();
- callTransportControlsMethod(PAUSE, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPauseCalled);
-
- mCallback.reset();
- callTransportControlsMethod(STOP, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnStopCalled);
-
- mCallback.reset();
- callTransportControlsMethod(
- FAST_FORWARD, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnFastForwardCalled);
-
- mCallback.reset();
- callTransportControlsMethod(REWIND, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnRewindCalled);
-
- mCallback.reset();
- callTransportControlsMethod(
- SKIP_TO_PREVIOUS, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSkipToPreviousCalled);
-
- mCallback.reset();
- callTransportControlsMethod(
- SKIP_TO_NEXT, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSkipToNextCalled);
-
- mCallback.reset();
- final long seekPosition = 1000;
- callTransportControlsMethod(
- SEEK_TO, seekPosition, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSeekToCalled);
- assertEquals(seekPosition, mCallback.mSeekPosition);
-
- mCallback.reset();
- final RatingCompat rating =
- RatingCompat.newStarRating(RatingCompat.RATING_5_STARS, 3f);
- callTransportControlsMethod(
- SET_RATING, rating, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetRatingCalled);
- assertEquals(rating.getRatingStyle(), mCallback.mRating.getRatingStyle());
- assertEquals(rating.getStarRating(), mCallback.mRating.getStarRating(), DELTA);
-
- mCallback.reset();
- final String mediaId = "test-media-id";
- final Bundle extras = new Bundle();
- extras.putString(TEST_KEY, TEST_VALUE);
- Bundle arguments = new Bundle();
- arguments.putString("mediaId", mediaId);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- PLAY_FROM_MEDIA_ID, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPlayFromMediaIdCalled);
- assertEquals(mediaId, mCallback.mMediaId);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- final String query = "test-query";
- arguments = new Bundle();
- arguments.putString("query", query);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- PLAY_FROM_SEARCH, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPlayFromSearchCalled);
- assertEquals(query, mCallback.mQuery);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- final Uri uri = Uri.parse("content://test/popcorn.mod");
- arguments = new Bundle();
- arguments.putParcelable("uri", uri);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- PLAY_FROM_URI, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPlayFromUriCalled);
- assertEquals(uri, mCallback.mUri);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- final String action = "test-action";
- arguments = new Bundle();
- arguments.putString("action", action);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- SEND_CUSTOM_ACTION, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnCustomActionCalled);
- assertEquals(action, mCallback.mAction);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- mCallback.mOnCustomActionCalled = false;
- final PlaybackStateCompat.CustomAction customAction =
- new PlaybackStateCompat.CustomAction.Builder(action, action, -1)
- .setExtras(extras)
- .build();
- arguments = new Bundle();
- arguments.putParcelable("action", customAction);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- SEND_CUSTOM_ACTION_PARCELABLE,
- arguments,
- getContext(),
- mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnCustomActionCalled);
- assertEquals(action, mCallback.mAction);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- final long queueItemId = 1000;
- callTransportControlsMethod(
- SKIP_TO_QUEUE_ITEM, queueItemId, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSkipToQueueItemCalled);
- assertEquals(queueItemId, mCallback.mQueueItemId);
-
- mCallback.reset();
- callTransportControlsMethod(
- PREPARE, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPrepareCalled);
-
- mCallback.reset();
- arguments = new Bundle();
- arguments.putString("mediaId", mediaId);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- PREPARE_FROM_MEDIA_ID, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPrepareFromMediaIdCalled);
- assertEquals(mediaId, mCallback.mMediaId);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- arguments = new Bundle();
- arguments.putString("query", query);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- PREPARE_FROM_SEARCH, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPrepareFromSearchCalled);
- assertEquals(query, mCallback.mQuery);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- arguments = new Bundle();
- arguments.putParcelable("uri", uri);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- PREPARE_FROM_URI, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPrepareFromUriCalled);
- assertEquals(uri, mCallback.mUri);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- callTransportControlsMethod(
- SET_CAPTIONING_ENABLED, ENABLED, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetCaptioningEnabledCalled);
- assertEquals(ENABLED, mCallback.mCaptioningEnabled);
-
- mCallback.reset();
- final int repeatMode = PlaybackStateCompat.REPEAT_MODE_ALL;
- callTransportControlsMethod(
- SET_REPEAT_MODE, repeatMode, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetRepeatModeCalled);
- assertEquals(repeatMode, mCallback.mRepeatMode);
-
- mCallback.reset();
- final int shuffleMode = PlaybackStateCompat.SHUFFLE_MODE_ALL;
- callTransportControlsMethod(
- SET_SHUFFLE_MODE, shuffleMode, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetShuffleModeCalled);
- assertEquals(shuffleMode, mCallback.mShuffleMode);
+ assertEquals(PlaybackStateCompat.STATE_STOPPED,
+ mSession.getController().getPlaybackState().getState());
}
}
+ @Test
+ @SmallTest
+ public void testVolumeControl() throws Exception {
+ if (android.os.Build.VERSION.SDK_INT < 27) {
+ // This test causes an Exception on System UI in API < 27.
+ return;
+ }
+ VolumeProviderCompat vp =
+ new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE, 11, 5) {
+ @Override
+ public void onSetVolumeTo(int volume) {
+ synchronized (mWaitLock) {
+ setCurrentVolume(volume);
+ mWaitLock.notify();
+ }
+ }
+
+ @Override
+ public void onAdjustVolume(int direction) {
+ synchronized (mWaitLock) {
+ switch (direction) {
+ case AudioManager.ADJUST_LOWER:
+ setCurrentVolume(getCurrentVolume() - 1);
+ break;
+ case AudioManager.ADJUST_RAISE:
+ setCurrentVolume(getCurrentVolume() + 1);
+ break;
+ }
+ mWaitLock.notify();
+ }
+ }
+ };
+ mSession.setPlaybackToRemote(vp);
+
+ synchronized (mWaitLock) {
+ // test setVolumeTo
+ callMediaControllerMethod(SET_VOLUME_TO,
+ 7 /* Target volume */, getContext(), mSession.getSessionToken());
+ mWaitLock.wait(TIME_OUT_MS);
+ assertEquals(7, vp.getCurrentVolume());
+
+ // test adjustVolume
+ callMediaControllerMethod(ADJUST_VOLUME,
+ AudioManager.ADJUST_LOWER, getContext(), mSession.getSessionToken());
+ mWaitLock.wait(TIME_OUT_MS);
+ assertEquals(6, vp.getCurrentVolume());
+
+ callMediaControllerMethod(ADJUST_VOLUME,
+ AudioManager.ADJUST_RAISE, getContext(), mSession.getSessionToken());
+ mWaitLock.wait(TIME_OUT_MS);
+ assertEquals(7, vp.getCurrentVolume());
+ }
+ }
+
+ private void setPlaybackState(int state) {
+ final long allActions = PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE
+ | PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_STOP
+ | PlaybackStateCompat.ACTION_SKIP_TO_NEXT
+ | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
+ | PlaybackStateCompat.ACTION_FAST_FORWARD | PlaybackStateCompat.ACTION_REWIND;
+ PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder().setActions(allActions)
+ .setState(state, 0L, 0.0f).build();
+ synchronized (mWaitLock) {
+ mSession.setPlaybackState(playbackState);
+ }
+ }
+
+ private void sendMediaKeyInputToController(int keyCode) {
+ sendMediaKeyInputToController(keyCode, false);
+ }
+
+ private void sendMediaKeyInputToController(int keyCode, boolean isLongPress) {
+ MediaControllerCompat controller = mSession.getController();
+ long currentTimeMs = System.currentTimeMillis();
+ KeyEvent down = new KeyEvent(
+ currentTimeMs, currentTimeMs, KeyEvent.ACTION_DOWN, keyCode, 0);
+ controller.dispatchMediaButtonEvent(down);
+ if (isLongPress) {
+ KeyEvent longPress = new KeyEvent(
+ currentTimeMs, System.currentTimeMillis(), KeyEvent.ACTION_DOWN, keyCode, 1);
+ controller.dispatchMediaButtonEvent(longPress);
+ }
+ KeyEvent up = new KeyEvent(
+ currentTimeMs, System.currentTimeMillis(), KeyEvent.ACTION_UP, keyCode, 0);
+ controller.dispatchMediaButtonEvent(up);
+ }
+
private class MediaSessionCallback extends MediaSessionCompat.Callback {
+ private CountDownLatch mLatch;
private long mSeekPosition;
private long mQueueItemId;
private RatingCompat mRating;
@@ -409,7 +825,7 @@
private MediaDescriptionCompat mQueueDescription;
private List<MediaSessionCompat.QueueItem> mQueue = new ArrayList<>();
- private boolean mOnPlayCalled;
+ private int mOnPlayCalledCount;
private boolean mOnPauseCalled;
private boolean mOnStopCalled;
private boolean mOnFastForwardCalled;
@@ -435,7 +851,8 @@
private boolean mOnAddQueueItemAtCalled;
private boolean mOnRemoveQueueItemCalled;
- public void reset() {
+ public void reset(int count) {
+ mLatch = new CountDownLatch(count);
mSeekPosition = -1;
mQueueItemId = -1;
mRating = null;
@@ -452,7 +869,7 @@
mQueueIndex = -1;
mQueueDescription = null;
- mOnPlayCalled = false;
+ mOnPlayCalledCount = 0;
mOnPauseCalled = false;
mOnStopCalled = false;
mOnFastForwardCalled = false;
@@ -479,242 +896,203 @@
mOnRemoveQueueItemCalled = false;
}
+ public boolean await(long timeoutMs) {
+ try {
+ return mLatch.await(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+
@Override
public void onPlay() {
- synchronized (mWaitLock) {
- mOnPlayCalled = true;
- mWaitLock.notify();
- }
+ mOnPlayCalledCount++;
+ setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
+ mLatch.countDown();
}
@Override
public void onPause() {
- synchronized (mWaitLock) {
- mOnPauseCalled = true;
- mWaitLock.notify();
- }
+ mOnPauseCalled = true;
+ setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
+ mLatch.countDown();
}
@Override
public void onStop() {
- synchronized (mWaitLock) {
- mOnStopCalled = true;
- mWaitLock.notify();
- }
+ mOnStopCalled = true;
+ setPlaybackState(PlaybackStateCompat.STATE_STOPPED);
+ mLatch.countDown();
}
@Override
public void onFastForward() {
- synchronized (mWaitLock) {
- mOnFastForwardCalled = true;
- mWaitLock.notify();
- }
+ mOnFastForwardCalled = true;
+ mLatch.countDown();
}
@Override
public void onRewind() {
- synchronized (mWaitLock) {
- mOnRewindCalled = true;
- mWaitLock.notify();
- }
+ mOnRewindCalled = true;
+ mLatch.countDown();
}
@Override
public void onSkipToPrevious() {
- synchronized (mWaitLock) {
- mOnSkipToPreviousCalled = true;
- mWaitLock.notify();
- }
+ mOnSkipToPreviousCalled = true;
+ mLatch.countDown();
}
@Override
public void onSkipToNext() {
- synchronized (mWaitLock) {
- mOnSkipToNextCalled = true;
- mWaitLock.notify();
- }
+ mOnSkipToNextCalled = true;
+ mLatch.countDown();
}
@Override
public void onSeekTo(long pos) {
- synchronized (mWaitLock) {
- mOnSeekToCalled = true;
- mSeekPosition = pos;
- mWaitLock.notify();
- }
+ mOnSeekToCalled = true;
+ mSeekPosition = pos;
+ mLatch.countDown();
}
@Override
public void onSetRating(RatingCompat rating) {
- synchronized (mWaitLock) {
- mOnSetRatingCalled = true;
- mRating = rating;
- mWaitLock.notify();
- }
+ mOnSetRatingCalled = true;
+ mRating = rating;
+ mLatch.countDown();
}
@Override
public void onPlayFromMediaId(String mediaId, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPlayFromMediaIdCalled = true;
- mMediaId = mediaId;
- mExtras = extras;
- mWaitLock.notify();
- }
+ mOnPlayFromMediaIdCalled = true;
+ mMediaId = mediaId;
+ mExtras = extras;
+ mLatch.countDown();
}
@Override
public void onPlayFromSearch(String query, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPlayFromSearchCalled = true;
- mQuery = query;
- mExtras = extras;
- mWaitLock.notify();
- }
+ mOnPlayFromSearchCalled = true;
+ mQuery = query;
+ mExtras = extras;
+ mLatch.countDown();
}
@Override
public void onPlayFromUri(Uri uri, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPlayFromUriCalled = true;
- mUri = uri;
- mExtras = extras;
- mWaitLock.notify();
- }
+ mOnPlayFromUriCalled = true;
+ mUri = uri;
+ mExtras = extras;
+ mLatch.countDown();
}
@Override
public void onCustomAction(String action, Bundle extras) {
- synchronized (mWaitLock) {
- mOnCustomActionCalled = true;
- mAction = action;
- mExtras = extras;
- mWaitLock.notify();
- }
+ mOnCustomActionCalled = true;
+ mAction = action;
+ mExtras = extras;
+ mLatch.countDown();
}
@Override
public void onSkipToQueueItem(long id) {
- synchronized (mWaitLock) {
- mOnSkipToQueueItemCalled = true;
- mQueueItemId = id;
- mWaitLock.notify();
- }
+ mOnSkipToQueueItemCalled = true;
+ mQueueItemId = id;
+ mLatch.countDown();
}
@Override
public void onCommand(String command, Bundle extras, ResultReceiver cb) {
- synchronized (mWaitLock) {
- mOnCommandCalled = true;
- mCommand = command;
- mExtras = extras;
- mCommandCallback = cb;
- mWaitLock.notify();
- }
+ mOnCommandCalled = true;
+ mCommand = command;
+ mExtras = extras;
+ mCommandCallback = cb;
+ mLatch.countDown();
}
@Override
public void onPrepare() {
- synchronized (mWaitLock) {
- mOnPrepareCalled = true;
- mWaitLock.notify();
- }
+ mOnPrepareCalled = true;
+ mLatch.countDown();
}
@Override
public void onPrepareFromMediaId(String mediaId, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPrepareFromMediaIdCalled = true;
- mMediaId = mediaId;
- mExtras = extras;
- mWaitLock.notify();
- }
+ mOnPrepareFromMediaIdCalled = true;
+ mMediaId = mediaId;
+ mExtras = extras;
+ mLatch.countDown();
}
@Override
public void onPrepareFromSearch(String query, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPrepareFromSearchCalled = true;
- mQuery = query;
- mExtras = extras;
- mWaitLock.notify();
- }
+ mOnPrepareFromSearchCalled = true;
+ mQuery = query;
+ mExtras = extras;
+ mLatch.countDown();
}
@Override
public void onPrepareFromUri(Uri uri, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPrepareFromUriCalled = true;
- mUri = uri;
- mExtras = extras;
- mWaitLock.notify();
- }
+ mOnPrepareFromUriCalled = true;
+ mUri = uri;
+ mExtras = extras;
+ mLatch.countDown();
}
@Override
public void onSetRepeatMode(int repeatMode) {
- synchronized (mWaitLock) {
- mOnSetRepeatModeCalled = true;
- mRepeatMode = repeatMode;
- mWaitLock.notify();
- }
+ mOnSetRepeatModeCalled = true;
+ mRepeatMode = repeatMode;
+ mLatch.countDown();
}
@Override
public void onAddQueueItem(MediaDescriptionCompat description) {
- synchronized (mWaitLock) {
- mOnAddQueueItemCalled = true;
- mQueueDescription = description;
- mQueue.add(new MediaSessionCompat.QueueItem(description, mQueue.size()));
- mSession.setQueue(mQueue);
- mWaitLock.notify();
- }
+ mOnAddQueueItemCalled = true;
+ mQueueDescription = description;
+ mQueue.add(new MediaSessionCompat.QueueItem(description, mQueue.size()));
+ mSession.setQueue(mQueue);
+ mLatch.countDown();
}
@Override
public void onAddQueueItem(MediaDescriptionCompat description, int index) {
- synchronized (mWaitLock) {
- mOnAddQueueItemAtCalled = true;
- mQueueIndex = index;
- mQueueDescription = description;
- mQueue.add(index, new MediaSessionCompat.QueueItem(description, mQueue.size()));
- mSession.setQueue(mQueue);
- mWaitLock.notify();
- }
+ mOnAddQueueItemAtCalled = true;
+ mQueueIndex = index;
+ mQueueDescription = description;
+ mQueue.add(index, new MediaSessionCompat.QueueItem(description, mQueue.size()));
+ mSession.setQueue(mQueue);
+ mLatch.countDown();
}
@Override
public void onRemoveQueueItem(MediaDescriptionCompat description) {
- synchronized (mWaitLock) {
- mOnRemoveQueueItemCalled = true;
- String mediaId = description.getMediaId();
- for (int i = mQueue.size() - 1; i >= 0; --i) {
- if (mediaId.equals(mQueue.get(i).getDescription().getMediaId())) {
- mQueueDescription = mQueue.remove(i).getDescription();
- mSession.setQueue(mQueue);
- break;
- }
+ mOnRemoveQueueItemCalled = true;
+ String mediaId = description.getMediaId();
+ for (int i = mQueue.size() - 1; i >= 0; --i) {
+ if (mediaId.equals(mQueue.get(i).getDescription().getMediaId())) {
+ mQueueDescription = mQueue.remove(i).getDescription();
+ mSession.setQueue(mQueue);
+ break;
}
- mWaitLock.notify();
}
+ mLatch.countDown();
}
@Override
public void onSetCaptioningEnabled(boolean enabled) {
- synchronized (mWaitLock) {
- mOnSetCaptioningEnabledCalled = true;
- mCaptioningEnabled = enabled;
- mWaitLock.notify();
- }
+ mOnSetCaptioningEnabledCalled = true;
+ mCaptioningEnabled = enabled;
+ mLatch.countDown();
}
@Override
public void onSetShuffleMode(int shuffleMode) {
- synchronized (mWaitLock) {
- mOnSetShuffleModeCalled = true;
- mShuffleMode = shuffleMode;
- mWaitLock.notify();
- }
+ mOnSetShuffleModeCalled = true;
+ mShuffleMode = shuffleMode;
+ mLatch.countDown();
}
}
}
diff --git a/media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java b/media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java
index 61c33f8..7032a0b 100644
--- a/media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java
+++ b/media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java
@@ -22,16 +22,20 @@
import static android.support.mediacompat.testlib.MediaBrowserConstants.EXTRAS_VALUE;
import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_CHILDREN;
import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_CHILDREN_DELAYED;
+import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_INCLUDE_METADATA;
import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_INVALID;
import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_ROOT;
+import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_METADATA;
import static android.support.mediacompat.testlib.MediaBrowserConstants.SEARCH_QUERY;
import static android.support.mediacompat.testlib.MediaBrowserConstants.SEARCH_QUERY_FOR_ERROR;
import static android.support.mediacompat.testlib.MediaBrowserConstants.SEARCH_QUERY_FOR_NO_RESULT;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.v4.media.MediaBrowserCompat.MediaItem;
import android.support.v4.media.MediaBrowserServiceCompat;
import android.support.v4.media.MediaDescriptionCompat;
+import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import junit.framework.Assert;
@@ -79,25 +83,43 @@
}
@Override
- public void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result) {
+ public void onLoadChildren(final String parentId, final Result<List<MediaItem>> result) {
List<MediaItem> mediaItems = new ArrayList<>();
- if (MEDIA_ID_ROOT.equals(parentMediaId)) {
+ if (MEDIA_ID_ROOT.equals(parentId)) {
Bundle rootHints = getBrowserRootHints();
for (String id : MEDIA_ID_CHILDREN) {
mediaItems.add(createMediaItem(id));
}
result.sendResult(mediaItems);
- } else if (MEDIA_ID_CHILDREN_DELAYED.equals(parentMediaId)) {
+ } else if (MEDIA_ID_CHILDREN_DELAYED.equals(parentId)) {
Assert.assertNull(mPendingLoadChildrenResult);
mPendingLoadChildrenResult = result;
mPendingRootHints = getBrowserRootHints();
result.detach();
- } else if (MEDIA_ID_INVALID.equals(parentMediaId)) {
+ } else if (MEDIA_ID_INVALID.equals(parentId)) {
result.sendResult(null);
}
}
@Override
+ public void onLoadChildren(@NonNull String parentId, @NonNull Result<List<MediaItem>> result,
+ @NonNull Bundle options) {
+ if (MEDIA_ID_INCLUDE_METADATA.equals(parentId)) {
+ // Test unparcelling the Bundle.
+ MediaMetadataCompat metadata = options.getParcelable(MEDIA_METADATA);
+ if (metadata == null) {
+ super.onLoadChildren(parentId, result, options);
+ } else {
+ List<MediaItem> mediaItems = new ArrayList<>();
+ mediaItems.add(new MediaItem(metadata.getDescription(), MediaItem.FLAG_PLAYABLE));
+ result.sendResult(mediaItems);
+ }
+ } else {
+ super.onLoadChildren(parentId, result, options);
+ }
+ }
+
+ @Override
public void onLoadItem(String itemId, Result<MediaItem> result) {
if (MEDIA_ID_CHILDREN_DELAYED.equals(itemId)) {
mPendingLoadItemResult = result;
diff --git a/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/MediaBrowserConstants.java b/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/MediaBrowserConstants.java
index 86024d9..f961308 100644
--- a/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/MediaBrowserConstants.java
+++ b/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/MediaBrowserConstants.java
@@ -31,14 +31,16 @@
public static final int SET_SESSION_TOKEN = 7;
public static final String MEDIA_ID_ROOT = "test_media_id_root";
-
- public static final String EXTRAS_KEY = "test_extras_key";
- public static final String EXTRAS_VALUE = "test_extras_value";
-
public static final String MEDIA_ID_INVALID = "test_media_id_invalid";
public static final String MEDIA_ID_CHILDREN_DELAYED = "test_media_id_children_delayed";
public static final String MEDIA_ID_ON_LOAD_ITEM_NOT_IMPLEMENTED =
"test_media_id_on_load_item_not_implemented";
+ public static final String MEDIA_ID_INCLUDE_METADATA = "test_media_id_include_metadata";
+
+ public static final String EXTRAS_KEY = "test_extras_key";
+ public static final String EXTRAS_VALUE = "test_extras_value";
+
+ public static final String MEDIA_METADATA = "test_media_metadata";
public static final String SEARCH_QUERY = "children_2";
public static final String SEARCH_QUERY_FOR_NO_RESULT = "query no result";
diff --git a/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/MediaControllerConstants.java b/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/MediaControllerConstants.java
index 5fa086b..4978888 100644
--- a/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/MediaControllerConstants.java
+++ b/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/MediaControllerConstants.java
@@ -26,6 +26,8 @@
public static final int ADD_QUEUE_ITEM = 202;
public static final int ADD_QUEUE_ITEM_WITH_INDEX = 203;
public static final int REMOVE_QUEUE_ITEM = 204;
+ public static final int SET_VOLUME_TO = 205;
+ public static final int ADJUST_VOLUME = 206;
// TransportControls methods.
public static final int PLAY = 301;
diff --git a/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/MediaSessionConstants.java b/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/MediaSessionConstants.java
index cbdccc1..c0a64d4 100644
--- a/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/MediaSessionConstants.java
+++ b/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/MediaSessionConstants.java
@@ -51,6 +51,8 @@
public static final long TEST_QUEUE_ID_2 = 20L;
public static final String TEST_MEDIA_ID_1 = "media_id_1";
public static final String TEST_MEDIA_ID_2 = "media_id_2";
+ public static final String TEST_MEDIA_TITLE_1 = "media_title_1";
+ public static final String TEST_MEDIA_TITLE_2 = "media_title_2";
public static final long TEST_ACTION = 55L;
public static final int TEST_ERROR_CODE = 0x3;
diff --git a/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/VersionConstants.java b/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/VersionConstants.java
index 6533ee1..4b217b1 100644
--- a/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/VersionConstants.java
+++ b/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/VersionConstants.java
@@ -22,4 +22,7 @@
public class VersionConstants {
public static final String KEY_CLIENT_VERSION = "client_version";
public static final String KEY_SERVICE_VERSION = "service_version";
+
+ public static final String VERSION_TOT = "tot";
+ public static final String VERSION_PREVIOUS = "previous";
}
diff --git a/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/util/IntentUtil.java b/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/util/IntentUtil.java
index bbf9752..8d58a6f 100644
--- a/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/util/IntentUtil.java
+++ b/media-compat/version-compat-tests/lib/src/main/java/android/support/mediacompat/testlib/util/IntentUtil.java
@@ -30,12 +30,13 @@
*/
public class IntentUtil {
+ public static final String SERVICE_PACKAGE_NAME = "android.support.mediacompat.service.test";
+ public static final String CLIENT_PACKAGE_NAME = "android.support.mediacompat.client.test";
+
public static final ComponentName SERVICE_RECEIVER_COMPONENT_NAME = new ComponentName(
- "android.support.mediacompat.service.test",
- "android.support.mediacompat.service.ServiceBroadcastReceiver");
+ SERVICE_PACKAGE_NAME, "android.support.mediacompat.service.ServiceBroadcastReceiver");
public static final ComponentName CLIENT_RECEIVER_COMPONENT_NAME = new ComponentName(
- "android.support.mediacompat.client.test",
- "android.support.mediacompat.client.ClientBroadcastReceiver");
+ CLIENT_PACKAGE_NAME, "android.support.mediacompat.client.ClientBroadcastReceiver");
public static final String ACTION_CALL_MEDIA_BROWSER_SERVICE_METHOD =
"android.support.mediacompat.service.action.CALL_MEDIA_BROWSER_SERVICE_METHOD";
diff --git a/media-compat/version-compat-tests/previous/client/build.gradle b/media-compat/version-compat-tests/previous/client/build.gradle
index 01b3847..2788a1a 100644
--- a/media-compat/version-compat-tests/previous/client/build.gradle
+++ b/media-compat/version-compat-tests/previous/client/build.gradle
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
+
plugins {
id("SupportAndroidLibraryPlugin")
}
@@ -22,7 +24,7 @@
androidTestImplementation project(':support-media-compat-test-lib')
androidTestImplementation "com.android.support:support-media-compat:27.0.1"
- androidTestImplementation(libs.test_runner)
+ androidTestImplementation(TEST_RUNNER)
}
android {
diff --git a/media-compat/tests/src/android/support/v4/media/AudioAttributesCompatTest.java b/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/AudioAttributesCompatTest.java
similarity index 97%
copy from media-compat/tests/src/android/support/v4/media/AudioAttributesCompatTest.java
copy to media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/AudioAttributesCompatTest.java
index d66c7fc..675c0fc 100644
--- a/media-compat/tests/src/android/support/v4/media/AudioAttributesCompatTest.java
+++ b/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/AudioAttributesCompatTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.support.v4.media;
+package android.support.mediacompat.client;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.core.IsNot.not;
@@ -25,6 +25,7 @@
import android.support.test.filters.SdkSuppress;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.media.AudioAttributesCompat;
import org.junit.After;
import org.junit.Before;
diff --git a/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/ClientBroadcastReceiver.java b/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/ClientBroadcastReceiver.java
index 3166e55..3227482 100644
--- a/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/ClientBroadcastReceiver.java
+++ b/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/ClientBroadcastReceiver.java
@@ -19,6 +19,7 @@
import static android.support.mediacompat.testlib.MediaControllerConstants.ADD_QUEUE_ITEM;
import static android.support.mediacompat.testlib.MediaControllerConstants
.ADD_QUEUE_ITEM_WITH_INDEX;
+import static android.support.mediacompat.testlib.MediaControllerConstants.ADJUST_VOLUME;
import static android.support.mediacompat.testlib.MediaControllerConstants.FAST_FORWARD;
import static android.support.mediacompat.testlib.MediaControllerConstants.PAUSE;
import static android.support.mediacompat.testlib.MediaControllerConstants.PLAY;
@@ -40,6 +41,7 @@
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_RATING;
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_REPEAT_MODE;
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_SHUFFLE_MODE;
+import static android.support.mediacompat.testlib.MediaControllerConstants.SET_VOLUME_TO;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_NEXT;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_PREVIOUS;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_QUEUE_ITEM;
@@ -105,6 +107,12 @@
controller.removeQueueItem(
(MediaDescriptionCompat) extras.getParcelable(KEY_ARGUMENT));
break;
+ case SET_VOLUME_TO:
+ controller.setVolumeTo(extras.getInt(KEY_ARGUMENT), 0);
+ break;
+ case ADJUST_VOLUME:
+ controller.adjustVolume(extras.getInt(KEY_ARGUMENT), 0);
+ break;
}
} else if (ACTION_CALL_TRANSPORT_CONTROLS_METHOD.equals(intent.getAction())
&& extras != null) {
diff --git a/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaBrowserCompatTest.java b/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaBrowserCompatTest.java
index 31bdb7a..a2e77ff 100644
--- a/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaBrowserCompatTest.java
+++ b/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaBrowserCompatTest.java
@@ -47,6 +47,7 @@
import static android.support.mediacompat.testlib.MediaBrowserConstants.TEST_VALUE_3;
import static android.support.mediacompat.testlib.MediaBrowserConstants.TEST_VALUE_4;
import static android.support.mediacompat.testlib.VersionConstants.KEY_SERVICE_VERSION;
+import static android.support.mediacompat.testlib.util.IntentUtil.SERVICE_PACKAGE_NAME;
import static android.support.mediacompat.testlib.util.IntentUtil.callMediaBrowserServiceMethod;
import static android.support.test.InstrumentationRegistry.getArguments;
import static android.support.test.InstrumentationRegistry.getContext;
@@ -80,6 +81,8 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Test {@link android.support.v4.media.MediaBrowserCompat}.
@@ -105,13 +108,15 @@
*/
private static final long SLEEP_MS = 100L;
private static final ComponentName TEST_BROWSER_SERVICE = new ComponentName(
- "android.support.mediacompat.service.test",
+ SERVICE_PACKAGE_NAME,
"android.support.mediacompat.service.StubMediaBrowserServiceCompat");
private static final ComponentName TEST_BROWSER_SERVICE_DELAYED_MEDIA_SESSION =
new ComponentName(
- "android.support.mediacompat.service.test",
+ SERVICE_PACKAGE_NAME,
"android.support.mediacompat.service"
+ ".StubMediaBrowserServiceCompatWithDelayedMediaSession");
+ private static final ComponentName TEST_INVALID_BROWSER_SERVICE = new ComponentName(
+ "invalid.package", "invalid.ServiceClassName");
private String mServiceVersion;
private MediaBrowserCompat mMediaBrowser;
@@ -157,6 +162,21 @@
@Test
@SmallTest
+ public void testBrowserRoot() {
+ final String id = "test-id";
+ final String key = "test-key";
+ final String val = "test-val";
+ final Bundle extras = new Bundle();
+ extras.putString(key, val);
+
+ MediaBrowserServiceCompat.BrowserRoot browserRoot =
+ new MediaBrowserServiceCompat.BrowserRoot(id, extras);
+ assertEquals(id, browserRoot.getRootId());
+ assertEquals(val, browserRoot.getExtras().getString(key));
+ }
+
+ @Test
+ @SmallTest
public void testMediaBrowser() throws Exception {
assertFalse(mMediaBrowser.isConnected());
@@ -178,6 +198,37 @@
@Test
@SmallTest
+ public void testGetServiceComponentBeforeConnection() {
+ try {
+ ComponentName serviceComponent = mMediaBrowser.getServiceComponent();
+ fail();
+ } catch (IllegalStateException e) {
+ // expected
+ }
+ }
+
+ @Test
+ @SmallTest
+ public void testConnectionFailed() throws Exception {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mMediaBrowser = new MediaBrowserCompat(getInstrumentation().getTargetContext(),
+ TEST_INVALID_BROWSER_SERVICE, mConnectionCallback, mRootHints);
+ }
+ });
+
+ synchronized (mConnectionCallback.mWaitLock) {
+ mMediaBrowser.connect();
+ mConnectionCallback.mWaitLock.wait(TIME_OUT_MS);
+ }
+ assertEquals(1, mConnectionCallback.mConnectionFailedCount);
+ assertEquals(0, mConnectionCallback.mConnectedCount);
+ assertEquals(0, mConnectionCallback.mConnectionSuspendedCount);
+ }
+
+ @Test
+ @SmallTest
public void testConnectTwice() throws Exception {
connectMediaBrowserService();
try {
@@ -206,18 +257,16 @@
assertEquals(1, mConnectionCallback.mConnectedCount);
}
- synchronized (mSubscriptionCallback.mWaitLock) {
- // Test subscribe.
- resetCallbacks();
- mMediaBrowser.subscribe(MEDIA_ID_ROOT, mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedCount > 0);
- assertEquals(MEDIA_ID_ROOT, mSubscriptionCallback.mLastParentId);
- }
+ // Test subscribe.
+ mSubscriptionCallback.reset(1);
+ mMediaBrowser.subscribe(MEDIA_ID_ROOT, mSubscriptionCallback);
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(1, mSubscriptionCallback.mChildrenLoadedCount);
+ assertEquals(MEDIA_ID_ROOT, mSubscriptionCallback.mLastParentId);
synchronized (mItemCallback.mWaitLock) {
// Test getItem.
- resetCallbacks();
+ mItemCallback.reset();
mMediaBrowser.getItem(MEDIA_ID_CHILDREN[0], mItemCallback);
mItemCallback.mWaitLock.wait(TIME_OUT_MS);
assertEquals(MEDIA_ID_CHILDREN[0], mItemCallback.mLastMediaItem.getMediaId());
@@ -225,12 +274,11 @@
// Reconnect after connection was established.
mMediaBrowser.disconnect();
- resetCallbacks();
connectMediaBrowserService();
synchronized (mItemCallback.mWaitLock) {
// Test getItem.
- resetCallbacks();
+ mItemCallback.reset();
mMediaBrowser.getItem(MEDIA_ID_CHILDREN[0], mItemCallback);
mItemCallback.mWaitLock.wait(TIME_OUT_MS);
assertEquals(MEDIA_ID_CHILDREN[0], mItemCallback.mLastMediaItem.getMediaId());
@@ -245,7 +293,7 @@
public void run() {
mMediaBrowser.connect();
mMediaBrowser.disconnect();
- resetCallbacks();
+ mConnectionCallback.reset();
}
});
@@ -259,48 +307,43 @@
assertEquals(0, mConnectionCallback.mConnectionSuspendedCount);
}
-// @Test
-// @MediumTest
+ @Test
+ @MediumTest
public void testSubscribe() throws Exception {
connectMediaBrowserService();
- synchronized (mSubscriptionCallback.mWaitLock) {
- mMediaBrowser.subscribe(MEDIA_ID_ROOT, mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedCount > 0);
- assertEquals(MEDIA_ID_ROOT, mSubscriptionCallback.mLastParentId);
- assertEquals(MEDIA_ID_CHILDREN.length,
- mSubscriptionCallback.mLastChildMediaItems.size());
- for (int i = 0; i < MEDIA_ID_CHILDREN.length; ++i) {
- assertEquals(MEDIA_ID_CHILDREN[i],
- mSubscriptionCallback.mLastChildMediaItems.get(i).getMediaId());
- }
-
- // Test MediaBrowserServiceCompat.notifyChildrenChanged()
- mSubscriptionCallback.reset();
- callMediaBrowserServiceMethod(NOTIFY_CHILDREN_CHANGED, MEDIA_ID_ROOT, getContext());
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedCount > 0);
+ mSubscriptionCallback.reset(1);
+ mMediaBrowser.subscribe(MEDIA_ID_ROOT, mSubscriptionCallback);
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(1, mSubscriptionCallback.mChildrenLoadedCount);
+ assertEquals(MEDIA_ID_ROOT, mSubscriptionCallback.mLastParentId);
+ assertEquals(MEDIA_ID_CHILDREN.length, mSubscriptionCallback.mLastChildMediaItems.size());
+ for (int i = 0; i < MEDIA_ID_CHILDREN.length; ++i) {
+ assertEquals(MEDIA_ID_CHILDREN[i],
+ mSubscriptionCallback.mLastChildMediaItems.get(i).getMediaId());
}
+ // Test MediaBrowserServiceCompat.notifyChildrenChanged()
+ mSubscriptionCallback.reset(1);
+ callMediaBrowserServiceMethod(NOTIFY_CHILDREN_CHANGED, MEDIA_ID_ROOT, getContext());
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(1, mSubscriptionCallback.mChildrenLoadedCount);
+
// Test unsubscribe.
- resetCallbacks();
+ mSubscriptionCallback.reset(1);
mMediaBrowser.unsubscribe(MEDIA_ID_ROOT);
// After unsubscribing, make StubMediaBrowserServiceCompat notify that the children are
// changed.
callMediaBrowserServiceMethod(NOTIFY_CHILDREN_CHANGED, MEDIA_ID_ROOT, getContext());
- try {
- Thread.sleep(SLEEP_MS);
- } catch (InterruptedException e) {
- fail("Unexpected InterruptedException occurred.");
- }
+ mSubscriptionCallback.await(WAIT_TIME_FOR_NO_RESPONSE_MS);
+
// onChildrenLoaded should not be called.
assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
}
-// @Test
-// @MediumTest
+ @Test
+ @MediumTest
public void testSubscribeWithOptions() throws Exception {
connectMediaBrowserService();
final int pageSize = 3;
@@ -308,36 +351,34 @@
Bundle options = new Bundle();
options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
- synchronized (mSubscriptionCallback.mWaitLock) {
- for (int page = 0; page <= lastPage; ++page) {
- resetCallbacks();
- options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
- mMediaBrowser.subscribe(MEDIA_ID_ROOT, options, mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedWithOptionCount > 0);
- assertEquals(MEDIA_ID_ROOT, mSubscriptionCallback.mLastParentId);
- if (page != lastPage) {
- assertEquals(pageSize, mSubscriptionCallback.mLastChildMediaItems.size());
- } else {
- assertEquals((MEDIA_ID_CHILDREN.length - 1) % pageSize + 1,
- mSubscriptionCallback.mLastChildMediaItems.size());
- }
- // Check whether all the items in the current page are loaded.
- for (int i = 0; i < mSubscriptionCallback.mLastChildMediaItems.size(); ++i) {
- assertEquals(MEDIA_ID_CHILDREN[page * pageSize + i],
- mSubscriptionCallback.mLastChildMediaItems.get(i).getMediaId());
- }
+ for (int page = 0; page <= lastPage; ++page) {
+ mSubscriptionCallback.reset(1);
+ options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
+ mMediaBrowser.subscribe(MEDIA_ID_ROOT, options, mSubscriptionCallback);
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(1, mSubscriptionCallback.mChildrenLoadedWithOptionCount);
+ assertEquals(MEDIA_ID_ROOT, mSubscriptionCallback.mLastParentId);
+ if (page != lastPage) {
+ assertEquals(pageSize, mSubscriptionCallback.mLastChildMediaItems.size());
+ } else {
+ assertEquals((MEDIA_ID_CHILDREN.length - 1) % pageSize + 1,
+ mSubscriptionCallback.mLastChildMediaItems.size());
+ }
+ // Check whether all the items in the current page are loaded.
+ for (int i = 0; i < mSubscriptionCallback.mLastChildMediaItems.size(); ++i) {
+ assertEquals(MEDIA_ID_CHILDREN[page * pageSize + i],
+ mSubscriptionCallback.mLastChildMediaItems.get(i).getMediaId());
}
// Test MediaBrowserServiceCompat.notifyChildrenChanged()
- mSubscriptionCallback.reset();
+ mSubscriptionCallback.reset(page + 1);
callMediaBrowserServiceMethod(NOTIFY_CHILDREN_CHANGED, MEDIA_ID_ROOT, getContext());
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedWithOptionCount > 0);
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(page + 1, mSubscriptionCallback.mChildrenLoadedWithOptionCount);
}
// Test unsubscribe with callback argument.
- resetCallbacks();
+ mSubscriptionCallback.reset(1);
mMediaBrowser.unsubscribe(MEDIA_ID_ROOT, mSubscriptionCallback);
// After unsubscribing, make StubMediaBrowserServiceCompat notify that the children are
@@ -356,17 +397,16 @@
@MediumTest
public void testSubscribeDelayedItems() throws Exception {
connectMediaBrowserService();
- synchronized (mSubscriptionCallback.mWaitLock) {
- mSubscriptionCallback.reset();
- mMediaBrowser.subscribe(MEDIA_ID_CHILDREN_DELAYED, mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
- callMediaBrowserServiceMethod(
- SEND_DELAYED_NOTIFY_CHILDREN_CHANGED, MEDIA_ID_CHILDREN_DELAYED, getContext());
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mSubscriptionCallback.mChildrenLoadedCount > 0);
- }
+ mSubscriptionCallback.reset(1);
+ mMediaBrowser.subscribe(MEDIA_ID_CHILDREN_DELAYED, mSubscriptionCallback);
+ mSubscriptionCallback.await(WAIT_TIME_FOR_NO_RESPONSE_MS);
+ assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
+
+ callMediaBrowserServiceMethod(
+ SEND_DELAYED_NOTIFY_CHILDREN_CHANGED, MEDIA_ID_CHILDREN_DELAYED, getContext());
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(1, mSubscriptionCallback.mChildrenLoadedCount);
}
@Test
@@ -374,11 +414,10 @@
public void testSubscribeInvalidItem() throws Exception {
connectMediaBrowserService();
- synchronized (mSubscriptionCallback.mWaitLock) {
- mMediaBrowser.subscribe(MEDIA_ID_INVALID, mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertEquals(MEDIA_ID_INVALID, mSubscriptionCallback.mLastErrorId);
- }
+ mSubscriptionCallback.reset(1);
+ mMediaBrowser.subscribe(MEDIA_ID_INVALID, mSubscriptionCallback);
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(MEDIA_ID_INVALID, mSubscriptionCallback.mLastErrorId);
}
@Test
@@ -392,16 +431,15 @@
options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
- synchronized (mSubscriptionCallback.mWaitLock) {
- mMediaBrowser.subscribe(MEDIA_ID_INVALID, options, mSubscriptionCallback);
- mSubscriptionCallback.mWaitLock.wait(TIME_OUT_MS);
- assertEquals(MEDIA_ID_INVALID, mSubscriptionCallback.mLastErrorId);
- assertNotNull(mSubscriptionCallback.mLastOptions);
- assertEquals(page,
- mSubscriptionCallback.mLastOptions.getInt(MediaBrowserCompat.EXTRA_PAGE));
- assertEquals(pageSize,
- mSubscriptionCallback.mLastOptions.getInt(MediaBrowserCompat.EXTRA_PAGE_SIZE));
- }
+ mSubscriptionCallback.reset(1);
+ mMediaBrowser.subscribe(MEDIA_ID_INVALID, options, mSubscriptionCallback);
+ mSubscriptionCallback.await(TIME_OUT_MS);
+ assertEquals(MEDIA_ID_INVALID, mSubscriptionCallback.mLastErrorId);
+ assertNotNull(mSubscriptionCallback.mLastOptions);
+ assertEquals(page,
+ mSubscriptionCallback.mLastOptions.getInt(MediaBrowserCompat.EXTRA_PAGE));
+ assertEquals(pageSize,
+ mSubscriptionCallback.mLastOptions.getInt(MediaBrowserCompat.EXTRA_PAGE_SIZE));
}
@Test
@@ -419,17 +457,17 @@
Bundle options = new Bundle();
options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
+ callback.reset(1);
mMediaBrowser.subscribe(MEDIA_ID_ROOT, options, callback);
- synchronized (callback.mWaitLock) {
- callback.mWaitLock.wait(TIME_OUT_MS);
- }
+ callback.await(TIME_OUT_MS);
+
// Each onChildrenLoaded() must be called.
assertEquals(1, callback.mChildrenLoadedWithOptionCount);
}
// Reset callbacks and unsubscribe.
for (StubSubscriptionCallback callback : subscriptionCallbacks) {
- callback.reset();
+ callback.reset(1);
}
mMediaBrowser.unsubscribe(MEDIA_ID_ROOT);
@@ -448,8 +486,8 @@
}
}
-// @Test
-// @MediumTest
+ @Test
+ @MediumTest
public void testUnsubscribeWithSubscriptionCallbackForMultipleSubscriptions() throws Exception {
connectMediaBrowserService();
final List<StubSubscriptionCallback> subscriptionCallbacks = new ArrayList<>();
@@ -463,10 +501,10 @@
Bundle options = new Bundle();
options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
+ callback.reset(1);
mMediaBrowser.subscribe(MEDIA_ID_ROOT, options, callback);
- synchronized (callback.mWaitLock) {
- callback.mWaitLock.wait(TIME_OUT_MS);
- }
+ callback.await(TIME_OUT_MS);
+
// Each onChildrenLoaded() must be called.
assertEquals(1, callback.mChildrenLoadedWithOptionCount);
}
@@ -476,7 +514,7 @@
for (int i = 0; i < orderOfRemovingCallbacks.length; i++) {
// Reset callbacks
for (StubSubscriptionCallback callback : subscriptionCallbacks) {
- callback.reset();
+ callback.reset(1);
}
// Remove one subscription
@@ -611,6 +649,7 @@
customActionExtras.putString(TEST_KEY_1, TEST_VALUE_1);
mMediaBrowser.sendCustomAction(
CUSTOM_ACTION, customActionExtras, mCustomActionCallback);
+ mCustomActionCallback.mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
mCustomActionCallback.reset();
Bundle data1 = new Bundle();
@@ -701,6 +740,8 @@
Bundle customActionExtras = new Bundle();
customActionExtras.putString(TEST_KEY_1, TEST_VALUE_1);
mMediaBrowser.sendCustomAction(CUSTOM_ACTION, customActionExtras, null);
+ // Wait some time so that the service can get a result receiver for the custom action.
+ Thread.sleep(WAIT_TIME_FOR_NO_RESPONSE_MS);
// These calls should not make any exceptions.
callMediaBrowserServiceMethod(CUSTOM_ACTION_SEND_PROGRESS_UPDATE, new Bundle(),
@@ -768,12 +809,6 @@
}
}
- private void resetCallbacks() {
- mConnectionCallback.reset();
- mSubscriptionCallback.reset();
- mItemCallback.reset();
- }
-
private class StubConnectionCallback extends MediaBrowserCompat.ConnectionCallback {
final Object mWaitLock = new Object();
volatile int mConnectedCount;
@@ -812,7 +847,7 @@
}
private class StubSubscriptionCallback extends MediaBrowserCompat.SubscriptionCallback {
- final Object mWaitLock = new Object();
+ private CountDownLatch mLatch;
private volatile int mChildrenLoadedCount;
private volatile int mChildrenLoadedWithOptionCount;
private volatile String mLastErrorId;
@@ -820,7 +855,8 @@
private volatile Bundle mLastOptions;
private volatile List<MediaItem> mLastChildMediaItems;
- public void reset() {
+ public void reset(int count) {
+ mLatch = new CountDownLatch(count);
mChildrenLoadedCount = 0;
mChildrenLoadedWithOptionCount = 0;
mLastErrorId = null;
@@ -829,43 +865,43 @@
mLastChildMediaItems = null;
}
+ public boolean await(long timeoutMs) {
+ try {
+ return mLatch.await(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+
@Override
public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children) {
- synchronized (mWaitLock) {
- mChildrenLoadedCount++;
- mLastParentId = parentId;
- mLastChildMediaItems = children;
- mWaitLock.notify();
- }
+ mChildrenLoadedCount++;
+ mLastParentId = parentId;
+ mLastChildMediaItems = children;
+ mLatch.countDown();
}
@Override
public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children,
@NonNull Bundle options) {
- synchronized (mWaitLock) {
- mChildrenLoadedWithOptionCount++;
- mLastParentId = parentId;
- mLastOptions = options;
- mLastChildMediaItems = children;
- mWaitLock.notify();
- }
+ mChildrenLoadedWithOptionCount++;
+ mLastParentId = parentId;
+ mLastOptions = options;
+ mLastChildMediaItems = children;
+ mLatch.countDown();
}
@Override
public void onError(@NonNull String id) {
- synchronized (mWaitLock) {
- mLastErrorId = id;
- mWaitLock.notify();
- }
+ mLastErrorId = id;
+ mLatch.countDown();
}
@Override
public void onError(@NonNull String id, @NonNull Bundle options) {
- synchronized (mWaitLock) {
- mLastErrorId = id;
- mLastOptions = options;
- mWaitLock.notify();
- }
+ mLastErrorId = id;
+ mLastOptions = options;
+ mLatch.countDown();
}
}
diff --git a/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java b/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
index 79993ef..b173a4d 100644
--- a/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
+++ b/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
@@ -46,6 +46,7 @@
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_SESSION_EVENT;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_VALUE;
import static android.support.mediacompat.testlib.VersionConstants.KEY_SERVICE_VERSION;
+import static android.support.mediacompat.testlib.util.IntentUtil.SERVICE_PACKAGE_NAME;
import static android.support.mediacompat.testlib.util.IntentUtil.callMediaSessionMethod;
import static android.support.mediacompat.testlib.util.TestUtil.assertBundleEquals;
import static android.support.test.InstrumentationRegistry.getArguments;
@@ -55,9 +56,11 @@
import static android.support.v4.media.MediaMetadataCompat.METADATA_KEY_RATING;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -84,8 +87,6 @@
import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
-import junit.framework.Assert;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -107,7 +108,7 @@
private static final int MAX_AUDIO_INFO_CHANGED_CALLBACK_COUNT = 10;
private static final ComponentName TEST_BROWSER_SERVICE = new ComponentName(
- "android.support.mediacompat.service.test",
+ SERVICE_PACKAGE_NAME,
"android.support.mediacompat.service.StubMediaBrowserServiceCompat");
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -119,6 +120,7 @@
private MediaBrowserCompat mMediaBrowser;
private ConnectionCallback mConnectionCallback = new ConnectionCallback();
+ private MediaSessionCompat.Token mSessionToken;
private MediaControllerCompat mController;
private MediaControllerCallback mMediaControllerCallback = new MediaControllerCallback();
@@ -140,11 +142,11 @@
mMediaBrowser.connect();
mConnectionCallback.mWaitLock.wait(TIME_OUT_MS);
if (!mMediaBrowser.isConnected()) {
- Assert.fail("Browser failed to connect!");
+ fail("Browser failed to connect!");
}
}
- mController =
- new MediaControllerCompat(getTargetContext(), mMediaBrowser.getSessionToken());
+ mSessionToken = mMediaBrowser.getSessionToken();
+ mController = new MediaControllerCompat(getTargetContext(), mSessionToken);
mController.registerCallback(mMediaControllerCallback, mHandler);
}
@@ -155,6 +157,20 @@
}
}
+ @Test
+ @SmallTest
+ public void testGetPackageName() {
+ assertEquals(SERVICE_PACKAGE_NAME, mController.getPackageName());
+ }
+
+ @Test
+ @SmallTest
+ public void testIsSessionReady() throws Exception {
+ // mController already has the extra binder since it was created with the session token
+ // which holds the extra binder.
+ assertTrue(mController.isSessionReady());
+ }
+
/**
* Tests {@link MediaSessionCompat#setExtras}.
*/
@@ -487,7 +503,7 @@
&& info.getMaxVolume() == TEST_MAX_VOLUME
&& info.getVolumeControl() == VolumeProviderCompat.VOLUME_CONTROL_FIXED
&& info.getPlaybackType()
- == MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
+ == MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
break;
}
}
@@ -541,6 +557,36 @@
}.run();
}
+ @Test
+ @SmallTest
+ public void testSessionReady() throws Exception {
+ if (android.os.Build.VERSION.SDK_INT < 21) {
+ return;
+ }
+
+ final MediaSessionCompat.Token tokenWithoutExtraBinder =
+ MediaSessionCompat.Token.fromToken(mSessionToken.getToken());
+
+ final MediaControllerCallback callback = new MediaControllerCallback();
+ synchronized (mWaitLock) {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ MediaControllerCompat controller = new MediaControllerCompat(
+ getInstrumentation().getTargetContext(), tokenWithoutExtraBinder);
+ controller.registerCallback(callback, new Handler());
+ assertFalse(controller.isSessionReady());
+ } catch (Exception e) {
+ fail();
+ }
+ }
+ });
+ mWaitLock.wait(TIME_OUT_MS);
+ assertTrue(callback.mOnSessionReadyCalled);
+ }
+ }
+
private void assertQueueEquals(List<QueueItem> expected, List<QueueItem> observed) {
if (expected == null || observed == null) {
assertTrue(expected == observed);
@@ -570,6 +616,7 @@
private volatile boolean mOnCaptioningEnabledChangedCalled;
private volatile boolean mOnRepeatModeChangedCalled;
private volatile boolean mOnShuffleModeChangedCalled;
+ private volatile boolean mOnSessionReadyCalled;
private volatile PlaybackStateCompat mPlaybackState;
private volatile MediaMetadataCompat mMediaMetadata;
@@ -703,6 +750,14 @@
mWaitLock.notify();
}
}
+
+ @Override
+ public void onSessionReady() {
+ synchronized (mWaitLock) {
+ mOnSessionReadyCalled = true;
+ mWaitLock.notify();
+ }
+ }
}
private class ConnectionCallback extends MediaBrowserCompat.ConnectionCallback {
diff --git a/media-compat/tests/src/android/support/v4/media/MediaItemTest.java b/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaItemTest.java
similarity index 94%
copy from media-compat/tests/src/android/support/v4/media/MediaItemTest.java
copy to media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaItemTest.java
index bd2565f..179a178 100644
--- a/media-compat/tests/src/android/support/v4/media/MediaItemTest.java
+++ b/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaItemTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.support.v4.media;
+package android.support.mediacompat.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -22,11 +22,12 @@
import android.os.Parcel;
import android.support.test.filters.SmallTest;
import android.support.v4.media.MediaBrowserCompat.MediaItem;
+import android.support.v4.media.MediaDescriptionCompat;
import org.junit.Test;
/**
- * Test {@link MediaBrowserCompat.MediaItem}.
+ * Test {@link MediaItem}.
*/
public class MediaItemTest {
private static final String DESCRIPTION = "test_description";
diff --git a/media-compat/tests/src/android/support/v4/media/session/PlaybackStateCompatTest.java b/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/PlaybackStateCompatTest.java
similarity index 97%
copy from media-compat/tests/src/android/support/v4/media/session/PlaybackStateCompatTest.java
copy to media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/PlaybackStateCompatTest.java
index 9e320cd..7962731 100644
--- a/media-compat/tests/src/android/support/v4/media/session/PlaybackStateCompatTest.java
+++ b/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/PlaybackStateCompatTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v4.media.session;
+package android.support.mediacompat.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -24,6 +24,8 @@
import android.os.Parcel;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/media-compat/version-compat-tests/previous/service/build.gradle b/media-compat/version-compat-tests/previous/service/build.gradle
index 03f95ce..469f6e4 100644
--- a/media-compat/version-compat-tests/previous/service/build.gradle
+++ b/media-compat/version-compat-tests/previous/service/build.gradle
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
+
plugins {
id("SupportAndroidLibraryPlugin")
}
@@ -22,7 +24,7 @@
androidTestImplementation project(':support-media-compat-test-lib')
androidTestImplementation "com.android.support:support-media-compat:27.0.1"
- androidTestImplementation(libs.test_runner)
+ androidTestImplementation(TEST_RUNNER)
}
android {
diff --git a/media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java b/media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
index d36eba3..5c5a432 100644
--- a/media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
+++ b/media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
@@ -18,6 +18,7 @@
import static android.support.mediacompat.testlib.MediaControllerConstants.ADD_QUEUE_ITEM;
import static android.support.mediacompat.testlib.MediaControllerConstants
.ADD_QUEUE_ITEM_WITH_INDEX;
+import static android.support.mediacompat.testlib.MediaControllerConstants.ADJUST_VOLUME;
import static android.support.mediacompat.testlib.MediaControllerConstants.FAST_FORWARD;
import static android.support.mediacompat.testlib.MediaControllerConstants.PAUSE;
import static android.support.mediacompat.testlib.MediaControllerConstants.PLAY;
@@ -39,12 +40,18 @@
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_RATING;
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_REPEAT_MODE;
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_SHUFFLE_MODE;
+import static android.support.mediacompat.testlib.MediaControllerConstants.SET_VOLUME_TO;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_NEXT;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_PREVIOUS;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_QUEUE_ITEM;
import static android.support.mediacompat.testlib.MediaControllerConstants.STOP;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_COMMAND;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_KEY;
+import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_MEDIA_ID_1;
+import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_MEDIA_ID_2;
+import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_MEDIA_TITLE_1;
+import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_MEDIA_TITLE_2;
+import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_QUEUE_ID_1;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_SESSION_TAG;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_VALUE;
import static android.support.mediacompat.testlib.VersionConstants.KEY_CLIENT_VERSION;
@@ -57,21 +64,38 @@
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
+import android.os.Parcel;
import android.os.ResultReceiver;
+import android.os.SystemClock;
+import android.support.test.filters.MediumTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.RatingCompat;
+import android.support.v4.media.VolumeProviderCompat;
+import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
+import android.view.KeyEvent;
import org.junit.After;
import org.junit.Before;
@@ -80,6 +104,8 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Test {@link MediaSessionCompat.Callback}.
@@ -91,6 +117,10 @@
// The maximum time to wait for an operation.
private static final long TIME_OUT_MS = 3000L;
+ private static final long WAIT_TIME_FOR_NO_RESPONSE_MS = 300L;
+
+ private static final long TEST_POSITION = 1000000L;
+ private static final float TEST_PLAYBACK_SPEED = 3.0f;
private static final float DELTA = 1e-4f;
private static final boolean ENABLED = true;
@@ -99,6 +129,7 @@
private String mClientVersion;
private MediaSessionCompat mSession;
private MediaSessionCallback mCallback = new MediaSessionCallback();
+ private AudioManager mAudioManager;
@Before
public void setUp() throws Exception {
@@ -109,9 +140,9 @@
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
+ mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mSession = new MediaSessionCompat(getTargetContext(), TEST_SESSION_TAG);
mSession.setCallback(mCallback, mHandler);
- mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS);
}
});
}
@@ -121,277 +152,662 @@
mSession.release();
}
+ /**
+ * Tests that a session can be created and that all the fields are initialized correctly.
+ */
+ @Test
+ @SmallTest
+ public void testCreateSession() throws Exception {
+ assertNotNull(mSession.getSessionToken());
+ assertFalse("New session should not be active", mSession.isActive());
+
+ // Verify by getting the controller and checking all its fields
+ MediaControllerCompat controller = mSession.getController();
+ assertNotNull(controller);
+
+ final String errorMsg = "New session has unexpected configuration.";
+ assertEquals(errorMsg, 0L, controller.getFlags());
+ assertNull(errorMsg, controller.getExtras());
+ assertNull(errorMsg, controller.getMetadata());
+ assertEquals(errorMsg, getContext().getPackageName(), controller.getPackageName());
+ assertNull(errorMsg, controller.getPlaybackState());
+ assertNull(errorMsg, controller.getQueue());
+ assertNull(errorMsg, controller.getQueueTitle());
+ assertEquals(errorMsg, RatingCompat.RATING_NONE, controller.getRatingType());
+ assertNull(errorMsg, controller.getSessionActivity());
+
+ assertNotNull(controller.getSessionToken());
+ assertNotNull(controller.getTransportControls());
+
+ MediaControllerCompat.PlaybackInfo info = controller.getPlaybackInfo();
+ assertNotNull(info);
+ assertEquals(errorMsg, MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_LOCAL,
+ info.getPlaybackType());
+ assertEquals(errorMsg, mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC),
+ info.getCurrentVolume());
+ }
+
+ @Test
+ @SmallTest
+ public void testGetSessionToken() throws Exception {
+ assertEquals(mSession.getSessionToken(), mSession.getController().getSessionToken());
+ }
+
+ /**
+ * Tests that a session can be created from the framework session object and the callback
+ * set on the framework session object before fromSession() is called works properly.
+ */
+ @Test
+ @SmallTest
+ public void testFromSession() throws Exception {
+ if (android.os.Build.VERSION.SDK_INT < 21) {
+ // MediaSession was introduced from API level 21.
+ return;
+ }
+ mCallback.reset(1);
+ mSession.setCallback(mCallback, new Handler(Looper.getMainLooper()));
+ MediaSessionCompat session = MediaSessionCompat.fromMediaSession(
+ getContext(), mSession.getMediaSession());
+ assertEquals(session.getSessionToken(), mSession.getSessionToken());
+
+ session.getController().getTransportControls().play();
+ mCallback.await(TIME_OUT_MS);
+ assertEquals(1, mCallback.mOnPlayCalledCount);
+ }
+
+ /**
+ * Tests {@link MediaSessionCompat.Token} created in the constructor of MediaSessionCompat.
+ */
+ @Test
+ @SmallTest
+ public void testSessionToken() throws Exception {
+ MediaSessionCompat.Token sessionToken = mSession.getSessionToken();
+
+ assertNotNull(sessionToken);
+ assertEquals(0, sessionToken.describeContents());
+
+ // Test writeToParcel
+ Parcel p = Parcel.obtain();
+ sessionToken.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ MediaSessionCompat.Token token = MediaSessionCompat.Token.CREATOR.createFromParcel(p);
+ assertEquals(token, sessionToken);
+ p.recycle();
+ }
+
+ /**
+ * Tests {@link MediaSessionCompat.QueueItem}.
+ */
+ @Test
+ @SmallTest
+ public void testQueueItem() {
+ MediaSessionCompat.QueueItem item = new MediaSessionCompat.QueueItem(
+ new MediaDescriptionCompat.Builder()
+ .setMediaId(TEST_MEDIA_ID_1)
+ .setTitle(TEST_MEDIA_TITLE_1)
+ .build(),
+ TEST_QUEUE_ID_1);
+ assertEquals(TEST_QUEUE_ID_1, item.getQueueId());
+ assertEquals(TEST_MEDIA_ID_1, item.getDescription().getMediaId());
+ assertEquals(TEST_MEDIA_TITLE_1, item.getDescription().getTitle());
+ assertEquals(0, item.describeContents());
+
+ Parcel p = Parcel.obtain();
+ item.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ MediaSessionCompat.QueueItem other =
+ MediaSessionCompat.QueueItem.CREATOR.createFromParcel(p);
+ assertEquals(item.toString(), other.toString());
+ p.recycle();
+ }
+
+ /**
+ * Tests {@link MediaSessionCompat#setActive}.
+ */
+ @Test
+ @SmallTest
+ public void testSetActive() throws Exception {
+ mSession.setActive(true);
+ assertTrue(mSession.isActive());
+ }
+
+ @Test
+ @SmallTest
+ public void testGetPlaybackStateWithPositionUpdate() throws InterruptedException {
+ final long stateSetTime = SystemClock.elapsedRealtime();
+ PlaybackStateCompat stateIn = new PlaybackStateCompat.Builder()
+ .setState(PlaybackStateCompat.STATE_PLAYING, TEST_POSITION, TEST_PLAYBACK_SPEED,
+ stateSetTime)
+ .build();
+ mSession.setPlaybackState(stateIn);
+
+ final long waitDuration = 100L;
+ Thread.sleep(waitDuration);
+
+ final long expectedUpdateTime = waitDuration + stateSetTime;
+ final long expectedPosition = (long) (TEST_PLAYBACK_SPEED * waitDuration) + TEST_POSITION;
+
+ final double updateTimeTolerance = 50L;
+ final double positionTolerance = updateTimeTolerance * TEST_PLAYBACK_SPEED;
+
+ PlaybackStateCompat stateOut = mSession.getController().getPlaybackState();
+ assertEquals(expectedUpdateTime, stateOut.getLastPositionUpdateTime(), updateTimeTolerance);
+ assertEquals(expectedPosition, stateOut.getPosition(), positionTolerance);
+
+ // Compare the result with MediaController.getPlaybackState().
+ if (Build.VERSION.SDK_INT >= 21) {
+ MediaController controller = new MediaController(
+ getContext(), (MediaSession.Token) mSession.getSessionToken().getToken());
+ PlaybackState state = controller.getPlaybackState();
+ assertEquals(state.getLastPositionUpdateTime(), stateOut.getLastPositionUpdateTime(),
+ updateTimeTolerance);
+ assertEquals(state.getPosition(), stateOut.getPosition(), positionTolerance);
+ }
+ }
+
+ /**
+ * Tests {@link MediaSessionCompat#setCallback} with {@code null}.
+ * No callback should be called once {@code setCallback(null)} is done.
+ */
+ @Test
+ @SmallTest
+ public void testSetCallbackWithNull() throws Exception {
+ mSession.setActive(true);
+ mCallback.reset(1);
+ callTransportControlsMethod(PLAY, null, getContext(), mSession.getSessionToken());
+ mSession.setCallback(null, mHandler);
+ mCallback.await(WAIT_TIME_FOR_NO_RESPONSE_MS);
+ assertEquals("Callback shouldn't be called.", 0, mCallback.mOnPlayCalledCount);
+ }
+
@Test
@SmallTest
public void testSendCommand() throws Exception {
- synchronized (mWaitLock) {
- mCallback.reset();
+ mCallback.reset(1);
- Bundle arguments = new Bundle();
- arguments.putString("command", TEST_COMMAND);
- Bundle extras = new Bundle();
- extras.putString(TEST_KEY, TEST_VALUE);
- arguments.putBundle("extras", extras);
- callMediaControllerMethod(
- SEND_COMMAND, arguments, getContext(), mSession.getSessionToken());
+ Bundle arguments = new Bundle();
+ arguments.putString("command", TEST_COMMAND);
+ Bundle extras = new Bundle();
+ extras.putString(TEST_KEY, TEST_VALUE);
+ arguments.putBundle("extras", extras);
+ callMediaControllerMethod(
+ SEND_COMMAND, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnCommandCalled);
- assertNotNull(mCallback.mCommandCallback);
- assertEquals(TEST_COMMAND, mCallback.mCommand);
- assertBundleEquals(extras, mCallback.mExtras);
- }
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnCommandCalled);
+ assertNotNull(mCallback.mCommandCallback);
+ assertEquals(TEST_COMMAND, mCallback.mCommand);
+ assertBundleEquals(extras, mCallback.mExtras);
}
@Test
@SmallTest
public void testAddRemoveQueueItems() throws Exception {
- final String mediaId1 = "media_id_1";
- final String mediaTitle1 = "media_title_1";
+ mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS);
+
MediaDescriptionCompat itemDescription1 = new MediaDescriptionCompat.Builder()
- .setMediaId(mediaId1).setTitle(mediaTitle1).build();
+ .setMediaId(TEST_MEDIA_ID_1).setTitle(TEST_MEDIA_TITLE_1).build();
- final String mediaId2 = "media_id_2";
- final String mediaTitle2 = "media_title_2";
MediaDescriptionCompat itemDescription2 = new MediaDescriptionCompat.Builder()
- .setMediaId(mediaId2).setTitle(mediaTitle2).build();
+ .setMediaId(TEST_MEDIA_ID_2).setTitle(TEST_MEDIA_TITLE_2).build();
- synchronized (mWaitLock) {
- mCallback.reset();
- callMediaControllerMethod(
- ADD_QUEUE_ITEM, itemDescription1, getContext(), mSession.getSessionToken());
+ mCallback.reset(1);
+ callMediaControllerMethod(
+ ADD_QUEUE_ITEM, itemDescription1, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnAddQueueItemCalled);
- assertEquals(-1, mCallback.mQueueIndex);
- assertEquals(mediaId1, mCallback.mQueueDescription.getMediaId());
- assertEquals(mediaTitle1, mCallback.mQueueDescription.getTitle());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnAddQueueItemCalled);
+ assertEquals(-1, mCallback.mQueueIndex);
+ assertEquals(TEST_MEDIA_ID_1, mCallback.mQueueDescription.getMediaId());
+ assertEquals(TEST_MEDIA_TITLE_1, mCallback.mQueueDescription.getTitle());
- mCallback.reset();
- Bundle arguments = new Bundle();
- arguments.putParcelable("description", itemDescription2);
- arguments.putInt("index", 0);
- callMediaControllerMethod(
- ADD_QUEUE_ITEM_WITH_INDEX, arguments, getContext(), mSession.getSessionToken());
+ mCallback.reset(1);
+ Bundle arguments = new Bundle();
+ arguments.putParcelable("description", itemDescription2);
+ arguments.putInt("index", 0);
+ callMediaControllerMethod(
+ ADD_QUEUE_ITEM_WITH_INDEX, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnAddQueueItemAtCalled);
- assertEquals(0, mCallback.mQueueIndex);
- assertEquals(mediaId2, mCallback.mQueueDescription.getMediaId());
- assertEquals(mediaTitle2, mCallback.mQueueDescription.getTitle());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnAddQueueItemAtCalled);
+ assertEquals(0, mCallback.mQueueIndex);
+ assertEquals(TEST_MEDIA_ID_2, mCallback.mQueueDescription.getMediaId());
+ assertEquals(TEST_MEDIA_TITLE_2, mCallback.mQueueDescription.getTitle());
- mCallback.reset();
- callMediaControllerMethod(
- REMOVE_QUEUE_ITEM, itemDescription1, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnRemoveQueueItemCalled);
- assertEquals(mediaId1, mCallback.mQueueDescription.getMediaId());
- assertEquals(mediaTitle1, mCallback.mQueueDescription.getTitle());
- }
+ mCallback.reset(1);
+ callMediaControllerMethod(
+ REMOVE_QUEUE_ITEM, itemDescription1, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnRemoveQueueItemCalled);
+ assertEquals(TEST_MEDIA_ID_1, mCallback.mQueueDescription.getMediaId());
+ assertEquals(TEST_MEDIA_TITLE_1, mCallback.mQueueDescription.getTitle());
}
@Test
@SmallTest
public void testTransportControlsAndMediaSessionCallback() throws Exception {
+ mCallback.reset(1);
+ callTransportControlsMethod(PLAY, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertEquals(1, mCallback.mOnPlayCalledCount);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(PAUSE, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPauseCalled);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(STOP, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnStopCalled);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(
+ FAST_FORWARD, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnFastForwardCalled);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(REWIND, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnRewindCalled);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(
+ SKIP_TO_PREVIOUS, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSkipToPreviousCalled);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(
+ SKIP_TO_NEXT, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSkipToNextCalled);
+
+ mCallback.reset(1);
+ final long seekPosition = 1000;
+ callTransportControlsMethod(
+ SEEK_TO, seekPosition, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSeekToCalled);
+ assertEquals(seekPosition, mCallback.mSeekPosition);
+
+ mCallback.reset(1);
+ final RatingCompat rating =
+ RatingCompat.newStarRating(RatingCompat.RATING_5_STARS, 3f);
+ callTransportControlsMethod(
+ SET_RATING, rating, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSetRatingCalled);
+ assertEquals(rating.getRatingStyle(), mCallback.mRating.getRatingStyle());
+ assertEquals(rating.getStarRating(), mCallback.mRating.getStarRating(), DELTA);
+
+ mCallback.reset(1);
+ final Bundle extras = new Bundle();
+ extras.putString(TEST_KEY, TEST_VALUE);
+ Bundle arguments = new Bundle();
+ arguments.putString("mediaId", TEST_MEDIA_ID_1);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ PLAY_FROM_MEDIA_ID, arguments, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPlayFromMediaIdCalled);
+ assertEquals(TEST_MEDIA_ID_1, mCallback.mMediaId);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ final String query = "test-query";
+ arguments = new Bundle();
+ arguments.putString("query", query);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ PLAY_FROM_SEARCH, arguments, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPlayFromSearchCalled);
+ assertEquals(query, mCallback.mQuery);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ final Uri uri = Uri.parse("content://test/popcorn.mod");
+ arguments = new Bundle();
+ arguments.putParcelable("uri", uri);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ PLAY_FROM_URI, arguments, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPlayFromUriCalled);
+ assertEquals(uri, mCallback.mUri);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ final String action = "test-action";
+ arguments = new Bundle();
+ arguments.putString("action", action);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ SEND_CUSTOM_ACTION, arguments, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnCustomActionCalled);
+ assertEquals(action, mCallback.mAction);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ mCallback.mOnCustomActionCalled = false;
+ final PlaybackStateCompat.CustomAction customAction =
+ new PlaybackStateCompat.CustomAction.Builder(action, action, -1)
+ .setExtras(extras)
+ .build();
+ arguments = new Bundle();
+ arguments.putParcelable("action", customAction);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ SEND_CUSTOM_ACTION_PARCELABLE,
+ arguments,
+ getContext(),
+ mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnCustomActionCalled);
+ assertEquals(action, mCallback.mAction);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ final long queueItemId = 1000;
+ callTransportControlsMethod(
+ SKIP_TO_QUEUE_ITEM, queueItemId, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSkipToQueueItemCalled);
+ assertEquals(queueItemId, mCallback.mQueueItemId);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(
+ PREPARE, null, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPrepareCalled);
+
+ mCallback.reset(1);
+ arguments = new Bundle();
+ arguments.putString("mediaId", TEST_MEDIA_ID_2);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ PREPARE_FROM_MEDIA_ID, arguments, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPrepareFromMediaIdCalled);
+ assertEquals(TEST_MEDIA_ID_2, mCallback.mMediaId);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ arguments = new Bundle();
+ arguments.putString("query", query);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ PREPARE_FROM_SEARCH, arguments, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPrepareFromSearchCalled);
+ assertEquals(query, mCallback.mQuery);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ arguments = new Bundle();
+ arguments.putParcelable("uri", uri);
+ arguments.putBundle("extras", extras);
+ callTransportControlsMethod(
+ PREPARE_FROM_URI, arguments, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnPrepareFromUriCalled);
+ assertEquals(uri, mCallback.mUri);
+ assertBundleEquals(extras, mCallback.mExtras);
+
+ mCallback.reset(1);
+ callTransportControlsMethod(
+ SET_CAPTIONING_ENABLED, ENABLED, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSetCaptioningEnabledCalled);
+ assertEquals(ENABLED, mCallback.mCaptioningEnabled);
+
+ mCallback.reset(1);
+ final int repeatMode = PlaybackStateCompat.REPEAT_MODE_ALL;
+ callTransportControlsMethod(
+ SET_REPEAT_MODE, repeatMode, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSetRepeatModeCalled);
+ assertEquals(repeatMode, mCallback.mRepeatMode);
+
+ mCallback.reset(1);
+ final int shuffleMode = PlaybackStateCompat.SHUFFLE_MODE_ALL;
+ callTransportControlsMethod(
+ SET_SHUFFLE_MODE, shuffleMode, getContext(), mSession.getSessionToken());
+ mCallback.await(TIME_OUT_MS);
+ assertTrue(mCallback.mOnSetShuffleModeCalled);
+ assertEquals(shuffleMode, mCallback.mShuffleMode);
+ }
+
+ /**
+ * Tests {@link MediaSessionCompat.Callback#onMediaButtonEvent}.
+ */
+ @Test
+ @MediumTest
+ public void testCallbackOnMediaButtonEvent() throws Exception {
+ mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS);
+ mSession.setActive(true);
+
+ final long waitTimeForNoResponse = 30L;
+
+ Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON)
+ .setComponent(new ComponentName(getContext(), getContext().getClass()));
+ PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, mediaButtonIntent, 0);
+ mSession.setMediaButtonReceiver(pi);
+
+ // Set state to STATE_PLAYING to get higher priority.
+ setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
+
+ mCallback.reset(1);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertEquals(1, mCallback.mOnPlayCalledCount);
+
+ mCallback.reset(1);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PAUSE);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertTrue(mCallback.mOnPauseCalled);
+
+ mCallback.reset(1);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_NEXT);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertTrue(mCallback.mOnSkipToNextCalled);
+
+ mCallback.reset(1);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertTrue(mCallback.mOnSkipToPreviousCalled);
+
+ mCallback.reset(1);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_STOP);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertTrue(mCallback.mOnStopCalled);
+
+ mCallback.reset(1);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertTrue(mCallback.mOnFastForwardCalled);
+
+ mCallback.reset(1);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_REWIND);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertTrue(mCallback.mOnRewindCalled);
+
+ // Test PLAY_PAUSE button twice.
+ // First, send PLAY_PAUSE button event while in STATE_PAUSED.
+ mCallback.reset(1);
+ setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertEquals(1, mCallback.mOnPlayCalledCount);
+
+ // Next, send PLAY_PAUSE button event while in STATE_PLAYING.
+ mCallback.reset(1);
+ setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertTrue(mCallback.mOnPauseCalled);
+
+ // Double tap of PLAY_PAUSE is the next track.
+ mCallback.reset(2);
+ setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ assertFalse(mCallback.await(waitTimeForNoResponse));
+ assertTrue(mCallback.mOnSkipToNextCalled);
+ assertEquals(0, mCallback.mOnPlayCalledCount);
+ assertFalse(mCallback.mOnPauseCalled);
+
+ // Test PLAY_PAUSE button long-press.
+ // It should be the same as the single short-press.
+ mCallback.reset(1);
+ setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, true);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertEquals(1, mCallback.mOnPlayCalledCount);
+
+ // Double tap of PLAY_PAUSE should be handled once.
+ // Initial down event from the second press within double tap time-out will make
+ // onSkipToNext() to be called, so further down events shouldn't be handled again.
+ mCallback.reset(2);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, true);
+ assertFalse(mCallback.await(waitTimeForNoResponse));
+ assertTrue(mCallback.mOnSkipToNextCalled);
+ assertEquals(0, mCallback.mOnPlayCalledCount);
+ assertFalse(mCallback.mOnPauseCalled);
+
+ // Test PLAY_PAUSE button long-press followed by the short-press.
+ // Initial long-press of the PLAY_PAUSE is considered as the single short-press already,
+ // so it shouldn't be used as the first tap of the double tap.
+ mCallback.reset(2);
+ setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, true);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ // onMediaButtonEvent() calls either onPlay() or onPause() depending on the playback state,
+ // so onPlay() should be called once and onPause() also should be called once.
+ assertEquals(1, mCallback.mOnPlayCalledCount);
+ assertTrue(mCallback.mOnPauseCalled);
+ assertFalse(mCallback.mOnSkipToNextCalled);
+
+ // If another media key is pressed while the double tap of PLAY_PAUSE,
+ // PLAY_PAUSE should be handled as normal.
+ mCallback.reset(3);
+ setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_STOP);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertFalse(mCallback.mOnSkipToNextCalled);
+ assertTrue(mCallback.mOnStopCalled);
+ assertEquals(2, mCallback.mOnPlayCalledCount);
+
+ // Test if media keys are handled in order.
+ mCallback.reset(2);
+ setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_STOP);
+ assertTrue(mCallback.await(TIME_OUT_MS));
+ assertEquals(1, mCallback.mOnPlayCalledCount);
+ assertTrue(mCallback.mOnStopCalled);
synchronized (mWaitLock) {
- mCallback.reset();
- callTransportControlsMethod(PLAY, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPlayCalled);
-
- mCallback.reset();
- callTransportControlsMethod(PAUSE, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPauseCalled);
-
- mCallback.reset();
- callTransportControlsMethod(STOP, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnStopCalled);
-
- mCallback.reset();
- callTransportControlsMethod(
- FAST_FORWARD, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnFastForwardCalled);
-
- mCallback.reset();
- callTransportControlsMethod(REWIND, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnRewindCalled);
-
- mCallback.reset();
- callTransportControlsMethod(
- SKIP_TO_PREVIOUS, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSkipToPreviousCalled);
-
- mCallback.reset();
- callTransportControlsMethod(
- SKIP_TO_NEXT, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSkipToNextCalled);
-
- mCallback.reset();
- final long seekPosition = 1000;
- callTransportControlsMethod(
- SEEK_TO, seekPosition, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSeekToCalled);
- assertEquals(seekPosition, mCallback.mSeekPosition);
-
- mCallback.reset();
- final RatingCompat rating =
- RatingCompat.newStarRating(RatingCompat.RATING_5_STARS, 3f);
- callTransportControlsMethod(
- SET_RATING, rating, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetRatingCalled);
- assertEquals(rating.getRatingStyle(), mCallback.mRating.getRatingStyle());
- assertEquals(rating.getStarRating(), mCallback.mRating.getStarRating(), DELTA);
-
- mCallback.reset();
- final String mediaId = "test-media-id";
- final Bundle extras = new Bundle();
- extras.putString(TEST_KEY, TEST_VALUE);
- Bundle arguments = new Bundle();
- arguments.putString("mediaId", mediaId);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- PLAY_FROM_MEDIA_ID, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPlayFromMediaIdCalled);
- assertEquals(mediaId, mCallback.mMediaId);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- final String query = "test-query";
- arguments = new Bundle();
- arguments.putString("query", query);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- PLAY_FROM_SEARCH, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPlayFromSearchCalled);
- assertEquals(query, mCallback.mQuery);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- final Uri uri = Uri.parse("content://test/popcorn.mod");
- arguments = new Bundle();
- arguments.putParcelable("uri", uri);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- PLAY_FROM_URI, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPlayFromUriCalled);
- assertEquals(uri, mCallback.mUri);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- final String action = "test-action";
- arguments = new Bundle();
- arguments.putString("action", action);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- SEND_CUSTOM_ACTION, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnCustomActionCalled);
- assertEquals(action, mCallback.mAction);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- mCallback.mOnCustomActionCalled = false;
- final PlaybackStateCompat.CustomAction customAction =
- new PlaybackStateCompat.CustomAction.Builder(action, action, -1)
- .setExtras(extras)
- .build();
- arguments = new Bundle();
- arguments.putParcelable("action", customAction);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- SEND_CUSTOM_ACTION_PARCELABLE,
- arguments,
- getContext(),
- mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnCustomActionCalled);
- assertEquals(action, mCallback.mAction);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- final long queueItemId = 1000;
- callTransportControlsMethod(
- SKIP_TO_QUEUE_ITEM, queueItemId, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSkipToQueueItemCalled);
- assertEquals(queueItemId, mCallback.mQueueItemId);
-
- mCallback.reset();
- callTransportControlsMethod(
- PREPARE, null, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPrepareCalled);
-
- mCallback.reset();
- arguments = new Bundle();
- arguments.putString("mediaId", mediaId);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- PREPARE_FROM_MEDIA_ID, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPrepareFromMediaIdCalled);
- assertEquals(mediaId, mCallback.mMediaId);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- arguments = new Bundle();
- arguments.putString("query", query);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- PREPARE_FROM_SEARCH, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPrepareFromSearchCalled);
- assertEquals(query, mCallback.mQuery);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- arguments = new Bundle();
- arguments.putParcelable("uri", uri);
- arguments.putBundle("extras", extras);
- callTransportControlsMethod(
- PREPARE_FROM_URI, arguments, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnPrepareFromUriCalled);
- assertEquals(uri, mCallback.mUri);
- assertBundleEquals(extras, mCallback.mExtras);
-
- mCallback.reset();
- callTransportControlsMethod(
- SET_CAPTIONING_ENABLED, ENABLED, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetCaptioningEnabledCalled);
- assertEquals(ENABLED, mCallback.mCaptioningEnabled);
-
- mCallback.reset();
- final int repeatMode = PlaybackStateCompat.REPEAT_MODE_ALL;
- callTransportControlsMethod(
- SET_REPEAT_MODE, repeatMode, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetRepeatModeCalled);
- assertEquals(repeatMode, mCallback.mRepeatMode);
-
- mCallback.reset();
- final int shuffleMode = PlaybackStateCompat.SHUFFLE_MODE_ALL;
- callTransportControlsMethod(
- SET_SHUFFLE_MODE, shuffleMode, getContext(), mSession.getSessionToken());
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mCallback.mOnSetShuffleModeCalled);
- assertEquals(shuffleMode, mCallback.mShuffleMode);
+ assertEquals(PlaybackStateCompat.STATE_STOPPED,
+ mSession.getController().getPlaybackState().getState());
}
}
+ @Test
+ @SmallTest
+ public void testVolumeControl() throws Exception {
+ if (android.os.Build.VERSION.SDK_INT < 27) {
+ // This test causes an Exception on System UI in API < 27.
+ return;
+ }
+ VolumeProviderCompat vp =
+ new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE, 11, 5) {
+ @Override
+ public void onSetVolumeTo(int volume) {
+ synchronized (mWaitLock) {
+ setCurrentVolume(volume);
+ mWaitLock.notify();
+ }
+ }
+
+ @Override
+ public void onAdjustVolume(int direction) {
+ synchronized (mWaitLock) {
+ switch (direction) {
+ case AudioManager.ADJUST_LOWER:
+ setCurrentVolume(getCurrentVolume() - 1);
+ break;
+ case AudioManager.ADJUST_RAISE:
+ setCurrentVolume(getCurrentVolume() + 1);
+ break;
+ }
+ mWaitLock.notify();
+ }
+ }
+ };
+ mSession.setPlaybackToRemote(vp);
+
+ synchronized (mWaitLock) {
+ // test setVolumeTo
+ callMediaControllerMethod(SET_VOLUME_TO,
+ 7 /* Target volume */, getContext(), mSession.getSessionToken());
+ mWaitLock.wait(TIME_OUT_MS);
+ assertEquals(7, vp.getCurrentVolume());
+
+ // test adjustVolume
+ callMediaControllerMethod(ADJUST_VOLUME,
+ AudioManager.ADJUST_LOWER, getContext(), mSession.getSessionToken());
+ mWaitLock.wait(TIME_OUT_MS);
+ assertEquals(6, vp.getCurrentVolume());
+
+ callMediaControllerMethod(ADJUST_VOLUME,
+ AudioManager.ADJUST_RAISE, getContext(), mSession.getSessionToken());
+ mWaitLock.wait(TIME_OUT_MS);
+ assertEquals(7, vp.getCurrentVolume());
+ }
+ }
+
+ private void setPlaybackState(int state) {
+ final long allActions = PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE
+ | PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_STOP
+ | PlaybackStateCompat.ACTION_SKIP_TO_NEXT
+ | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
+ | PlaybackStateCompat.ACTION_FAST_FORWARD | PlaybackStateCompat.ACTION_REWIND;
+ PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder().setActions(allActions)
+ .setState(state, 0L, 0.0f).build();
+ synchronized (mWaitLock) {
+ mSession.setPlaybackState(playbackState);
+ }
+ }
+
+ private void sendMediaKeyInputToController(int keyCode) {
+ sendMediaKeyInputToController(keyCode, false);
+ }
+
+ private void sendMediaKeyInputToController(int keyCode, boolean isLongPress) {
+ MediaControllerCompat controller = mSession.getController();
+ long currentTimeMs = System.currentTimeMillis();
+ KeyEvent down = new KeyEvent(
+ currentTimeMs, currentTimeMs, KeyEvent.ACTION_DOWN, keyCode, 0);
+ controller.dispatchMediaButtonEvent(down);
+ if (isLongPress) {
+ KeyEvent longPress = new KeyEvent(
+ currentTimeMs, System.currentTimeMillis(), KeyEvent.ACTION_DOWN, keyCode, 1);
+ controller.dispatchMediaButtonEvent(longPress);
+ }
+ KeyEvent up = new KeyEvent(
+ currentTimeMs, System.currentTimeMillis(), KeyEvent.ACTION_UP, keyCode, 0);
+ controller.dispatchMediaButtonEvent(up);
+ }
+
private class MediaSessionCallback extends MediaSessionCompat.Callback {
+ private CountDownLatch mLatch;
private long mSeekPosition;
private long mQueueItemId;
private RatingCompat mRating;
@@ -409,7 +825,7 @@
private MediaDescriptionCompat mQueueDescription;
private List<MediaSessionCompat.QueueItem> mQueue = new ArrayList<>();
- private boolean mOnPlayCalled;
+ private int mOnPlayCalledCount;
private boolean mOnPauseCalled;
private boolean mOnStopCalled;
private boolean mOnFastForwardCalled;
@@ -435,7 +851,8 @@
private boolean mOnAddQueueItemAtCalled;
private boolean mOnRemoveQueueItemCalled;
- public void reset() {
+ public void reset(int count) {
+ mLatch = new CountDownLatch(count);
mSeekPosition = -1;
mQueueItemId = -1;
mRating = null;
@@ -452,7 +869,7 @@
mQueueIndex = -1;
mQueueDescription = null;
- mOnPlayCalled = false;
+ mOnPlayCalledCount = 0;
mOnPauseCalled = false;
mOnStopCalled = false;
mOnFastForwardCalled = false;
@@ -479,242 +896,203 @@
mOnRemoveQueueItemCalled = false;
}
+ public boolean await(long timeoutMs) {
+ try {
+ return mLatch.await(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+
@Override
public void onPlay() {
- synchronized (mWaitLock) {
- mOnPlayCalled = true;
- mWaitLock.notify();
- }
+ mOnPlayCalledCount++;
+ setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
+ mLatch.countDown();
}
@Override
public void onPause() {
- synchronized (mWaitLock) {
- mOnPauseCalled = true;
- mWaitLock.notify();
- }
+ mOnPauseCalled = true;
+ setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
+ mLatch.countDown();
}
@Override
public void onStop() {
- synchronized (mWaitLock) {
- mOnStopCalled = true;
- mWaitLock.notify();
- }
+ mOnStopCalled = true;
+ setPlaybackState(PlaybackStateCompat.STATE_STOPPED);
+ mLatch.countDown();
}
@Override
public void onFastForward() {
- synchronized (mWaitLock) {
- mOnFastForwardCalled = true;
- mWaitLock.notify();
- }
+ mOnFastForwardCalled = true;
+ mLatch.countDown();
}
@Override
public void onRewind() {
- synchronized (mWaitLock) {
- mOnRewindCalled = true;
- mWaitLock.notify();
- }
+ mOnRewindCalled = true;
+ mLatch.countDown();
}
@Override
public void onSkipToPrevious() {
- synchronized (mWaitLock) {
- mOnSkipToPreviousCalled = true;
- mWaitLock.notify();
- }
+ mOnSkipToPreviousCalled = true;
+ mLatch.countDown();
}
@Override
public void onSkipToNext() {
- synchronized (mWaitLock) {
- mOnSkipToNextCalled = true;
- mWaitLock.notify();
- }
+ mOnSkipToNextCalled = true;
+ mLatch.countDown();
}
@Override
public void onSeekTo(long pos) {
- synchronized (mWaitLock) {
- mOnSeekToCalled = true;
- mSeekPosition = pos;
- mWaitLock.notify();
- }
+ mOnSeekToCalled = true;
+ mSeekPosition = pos;
+ mLatch.countDown();
}
@Override
public void onSetRating(RatingCompat rating) {
- synchronized (mWaitLock) {
- mOnSetRatingCalled = true;
- mRating = rating;
- mWaitLock.notify();
- }
+ mOnSetRatingCalled = true;
+ mRating = rating;
+ mLatch.countDown();
}
@Override
public void onPlayFromMediaId(String mediaId, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPlayFromMediaIdCalled = true;
- mMediaId = mediaId;
- mExtras = extras;
- mWaitLock.notify();
- }
+ mOnPlayFromMediaIdCalled = true;
+ mMediaId = mediaId;
+ mExtras = extras;
+ mLatch.countDown();
}
@Override
public void onPlayFromSearch(String query, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPlayFromSearchCalled = true;
- mQuery = query;
- mExtras = extras;
- mWaitLock.notify();
- }
+ mOnPlayFromSearchCalled = true;
+ mQuery = query;
+ mExtras = extras;
+ mLatch.countDown();
}
@Override
public void onPlayFromUri(Uri uri, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPlayFromUriCalled = true;
- mUri = uri;
- mExtras = extras;
- mWaitLock.notify();
- }
+ mOnPlayFromUriCalled = true;
+ mUri = uri;
+ mExtras = extras;
+ mLatch.countDown();
}
@Override
public void onCustomAction(String action, Bundle extras) {
- synchronized (mWaitLock) {
- mOnCustomActionCalled = true;
- mAction = action;
- mExtras = extras;
- mWaitLock.notify();
- }
+ mOnCustomActionCalled = true;
+ mAction = action;
+ mExtras = extras;
+ mLatch.countDown();
}
@Override
public void onSkipToQueueItem(long id) {
- synchronized (mWaitLock) {
- mOnSkipToQueueItemCalled = true;
- mQueueItemId = id;
- mWaitLock.notify();
- }
+ mOnSkipToQueueItemCalled = true;
+ mQueueItemId = id;
+ mLatch.countDown();
}
@Override
public void onCommand(String command, Bundle extras, ResultReceiver cb) {
- synchronized (mWaitLock) {
- mOnCommandCalled = true;
- mCommand = command;
- mExtras = extras;
- mCommandCallback = cb;
- mWaitLock.notify();
- }
+ mOnCommandCalled = true;
+ mCommand = command;
+ mExtras = extras;
+ mCommandCallback = cb;
+ mLatch.countDown();
}
@Override
public void onPrepare() {
- synchronized (mWaitLock) {
- mOnPrepareCalled = true;
- mWaitLock.notify();
- }
+ mOnPrepareCalled = true;
+ mLatch.countDown();
}
@Override
public void onPrepareFromMediaId(String mediaId, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPrepareFromMediaIdCalled = true;
- mMediaId = mediaId;
- mExtras = extras;
- mWaitLock.notify();
- }
+ mOnPrepareFromMediaIdCalled = true;
+ mMediaId = mediaId;
+ mExtras = extras;
+ mLatch.countDown();
}
@Override
public void onPrepareFromSearch(String query, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPrepareFromSearchCalled = true;
- mQuery = query;
- mExtras = extras;
- mWaitLock.notify();
- }
+ mOnPrepareFromSearchCalled = true;
+ mQuery = query;
+ mExtras = extras;
+ mLatch.countDown();
}
@Override
public void onPrepareFromUri(Uri uri, Bundle extras) {
- synchronized (mWaitLock) {
- mOnPrepareFromUriCalled = true;
- mUri = uri;
- mExtras = extras;
- mWaitLock.notify();
- }
+ mOnPrepareFromUriCalled = true;
+ mUri = uri;
+ mExtras = extras;
+ mLatch.countDown();
}
@Override
public void onSetRepeatMode(int repeatMode) {
- synchronized (mWaitLock) {
- mOnSetRepeatModeCalled = true;
- mRepeatMode = repeatMode;
- mWaitLock.notify();
- }
+ mOnSetRepeatModeCalled = true;
+ mRepeatMode = repeatMode;
+ mLatch.countDown();
}
@Override
public void onAddQueueItem(MediaDescriptionCompat description) {
- synchronized (mWaitLock) {
- mOnAddQueueItemCalled = true;
- mQueueDescription = description;
- mQueue.add(new MediaSessionCompat.QueueItem(description, mQueue.size()));
- mSession.setQueue(mQueue);
- mWaitLock.notify();
- }
+ mOnAddQueueItemCalled = true;
+ mQueueDescription = description;
+ mQueue.add(new MediaSessionCompat.QueueItem(description, mQueue.size()));
+ mSession.setQueue(mQueue);
+ mLatch.countDown();
}
@Override
public void onAddQueueItem(MediaDescriptionCompat description, int index) {
- synchronized (mWaitLock) {
- mOnAddQueueItemAtCalled = true;
- mQueueIndex = index;
- mQueueDescription = description;
- mQueue.add(index, new MediaSessionCompat.QueueItem(description, mQueue.size()));
- mSession.setQueue(mQueue);
- mWaitLock.notify();
- }
+ mOnAddQueueItemAtCalled = true;
+ mQueueIndex = index;
+ mQueueDescription = description;
+ mQueue.add(index, new MediaSessionCompat.QueueItem(description, mQueue.size()));
+ mSession.setQueue(mQueue);
+ mLatch.countDown();
}
@Override
public void onRemoveQueueItem(MediaDescriptionCompat description) {
- synchronized (mWaitLock) {
- mOnRemoveQueueItemCalled = true;
- String mediaId = description.getMediaId();
- for (int i = mQueue.size() - 1; i >= 0; --i) {
- if (mediaId.equals(mQueue.get(i).getDescription().getMediaId())) {
- mQueueDescription = mQueue.remove(i).getDescription();
- mSession.setQueue(mQueue);
- break;
- }
+ mOnRemoveQueueItemCalled = true;
+ String mediaId = description.getMediaId();
+ for (int i = mQueue.size() - 1; i >= 0; --i) {
+ if (mediaId.equals(mQueue.get(i).getDescription().getMediaId())) {
+ mQueueDescription = mQueue.remove(i).getDescription();
+ mSession.setQueue(mQueue);
+ break;
}
- mWaitLock.notify();
}
+ mLatch.countDown();
}
@Override
public void onSetCaptioningEnabled(boolean enabled) {
- synchronized (mWaitLock) {
- mOnSetCaptioningEnabledCalled = true;
- mCaptioningEnabled = enabled;
- mWaitLock.notify();
- }
+ mOnSetCaptioningEnabledCalled = true;
+ mCaptioningEnabled = enabled;
+ mLatch.countDown();
}
@Override
public void onSetShuffleMode(int shuffleMode) {
- synchronized (mWaitLock) {
- mOnSetShuffleModeCalled = true;
- mShuffleMode = shuffleMode;
- mWaitLock.notify();
- }
+ mOnSetShuffleModeCalled = true;
+ mShuffleMode = shuffleMode;
+ mLatch.countDown();
}
}
}
diff --git a/media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java b/media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java
index 61c33f8..7032a0b 100644
--- a/media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java
+++ b/media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java
@@ -22,16 +22,20 @@
import static android.support.mediacompat.testlib.MediaBrowserConstants.EXTRAS_VALUE;
import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_CHILDREN;
import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_CHILDREN_DELAYED;
+import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_INCLUDE_METADATA;
import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_INVALID;
import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_ID_ROOT;
+import static android.support.mediacompat.testlib.MediaBrowserConstants.MEDIA_METADATA;
import static android.support.mediacompat.testlib.MediaBrowserConstants.SEARCH_QUERY;
import static android.support.mediacompat.testlib.MediaBrowserConstants.SEARCH_QUERY_FOR_ERROR;
import static android.support.mediacompat.testlib.MediaBrowserConstants.SEARCH_QUERY_FOR_NO_RESULT;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.v4.media.MediaBrowserCompat.MediaItem;
import android.support.v4.media.MediaBrowserServiceCompat;
import android.support.v4.media.MediaDescriptionCompat;
+import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import junit.framework.Assert;
@@ -79,25 +83,43 @@
}
@Override
- public void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result) {
+ public void onLoadChildren(final String parentId, final Result<List<MediaItem>> result) {
List<MediaItem> mediaItems = new ArrayList<>();
- if (MEDIA_ID_ROOT.equals(parentMediaId)) {
+ if (MEDIA_ID_ROOT.equals(parentId)) {
Bundle rootHints = getBrowserRootHints();
for (String id : MEDIA_ID_CHILDREN) {
mediaItems.add(createMediaItem(id));
}
result.sendResult(mediaItems);
- } else if (MEDIA_ID_CHILDREN_DELAYED.equals(parentMediaId)) {
+ } else if (MEDIA_ID_CHILDREN_DELAYED.equals(parentId)) {
Assert.assertNull(mPendingLoadChildrenResult);
mPendingLoadChildrenResult = result;
mPendingRootHints = getBrowserRootHints();
result.detach();
- } else if (MEDIA_ID_INVALID.equals(parentMediaId)) {
+ } else if (MEDIA_ID_INVALID.equals(parentId)) {
result.sendResult(null);
}
}
@Override
+ public void onLoadChildren(@NonNull String parentId, @NonNull Result<List<MediaItem>> result,
+ @NonNull Bundle options) {
+ if (MEDIA_ID_INCLUDE_METADATA.equals(parentId)) {
+ // Test unparcelling the Bundle.
+ MediaMetadataCompat metadata = options.getParcelable(MEDIA_METADATA);
+ if (metadata == null) {
+ super.onLoadChildren(parentId, result, options);
+ } else {
+ List<MediaItem> mediaItems = new ArrayList<>();
+ mediaItems.add(new MediaItem(metadata.getDescription(), MediaItem.FLAG_PLAYABLE));
+ result.sendResult(mediaItems);
+ }
+ } else {
+ super.onLoadChildren(parentId, result, options);
+ }
+ }
+
+ @Override
public void onLoadItem(String itemId, Result<MediaItem> result) {
if (MEDIA_ID_CHILDREN_DELAYED.equals(itemId)) {
mPendingLoadItemResult = result;
diff --git a/media-compat/version-compat-tests/runtest.sh b/media-compat/version-compat-tests/runtest.sh
index d1a3c3a..817cd33 100755
--- a/media-compat/version-compat-tests/runtest.sh
+++ b/media-compat/version-compat-tests/runtest.sh
@@ -19,17 +19,28 @@
# - Exactly one test device should be connected.
#
# TODO:
-# - The test result should be easily seen. (Can we report the results to the Sponge?)
-# - Run specific combination of the test (e.g. Only want to test ToT-ToT)
-# - Run specific test class / method by using argument.
# - Support simultaneous multiple device connection
-# Usage './runtest.sh'
+# Usage './runtest.sh <version_combination_number> [option]'
CLIENT_MODULE_NAME_BASE="support-media-compat-test-client"
SERVICE_MODULE_NAME_BASE="support-media-compat-test-service"
CLIENT_VERSION=""
SERVICE_VERSION=""
+OPTION_TEST_TARGET=""
+
+function printRunTestUsage() {
+ echo "Usage: ./runtest.sh <version_combination_number> [option]"
+ echo ""
+ echo "Version combination number:"
+ echo " 1. Client-ToT / Service-ToT"
+ echo " 2. Client-ToT / Service-Latest release"
+ echo " 3. Client-Latest release / Service-ToT"
+ echo " 4. Run all of the above"
+ echo ""
+ echo "Option:"
+ echo " -t <class/method>: Only run the specific test class/method."
+}
function runTest() {
echo "Running test: Client-$CLIENT_VERSION / Service-$SERVICE_VERSION"
@@ -38,42 +49,59 @@
local SERVICE_MODULE_NAME="$SERVICE_MODULE_NAME_BASE$([ "$SERVICE_VERSION" = "tot" ] || echo "-previous")"
# Build test apks
- ./gradlew $CLIENT_MODULE_NAME:assembleDebugAndroidTest || (echo "Build failed. Aborting."; return 1)
- ./gradlew $SERVICE_MODULE_NAME:assembleDebugAndroidTest || (echo "Build failed. Aborting."; return 1)
+ ./gradlew $CLIENT_MODULE_NAME:assembleDebugAndroidTest || { echo "Build failed. Aborting."; exit 1; }
+ ./gradlew $SERVICE_MODULE_NAME:assembleDebugAndroidTest || { echo "Build failed. Aborting."; exit 1; }
# Install the apks
- adb install -r -d "../../out/dist/$CLIENT_MODULE_NAME.apk" || (echo "Apk installation failed. Aborting."; return 1)
- adb install -r -d "../../out/dist/$SERVICE_MODULE_NAME.apk" || (echo "Apk installation failed. Aborting."; return 1)
+ adb install -r -d "../../out/dist/$CLIENT_MODULE_NAME.apk" || { echo "Apk installation failed. Aborting."; exit 1; }
+ adb install -r -d "../../out/dist/$SERVICE_MODULE_NAME.apk" || { echo "Apk installation failed. Aborting."; exit 1; }
# Run the tests
+ local test_command="adb shell am instrument -w -e debug false -e client_version $CLIENT_VERSION -e service_version $SERVICE_VERSION"
+ local client_test_runner="android.support.mediacompat.client.test/android.support.test.runner.AndroidJUnitRunner"
+ local service_test_runner="android.support.mediacompat.service.test/android.support.test.runner.AndroidJUnitRunner"
+
echo ">>>>>>>>>>>>>>>>>>>>>>>> Test Started: Client-$CLIENT_VERSION & Service-$SERVICE_VERSION <<<<<<<<<<<<<<<<<<<<<<<<"
- adb shell am instrument -w -r -e package android.support.mediacompat.client -e debug false -e client_version $CLIENT_VERSION \
- -e service_version $SERVICE_VERSION android.support.mediacompat.client.test/android.support.test.runner.AndroidJUnitRunner
- adb shell am instrument -w -r -e package android.support.mediacompat.service -e debug false -e client_version $CLIENT_VERSION \
- -e service_version $SERVICE_VERSION android.support.mediacompat.service.test/android.support.test.runner.AndroidJUnitRunner
+
+ if [[ $OPTION_TEST_TARGET == *"client"* ]]; then
+ ${test_command} $OPTION_TEST_TARGET ${client_test_runner}
+ elif [[ $OPTION_TEST_TARGET == *"service"* ]]; then
+ ${test_command} $OPTION_TEST_TARGET ${service_test_runner}
+ else
+ ${test_command} ${client_test_runner}
+ ${test_command} ${service_test_runner}
+ fi
+
echo ">>>>>>>>>>>>>>>>>>>>>>>> Test Ended: Client-$CLIENT_VERSION & Service-$SERVICE_VERSION <<<<<<<<<<<<<<<<<<<<<<<<<<"
}
OLD_PWD=$(pwd)
-if [[ $OLD_PWD != *"frameworks/support"* ]]; then
- echo "Current working directory is" $OLD_PWD.
+
+if ! cd "$(echo $OLD_PWD | awk -F'frameworks/support' '{print $1}')"/frameworks/support &> /dev/null
+then
+ echo "Current working directory is $OLD_PWD"
echo "Please re-run this script in any folder under frameworks/support."
exit 1;
-else
- # Change working directory to frameworks/support
- cd "$(echo $OLD_PWD | awk -F'frameworks/support' '{print $1}')"/frameworks/support
fi
-echo "Choose the support library versions of the test you want to run:"
-echo " 1. Client-ToT / Service-ToT"
-echo " 2. Client-ToT / Service-Latest release"
-echo " 3. Client-Latest release / Service-ToT"
-echo " 4. Run all of the above"
-printf "Pick one of them: "
+if [[ $# -eq 0 || $1 -le 0 || $1 -gt 4 ]]
+then
+ printRunTestUsage
+ exit 1;
+fi
-read ANSWER
-case $ANSWER in
+if [[ ${2} == "-t" ]]; then
+ if [[ ${3} == *"client"* || ${3} == *"service"* ]]; then
+ OPTION_TEST_TARGET="-e class ${3}"
+ else
+ echo "Wrong test class/method name. Aborting."
+ echo "It should be in the form of \"<FULL_CLASS_NAME>[#METHOD_NAME]\"."
+ exit 1;
+ fi
+fi
+
+case ${1} in
1)
CLIENT_VERSION="tot"
SERVICE_VERSION="tot"
diff --git a/paging/common/build.gradle b/paging/common/build.gradle
index d07103f..fc9964e 100644
--- a/paging/common/build.gradle
+++ b/paging/common/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
import android.support.SupportLibraryExtension;
@@ -25,18 +26,13 @@
dependencies {
compile libs.support.annotations
- compile project(":arch:common")
+ compile(project(":arch:common"))
- testCompile libs.junit
- testCompile libs.mockito_core
- compile libs.support.annotations
- compile project(path: ':arch:common')
- testCompile libs.kotlin.stdlib
+ testCompile(JUNIT)
+ testCompile(MOCKITO_CORE)
+ testCompile(KOTLIN_STDLIB)
}
-createAndroidCheckstyle(project)
-createKotlinCheckstyle(project)
-
supportLibrary {
name = "Android Paging-Common"
publish = true
diff --git a/paging/common/src/main/java/android/arch/paging/ContiguousDataSource.java b/paging/common/src/main/java/android/arch/paging/ContiguousDataSource.java
index 03f2e86..b2e389f 100644
--- a/paging/common/src/main/java/android/arch/paging/ContiguousDataSource.java
+++ b/paging/common/src/main/java/android/arch/paging/ContiguousDataSource.java
@@ -19,21 +19,35 @@
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import java.util.concurrent.Executor;
+
abstract class ContiguousDataSource<Key, Value> extends DataSource<Key, Value> {
@Override
boolean isContiguous() {
return true;
}
- public abstract void loadInitial(@Nullable Key key, int initialLoadSize,
+ abstract void dispatchLoadInitial(
+ @Nullable Key key,
+ int initialLoadSize,
+ int pageSize,
boolean enablePlaceholders,
- @NonNull InitialLoadCallback<Value> callback);
+ @NonNull Executor mainThreadExecutor,
+ @NonNull PageResult.Receiver<Value> receiver);
- abstract void loadAfter(int currentEndIndex, @NonNull Value currentEndItem, int pageSize,
- @NonNull LoadCallback<Value> callback);
+ abstract void dispatchLoadAfter(
+ int currentEndIndex,
+ @NonNull Value currentEndItem,
+ int pageSize,
+ @NonNull Executor mainThreadExecutor,
+ @NonNull PageResult.Receiver<Value> receiver);
- abstract void loadBefore(int currentBeginIndex, @NonNull Value currentBeginItem, int pageSize,
- @NonNull LoadCallback<Value> callback);
+ abstract void dispatchLoadBefore(
+ int currentBeginIndex,
+ @NonNull Value currentBeginItem,
+ int pageSize,
+ @NonNull Executor mainThreadExecutor,
+ @NonNull PageResult.Receiver<Value> receiver);
/**
* Get the key from either the position, or item, or null if position/item invalid.
diff --git a/paging/common/src/main/java/android/arch/paging/ContiguousPagedList.java b/paging/common/src/main/java/android/arch/paging/ContiguousPagedList.java
index 302263d..42eb320 100644
--- a/paging/common/src/main/java/android/arch/paging/ContiguousPagedList.java
+++ b/paging/common/src/main/java/android/arch/paging/ContiguousPagedList.java
@@ -53,11 +53,6 @@
if (resultType == PageResult.INIT) {
mStorage.init(pageResult.leadingNulls, page, pageResult.trailingNulls,
pageResult.positionOffset, ContiguousPagedList.this);
-
- // notifyInserted is safe here, since if we're not on main thread, we won't have any
- // Callbacks registered to listen to the notify.
- notifyInserted(0, mStorage.size());
-
mLastLoad = pageResult.leadingNulls + pageResult.positionOffset + page.size() / 2;
} else if (resultType == PageResult.APPEND) {
mStorage.appendPage(page, ContiguousPagedList.this);
@@ -92,21 +87,12 @@
if (mDataSource.isInvalid()) {
detach();
} else {
- @DataSource.LoadCountType int type = mConfig.enablePlaceholders
- ? DataSource.LOAD_COUNT_ACCEPTED
- : DataSource.LOAD_COUNT_PREVENTED;
-
- DataSource.InitialLoadCallback<V> callback = new DataSource.InitialLoadCallback<>(
- type, mConfig.pageSize, mDataSource, mReceiver);
- mDataSource.loadInitial(key,
+ mDataSource.dispatchLoadInitial(key,
mConfig.initialLoadSizeHint,
+ mConfig.pageSize,
mConfig.enablePlaceholders,
- callback);
-
- // If initialLoad's callback is not called within the body, we force any following calls
- // to post to the UI thread. This constructor may be run on a background thread, but
- // after constructor, mutation must happen on UI thread.
- callback.setPostExecutor(mMainThreadExecutor);
+ mMainThreadExecutor,
+ mReceiver);
}
}
@@ -198,9 +184,8 @@
if (mDataSource.isInvalid()) {
detach();
} else {
- DataSource.LoadCallback<V> callback = new DataSource.LoadCallback<>(
- PageResult.PREPEND, mMainThreadExecutor, mDataSource, mReceiver);
- mDataSource.loadBefore(position, item, mConfig.pageSize, callback);
+ mDataSource.dispatchLoadBefore(position, item, mConfig.pageSize,
+ mMainThreadExecutor, mReceiver);
}
}
@@ -228,9 +213,8 @@
if (mDataSource.isInvalid()) {
detach();
} else {
- DataSource.LoadCallback<V> callback = new DataSource.LoadCallback<>(
- PageResult.APPEND, mMainThreadExecutor, mDataSource, mReceiver);
- mDataSource.loadAfter(position, item, mConfig.pageSize, callback);
+ mDataSource.dispatchLoadAfter(position, item, mConfig.pageSize,
+ mMainThreadExecutor, mReceiver);
}
}
});
diff --git a/paging/common/src/main/java/android/arch/paging/DataSource.java b/paging/common/src/main/java/android/arch/paging/DataSource.java
index 2e41cf6..bbf7ccb 100644
--- a/paging/common/src/main/java/android/arch/paging/DataSource.java
+++ b/paging/common/src/main/java/android/arch/paging/DataSource.java
@@ -16,14 +16,11 @@
package android.arch.paging;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
import android.support.annotation.AnyThread;
-import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
-import java.lang.annotation.Retention;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
@@ -33,11 +30,8 @@
* Base class for loading pages of snapshot data into a {@link PagedList}.
* <p>
* DataSource is queried to load pages of content into a {@link PagedList}. A PagedList can grow as
- * it loads more data, but the data loaded cannot be updated.
- * <p>
- * A PagedList / DataSource pair serve as a snapshot of the data set being loaded. If the
- * underlying data set is modified, a new PagedList / DataSource pair must be created to represent
- * the new data.
+ * it loads more data, but the data loaded cannot be updated. If the underlying data set is
+ * modified, a new PagedList / DataSource pair must be created to represent the new data.
* <h4>Loading Pages</h4>
* PagedList queries data from its DataSource in response to loading hints. {@link PagedListAdapter}
* calls {@link PagedList#loadAround(int)} to load content as the user scrolls in a RecyclerView.
@@ -71,18 +65,23 @@
* copy changes, invalidate the previous DataSource, and a new one wrapping the new state of the
* snapshot can be created.
* <h4>Implementing a DataSource</h4>
- * To implement, extend either the {@link KeyedDataSource}, or {@link PositionalDataSource}
- * subclass. Choose based on whether each load operation is based on the position of the data in the
- * list.
+ * To implement, extend one of the subclasses: {@link PageKeyedDataSource},
+ * {@link ItemKeyedDataSource}, or {@link PositionalDataSource}.
* <p>
- * Use {@link KeyedDataSource} if you need to use data from item {@code N-1} to load item
+ * Use {@link PageKeyedDataSource} if pages you load embed keys for loading adjacent pages. For
+ * example a network response that returns some items, and a next/previous page links.
+ * <p>
+ * Use {@link ItemKeyedDataSource} if you need to use data from item {@code N-1} to load item
* {@code N}. For example, if requesting the backend for the next comments in the list
* requires the ID or timestamp of the most recent loaded comment, or if querying the next users
* from a name-sorted database query requires the name and unique ID of the previous.
* <p>
- * Use {@link PositionalDataSource} if you can load arbitrary pages based solely on position
- * information, and can provide a fixed item count. PositionalDataSource supports querying pages at
- * arbitrary positions, so can provide data to PagedLists in arbitrary order.
+ * Use {@link PositionalDataSource} if you can load pages of a requested size at arbitrary
+ * positions, and provide a fixed item count. PositionalDataSource supports querying pages at
+ * arbitrary positions, so can provide data to PagedLists in arbitrary order. Note that
+ * PositionalDataSource is required to respect page size for efficient tiling. If you want to
+ * override page size (e.g. when network page size constraints are only known at runtime), use one
+ * of the other DataSource classes.
* <p>
* Because a {@code null} item indicates a placeholder in {@link PagedList}, DataSource may not
* return {@code null} items in lists that it loads. This is so that users of the PagedList
@@ -118,8 +117,13 @@
/**
* Create a DataSource.
* <p>
- * The DataSource should invalidate itself if the snapshot is no longer valid, and a new
- * DataSource should be queried from the Factory.
+ * The DataSource should invalidate itself if the snapshot is no longer valid. If a
+ * DataSource becomes invalid, the only way to query more data is to create a new DataSource
+ * from the Factory.
+ * <p>
+ * {@link LivePagedListBuilder} for example will construct a new PagedList and DataSource
+ * when the current DataSource is invalidated, and pass the new PagedList through the
+ * {@code LiveData<PagedList>} to observers.
*
* @return the new DataSource.
*/
@@ -137,150 +141,39 @@
*/
abstract boolean isContiguous();
- /**
- * Callback for DataSource initial loading methods to return data and position/count
- * information.
- * <p>
- * A callback can be called only once, and will throw if called again.
- * <p>
- * It is always valid for a DataSource loading method that takes a callback to stash the
- * callback and call it later. This enables DataSources to be fully asynchronous, and to handle
- * temporary, recoverable error states (such as a network error that can be retried).
- *
- * @param <T> Type of items being loaded.
- */
- public static class InitialLoadCallback<T> extends LoadCallback<T> {
- private final int mPageSize;
-
- InitialLoadCallback(@LoadCountType int countType, int pageSize,
- DataSource dataSource, PageResult.Receiver<T> receiver) {
- super(PageResult.INIT, countType, dataSource, receiver);
- mPageSize = pageSize;
- if (mPageSize < 1) {
- throw new IllegalArgumentException("Page size must be non-negative");
- }
- }
-
- /**
- * Called to pass initial load state from a DataSource.
- * <p>
- * Call this method from your DataSource's {@code loadInitial} function to return data,
- * and inform how many placeholders should be shown before and after. If counting is cheap
- * to compute (for example, if a network load returns the information regardless), it's
- * recommended to pass data back through this method.
- *
- * @param data List of items loaded from the DataSource. If this is empty, the DataSource
- * is treated as empty, and no further loads will occur.
- * @param position Position of the item at the front of the list, relative to the total
- * count. If there are {@code N} items before the items in data that can be
- * loaded from this DataSource, pass {@code N}.
- * @param totalCount Total number of items that may be returned from this DataSource.
- * Includes the number in the initial {@code data} parameter
- * as well as any items that can be loaded in front or behind of
- * {@code data}.
- */
- public void onResult(@NonNull List<T> data, int position, int totalCount) {
+ static class BaseLoadCallback<T> {
+ static void validateInitialLoadParams(@NonNull List<?> data, int position, int totalCount) {
if (position < 0) {
throw new IllegalArgumentException("Position must be non-negative");
}
if (data.size() + position > totalCount) {
throw new IllegalArgumentException(
- "List size + position too large; last item in list beyond totalCount");
+ "List size + position too large, last item in list beyond totalCount.");
}
if (data.size() == 0 && totalCount > 0) {
throw new IllegalArgumentException(
"Initial result cannot be empty if items are present in data set.");
}
- if (mCountType == LOAD_COUNT_REQUIRED_TILED
- && position + data.size() != totalCount
- && data.size() % mPageSize != 0) {
- throw new IllegalArgumentException("PositionalDataSource requires initial load size"
- + " to be a multiple of page size to support internal tiling.");
- }
-
- int trailingUnloadedCount = totalCount - position - data.size();
- if (mCountType == LOAD_COUNT_REQUIRED_TILED || mCountType == LOAD_COUNT_ACCEPTED) {
- dispatchResultToReceiver(new PageResult<>(
- data, position, trailingUnloadedCount, 0));
- } else {
- dispatchResultToReceiver(new PageResult<>(data, position));
- }
}
- /**
- * Called to pass initial load state from a DataSource without supporting placeholders.
- * <p>
- * Call this method from your DataSource's {@code loadInitial} function to return data,
- * if position is known but total size is not. If counting is not expensive, consider
- * calling the three parameter variant: {@link #onResult(List, int, int)}.
- *
- * @param data List of items loaded from the DataSource. If this is empty, the DataSource
- * is treated as empty, and no further loads will occur.
- * @param position Position of the item at the front of the list. If there are {@code N}
- * items before the items in data that can be provided by this DataSource,
- * pass {@code N}.
- */
- void onResult(@NonNull List<T> data, int position) {
- // not counting, don't need to check mAcceptCount
- dispatchResultToReceiver(new PageResult<>(
- data, 0, 0, position));
- }
- }
-
- @Retention(SOURCE)
- @IntDef({LOAD_COUNT_PREVENTED, LOAD_COUNT_ACCEPTED, LOAD_COUNT_REQUIRED_TILED})
- @interface LoadCountType {}
- static final int LOAD_COUNT_PREVENTED = 0;
- static final int LOAD_COUNT_ACCEPTED = 1;
- static final int LOAD_COUNT_REQUIRED_TILED = 2;
-
- /**
- * Callback for DataSource loading methods to return data.
- * <p>
- * A callback can be called only once, and will throw if called again.
- * <p>
- * It is always valid for a DataSource loading method that takes a callback to stash the
- * callback and call it later. This enables DataSources to be fully asynchronous, and to handle
- * temporary, recoverable error states (such as a network error that can be retried).
- *
- * @param <T> Type of items being loaded.
- */
- public static class LoadCallback<T> {
@PageResult.ResultType
final int mResultType;
- @LoadCountType
- final int mCountType;
private final DataSource mDataSource;
private final PageResult.Receiver<T> mReceiver;
- private int mPositionOffset = 0;
-
// mSignalLock protects mPostExecutor, and mHasSignalled
private final Object mSignalLock = new Object();
private Executor mPostExecutor = null;
private boolean mHasSignalled = false;
- private LoadCallback(@PageResult.ResultType int resultType, @LoadCountType int countType,
- DataSource dataSource, PageResult.Receiver<T> receiver) {
+ BaseLoadCallback(@NonNull DataSource dataSource, @PageResult.ResultType int resultType,
+ @Nullable Executor mainThreadExecutor, @NonNull PageResult.Receiver<T> receiver) {
+ mDataSource = dataSource;
mResultType = resultType;
- mCountType = countType;
- mDataSource = dataSource;
- mReceiver = receiver;
- }
-
- LoadCallback(int type, Executor mainThreadExecutor,
- DataSource dataSource, PageResult.Receiver<T> receiver) {
- mResultType = type;
- mCountType = LOAD_COUNT_PREVENTED;
mPostExecutor = mainThreadExecutor;
- mDataSource = dataSource;
mReceiver = receiver;
}
- void setPositionOffset(int positionOffset) {
- mPositionOffset = positionOffset;
- }
-
void setPostExecutor(Executor postExecutor) {
synchronized (mSignalLock) {
mPostExecutor = postExecutor;
@@ -288,20 +181,16 @@
}
/**
- * Called to pass loaded data from a DataSource.
- * <p>
- * Call this method from your DataSource's {@code load} methods to return data.
+ * Call before verifying args, or dispatching actul results
*
- * @param data List of items loaded from the DataSource.
+ * @return true if DataSource was invalid, and invalid result dispatched
*/
- public void onResult(@NonNull List<T> data) {
- if (mCountType == LOAD_COUNT_REQUIRED_TILED && !data.isEmpty()) {
- throw new IllegalArgumentException(
- "PositionalDataSource requires calling the three argument version of"
- + " InitialLoadCallback.onResult() to pass position information");
+ boolean dispatchInvalidResultIfInvalid() {
+ if (mDataSource.isInvalid()) {
+ dispatchResultToReceiver(PageResult.<T>getInvalidResult());
+ return true;
}
- dispatchResultToReceiver(new PageResult<>(
- data, 0, 0, mPositionOffset));
+ return false;
}
void dispatchResultToReceiver(final @NonNull PageResult<T> result) {
@@ -309,15 +198,12 @@
synchronized (mSignalLock) {
if (mHasSignalled) {
throw new IllegalStateException(
- "LoadCallback already dispatched, cannot dispatch again.");
+ "callback.onResult already called, cannot call again.");
}
mHasSignalled = true;
executor = mPostExecutor;
}
- final PageResult<T> resolvedResult =
- mDataSource.isInvalid() ? PageResult.<T>getInvalidResult() : result;
-
if (executor != null) {
executor.execute(new Runnable() {
@Override
diff --git a/paging/common/src/main/java/android/arch/paging/ItemKeyedDataSource.java b/paging/common/src/main/java/android/arch/paging/ItemKeyedDataSource.java
new file mode 100644
index 0000000..cb8247b
--- /dev/null
+++ b/paging/common/src/main/java/android/arch/paging/ItemKeyedDataSource.java
@@ -0,0 +1,337 @@
+/*
+ * 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 android.arch.paging;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Incremental data loader for paging keyed content, where loaded content uses previously loaded
+ * items as input to future loads.
+ * <p>
+ * Implement a DataSource using ItemKeyedDataSource if you need to use data from item {@code N - 1}
+ * to load item {@code N}. This is common, for example, in sorted database queries where
+ * attributes of the item such just before the next query define how to execute it.
+ * <p>
+ * The {@code InMemoryByItemRepository} in the
+ * <a href="https://github.com/googlesamples/android-architecture-components/blob/master/PagingWithNetworkSample/README.md">PagingWithNetworkSample</a>
+ * shows how to implement a network ItemKeyedDataSource using
+ * <a href="https://square.github.io/retrofit/">Retrofit</a>, while
+ * handling swipe-to-refresh, network errors, and retry.
+ *
+ * @param <Key> Type of data used to query Value types out of the DataSource.
+ * @param <Value> Type of items being loaded by the DataSource.
+ */
+public abstract class ItemKeyedDataSource<Key, Value> extends ContiguousDataSource<Key, Value> {
+
+ /**
+ * Holder object for inputs to {@link #loadInitial(LoadInitialParams, LoadInitialCallback)}.
+ *
+ * @param <Key> Type of data used to query Value types out of the DataSource.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public static class LoadInitialParams<Key> {
+ /**
+ * Load items around this key, or at the beginning of the data set if {@code null} is
+ * passed.
+ * <p>
+ * Note that this key is generally a hint, and may be ignored if you want to always load
+ * from the beginning.
+ */
+ @Nullable
+ public final Key requestedInitialKey;
+
+ /**
+ * Requested number of items to load.
+ * <p>
+ * Note that this may be larger than available data.
+ */
+ public final int requestedLoadSize;
+
+ /**
+ * Defines whether placeholders are enabled, and whether the total count passed to
+ * {@link LoadInitialCallback#onResult(List, int, int)} will be ignored.
+ */
+ public final boolean placeholdersEnabled;
+
+
+ LoadInitialParams(@Nullable Key requestedInitialKey, int requestedLoadSize,
+ boolean placeholdersEnabled) {
+ this.requestedInitialKey = requestedInitialKey;
+ this.requestedLoadSize = requestedLoadSize;
+ this.placeholdersEnabled = placeholdersEnabled;
+ }
+ }
+
+ /**
+ * Holder object for inputs to {@link #loadBefore(LoadParams, LoadCallback)}
+ * and {@link #loadAfter(LoadParams, LoadCallback)}.
+ *
+ * @param <Key> Type of data used to query Value types out of the DataSource.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public static class LoadParams<Key> {
+ /**
+ * Load items before/after this key.
+ * <p>
+ * Returned data must begin directly adjacent to this position.
+ */
+ public final Key key;
+ /**
+ * Requested number of items to load.
+ * <p>
+ * Returned page can be of this size, but it may be altered if that is easier, e.g. a
+ * network data source where the backend defines page size.
+ */
+ public final int requestedLoadSize;
+
+ LoadParams(Key key, int requestedLoadSize) {
+ this.key = key;
+ this.requestedLoadSize = requestedLoadSize;
+ }
+ }
+
+ /**
+ * Callback for {@link #loadInitial(LoadInitialParams, LoadInitialCallback)}
+ * to return data and, optionally, position/count information.
+ * <p>
+ * A callback can be called only once, and will throw if called again.
+ * <p>
+ * If you can compute the number of items in the data set before and after the loaded range,
+ * call the three parameter {@link #onResult(List, int, int)} to pass that information. You
+ * can skip passing this information by calling the single parameter {@link #onResult(List)},
+ * either if it's difficult to compute, or if {@link LoadInitialParams#placeholdersEnabled} is
+ * {@code false}, so the positioning information will be ignored.
+ * <p>
+ * It is always valid for a DataSource loading method that takes a callback to stash the
+ * callback and call it later. This enables DataSources to be fully asynchronous, and to handle
+ * temporary, recoverable error states (such as a network error that can be retried).
+ *
+ * @param <Value> Type of items being loaded.
+ */
+ public static class LoadInitialCallback<Value> extends LoadCallback<Value> {
+ private final boolean mCountingEnabled;
+ LoadInitialCallback(@NonNull ItemKeyedDataSource dataSource, boolean countingEnabled,
+ @NonNull PageResult.Receiver<Value> receiver) {
+ super(dataSource, PageResult.INIT, null, receiver);
+ mCountingEnabled = countingEnabled;
+ }
+
+ /**
+ * Called to pass initial load state from a DataSource.
+ * <p>
+ * Call this method from your DataSource's {@code loadInitial} function to return data,
+ * and inform how many placeholders should be shown before and after. If counting is cheap
+ * to compute (for example, if a network load returns the information regardless), it's
+ * recommended to pass data back through this method.
+ * <p>
+ * It is always valid to pass a different amount of data than what is requested. Pass an
+ * empty list if there is no more data to load.
+ *
+ * @param data List of items loaded from the DataSource. If this is empty, the DataSource
+ * is treated as empty, and no further loads will occur.
+ * @param position Position of the item at the front of the list. If there are {@code N}
+ * items before the items in data that can be loaded from this DataSource,
+ * pass {@code N}.
+ * @param totalCount Total number of items that may be returned from this DataSource.
+ * Includes the number in the initial {@code data} parameter
+ * as well as any items that can be loaded in front or behind of
+ * {@code data}.
+ */
+ public void onResult(@NonNull List<Value> data, int position, int totalCount) {
+ if (!dispatchInvalidResultIfInvalid()) {
+ validateInitialLoadParams(data, position, totalCount);
+
+ int trailingUnloadedCount = totalCount - position - data.size();
+ if (mCountingEnabled) {
+ dispatchResultToReceiver(new PageResult<>(
+ data, position, trailingUnloadedCount, 0));
+ } else {
+ dispatchResultToReceiver(new PageResult<>(data, position));
+ }
+ }
+ }
+ }
+
+ /**
+ * Callback for ItemKeyedDataSource {@link #loadBefore(LoadParams, LoadCallback)}
+ * and {@link #loadAfter(LoadParams, LoadCallback)} to return data.
+ * <p>
+ * A callback can be called only once, and will throw if called again.
+ * <p>
+ * It is always valid for a DataSource loading method that takes a callback to stash the
+ * callback and call it later. This enables DataSources to be fully asynchronous, and to handle
+ * temporary, recoverable error states (such as a network error that can be retried).
+ *
+ * @param <Value> Type of items being loaded.
+ */
+ public static class LoadCallback<Value> extends BaseLoadCallback<Value> {
+ LoadCallback(@NonNull ItemKeyedDataSource dataSource, @PageResult.ResultType int type,
+ @Nullable Executor mainThreadExecutor,
+ @NonNull PageResult.Receiver<Value> receiver) {
+ super(dataSource, type, mainThreadExecutor, receiver);
+ }
+
+ /**
+ * Called to pass loaded data from a DataSource.
+ * <p>
+ * Call this method from your ItemKeyedDataSource's
+ * {@link #loadBefore(LoadParams, LoadCallback)} and
+ * {@link #loadAfter(LoadParams, LoadCallback)} methods to return data.
+ * <p>
+ * Call this from {@link #loadInitial(LoadInitialParams, LoadInitialCallback)} to
+ * initialize without counting available data, or supporting placeholders.
+ * <p>
+ * It is always valid to pass a different amount of data than what is requested. Pass an
+ * empty list if there is no more data to load.
+ *
+ * @param data List of items loaded from the ItemKeyedDataSource.
+ */
+ public void onResult(@NonNull List<Value> data) {
+ if (!dispatchInvalidResultIfInvalid()) {
+ dispatchResultToReceiver(new PageResult<>(data, 0, 0, 0));
+ }
+ }
+ }
+
+ @Nullable
+ @Override
+ final Key getKey(int position, Value item) {
+ if (item == null) {
+ return null;
+ }
+
+ return getKey(item);
+ }
+
+ @Override
+ final void dispatchLoadInitial(@Nullable Key key, int initialLoadSize, int pageSize,
+ boolean enablePlaceholders, @NonNull Executor mainThreadExecutor,
+ @NonNull PageResult.Receiver<Value> receiver) {
+ LoadInitialCallback<Value> callback =
+ new LoadInitialCallback<>(this, enablePlaceholders, receiver);
+ loadInitial(new LoadInitialParams<>(key, initialLoadSize, enablePlaceholders), callback);
+
+ // If initialLoad's callback is not called within the body, we force any following calls
+ // to post to the UI thread. This constructor may be run on a background thread, but
+ // after constructor, mutation must happen on UI thread.
+ callback.setPostExecutor(mainThreadExecutor);
+ }
+
+ @Override
+ final void dispatchLoadAfter(int currentEndIndex, @NonNull Value currentEndItem,
+ int pageSize, @NonNull Executor mainThreadExecutor,
+ @NonNull PageResult.Receiver<Value> receiver) {
+ loadAfter(new LoadParams<>(getKey(currentEndItem), pageSize),
+ new LoadCallback<>(this, PageResult.APPEND, mainThreadExecutor, receiver));
+ }
+
+ @Override
+ final void dispatchLoadBefore(int currentBeginIndex, @NonNull Value currentBeginItem,
+ int pageSize, @NonNull Executor mainThreadExecutor,
+ @NonNull PageResult.Receiver<Value> receiver) {
+ loadBefore(new LoadParams<>(getKey(currentBeginItem), pageSize),
+ new LoadCallback<>(this, PageResult.PREPEND, mainThreadExecutor, receiver));
+ }
+
+ /**
+ * Load initial data.
+ * <p>
+ * This method is called first to initialize a PagedList with data. If it's possible to count
+ * the items that can be loaded by the DataSource, it's recommended to pass the loaded data to
+ * the callback via the three-parameter
+ * {@link LoadInitialCallback#onResult(List, int, int)}. This enables PagedLists
+ * presenting data from this source to display placeholders to represent unloaded items.
+ * <p>
+ * {@link LoadInitialParams#requestedInitialKey} and {@link LoadInitialParams#requestedLoadSize}
+ * are hints, not requirements, so they may be altered or ignored. Note that ignoring the
+ * {@code requestedInitialKey} can prevent subsequent PagedList/DataSource pairs from
+ * initializing at the same location. If your data source never invalidates (for example,
+ * loading from the network without the network ever signalling that old data must be reloaded),
+ * it's fine to ignore the {@code initialLoadKey} and always start from the beginning of the
+ * data set.
+ *
+ * @param params Parameters for initial load, including initial key and requested size.
+ * @param callback Callback that receives initial load data.
+ */
+ public abstract void loadInitial(@NonNull LoadInitialParams<Key> params,
+ @NonNull LoadInitialCallback<Value> callback);
+
+ /**
+ * Load list data after the key specified in {@link LoadParams#key LoadParams.key}.
+ * <p>
+ * It's valid to return a different list size than the page size if it's easier, e.g. if your
+ * backend defines page sizes. It is generally safer to increase the number loaded than reduce.
+ * <p>
+ * Data may be passed synchronously during the loadAfter method, or deferred and called at a
+ * later time. Further loads going down will be blocked until the callback is called.
+ * <p>
+ * If data cannot be loaded (for example, if the request is invalid, or the data would be stale
+ * and inconsistent, it is valid to call {@link #invalidate()} to invalidate the data source,
+ * and prevent further loading.
+ *
+ * @param params Parameters for the load, including the key to load after, and requested size.
+ * @param callback Callback that receives loaded data.
+ */
+ public abstract void loadAfter(@NonNull LoadParams<Key> params,
+ @NonNull LoadCallback<Value> callback);
+
+ /**
+ * Load list data before the key specified in {@link LoadParams#key LoadParams.key}.
+ * <p>
+ * It's valid to return a different list size than the page size if it's easier, e.g. if your
+ * backend defines page sizes. It is generally safer to increase the number loaded than reduce.
+ * <p>
+ * <p class="note"><strong>Note:</strong> Data returned will be prepended just before the key
+ * passed, so if you vary size, ensure that the last item is adjacent to the passed key.
+ * <p>
+ * Data may be passed synchronously during the loadBefore method, or deferred and called at a
+ * later time. Further loads going up will be blocked until the callback is called.
+ * <p>
+ * If data cannot be loaded (for example, if the request is invalid, or the data would be stale
+ * and inconsistent, it is valid to call {@link #invalidate()} to invalidate the data source,
+ * and prevent further loading.
+ *
+ * @param params Parameters for the load, including the key to load before, and requested size.
+ * @param callback Callback that receives loaded data.
+ */
+ public abstract void loadBefore(@NonNull LoadParams<Key> params,
+ @NonNull LoadCallback<Value> callback);
+
+ /**
+ * Return a key associated with the given item.
+ * <p>
+ * If your ItemKeyedDataSource is loading from a source that is sorted and loaded by a unique
+ * integer ID, you would return {@code item.getID()} here. This key can then be passed to
+ * {@link #loadBefore(LoadParams, LoadCallback)} or
+ * {@link #loadAfter(LoadParams, LoadCallback)} to load additional items adjacent to the item
+ * passed to this function.
+ * <p>
+ * If your key is more complex, such as when you're sorting by name, then resolving collisions
+ * with integer ID, you'll need to return both. In such a case you would use a wrapper class,
+ * such as {@code Pair<String, Integer>} or, in Kotlin,
+ * {@code data class Key(val name: String, val id: Int)}
+ *
+ * @param item Item to get the key from.
+ * @return Key associated with given item.
+ */
+ @NonNull
+ public abstract Key getKey(@NonNull Value item);
+}
diff --git a/paging/common/src/main/java/android/arch/paging/KeyedDataSource.java b/paging/common/src/main/java/android/arch/paging/KeyedDataSource.java
deleted file mode 100644
index b6656f3..0000000
--- a/paging/common/src/main/java/android/arch/paging/KeyedDataSource.java
+++ /dev/null
@@ -1,151 +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 android.arch.paging;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import java.util.List;
-/**
- * Incremental data loader for paging keyed content, where loaded content uses previously loaded
- * items as input to future loads.
- * <p>
- * Implement a DataSource using KeyedDataSource if you need to use data from item {@code N - 1}
- * to load item {@code N}. This is common, for example, in sorted database queries where
- * attributes of the item such just before the next query define how to execute it.
- *
- * @param <Key> Type of data used to query Value types out of the DataSource.
- * @param <Value> Type of items being loaded by the DataSource.
- */
-public abstract class KeyedDataSource<Key, Value> extends ContiguousDataSource<Key, Value> {
- @Override
- final void loadAfter(int currentEndIndex, @NonNull Value currentEndItem, int pageSize,
- @NonNull LoadCallback<Value> callback) {
- loadAfter(getKey(currentEndItem), pageSize, callback);
- }
-
- @Override
- final void loadBefore(int currentBeginIndex, @NonNull Value currentBeginItem, int pageSize,
- @NonNull LoadCallback<Value> callback) {
- loadBefore(getKey(currentBeginItem), pageSize, callback);
- }
-
- @Nullable
- @Override
- final Key getKey(int position, Value item) {
- if (item == null) {
- return null;
- }
-
- return getKey(item);
- }
-
-
- /**
- * Load initial data.
- * <p>
- * This method is called first to initialize a PagedList with data. If it's possible to count
- * the items that can be loaded by the DataSource, it's recommended to pass the loaded data to
- * the callback via the three-parameter
- * {@link DataSource.InitialLoadCallback#onResult(List, int, int)}. This enables PagedLists
- * presenting data from this source to display placeholders to represent unloaded items.
- * <p>
- * {@code initialLoadKey} and {@code requestedLoadSize} are hints, not requirements, so if it is
- * difficult or impossible to respect them, they may be altered. Note that ignoring the
- * {@code initialLoadKey} can prevent subsequent PagedList/DataSource pairs from initializing at
- * the same location. If your data source never invalidates (for example, loading from the
- * network without the network ever signalling that old data must be reloaded), it's fine to
- * ignore the {@code initialLoadKey} and always start from the beginning of the data set.
- *
- * @param initialLoadKey Load items around this key, or at the beginning of the data set if null
- * is passed.
- * @param requestedLoadSize Suggested number of items to load.
- * @param enablePlaceholders Signals whether counting is requested. If false, you can
- * potentially save work by calling the single-parameter variant of
- * {@link DataSource.LoadCallback#onResult(List)} and not counting the
- * number of items in the data set.
- * @param callback DataSource.LoadCallback that receives initial load data.
- */
- @Override
- public abstract void loadInitial(@Nullable Key initialLoadKey, int requestedLoadSize,
- boolean enablePlaceholders, @NonNull InitialLoadCallback<Value> callback);
-
- /**
- * Load list data after the specified item.
- * <p>
- * It's valid to return a different list size than the page size, if it's easier for this data
- * source. It is generally safer to increase the number loaded than reduce.
- * <p>
- * Data may be passed synchronously during the loadAfter method, or deferred and called at a
- * later time. Further loads going down will be blocked until the callback is called.
- * <p>
- * If data cannot be loaded (for example, if the request is invalid, or the data would be stale
- * and inconsistent, it is valid to call {@link #invalidate()} to invalidate the data source,
- * and prevent further loading.
- *
- * @param currentEndKey Load items after this key. May be null on initial load, to indicate load
- * from beginning.
- * @param pageSize Suggested number of items to load.
- * @param callback DataSource.LoadCallback that receives loaded data.
- */
- public abstract void loadAfter(@NonNull Key currentEndKey, int pageSize,
- @NonNull LoadCallback<Value> callback);
-
- /**
- * Load data before the currently loaded content.
- * <p>
- * It's valid to return a different list size than the page size, if it's easier for this data
- * source. It is generally safer to increase the number loaded than reduce. Note that the last
- * item returned must be directly adjacent to the key passed, so varying size from the pageSize
- * requested should effectively grow or shrink the list by modifying the beginning, not the end.
- * <p>
- * Data may be passed synchronously during the loadBefore method, or deferred and called at a
- * later time. Further loads going up will be blocked until the callback is called.
- * <p>
- * If data cannot be loaded (for example, if the request is invalid, or the data would be stale
- * and inconsistent, it is valid to call {@link #invalidate()} to invalidate the data source,
- * and prevent further loading.
- * <p class="note"><strong>Note:</strong> Data must be returned in the order it will be
- * presented in the list.
- *
- * @param currentBeginKey Load items before this key.
- * @param pageSize Suggested number of items to load.
- * @param callback DataSource.LoadCallback that receives loaded data.
- */
- public abstract void loadBefore(@NonNull Key currentBeginKey, int pageSize,
- @NonNull LoadCallback<Value> callback);
-
- /**
- * Return a key associated with the given item.
- * <p>
- * If your KeyedDataSource is loading from a source that is sorted and loaded by a unique
- * integer ID, you would return {@code item.getID()} here. This key can then be passed to
- * {@link #loadBefore(Object, int, LoadCallback)} or
- * {@link #loadAfter(Object, int, LoadCallback)} to load additional items adjacent to the item
- * passed to this function.
- * <p>
- * If your key is more complex, such as when you're sorting by name, then resolving collisions
- * with integer ID, you'll need to return both. In such a case you would use a wrapper class,
- * such as {@code Pair<String, Integer>} or, in Kotlin,
- * {@code data class Key(val name: String, val id: Int)}
- *
- * @param item Item to get the key from.
- * @return Key associated with given item.
- */
- @NonNull
- public abstract Key getKey(@NonNull Value item);
-}
diff --git a/paging/common/src/main/java/android/arch/paging/ListDataSource.java b/paging/common/src/main/java/android/arch/paging/ListDataSource.java
index b6f366a..1482a91 100644
--- a/paging/common/src/main/java/android/arch/paging/ListDataSource.java
+++ b/paging/common/src/main/java/android/arch/paging/ListDataSource.java
@@ -29,22 +29,23 @@
}
@Override
- public void loadInitial(int requestedStartPosition, int requestedLoadSize, int pageSize,
- @NonNull InitialLoadCallback<T> callback) {
+ public void loadInitial(@NonNull LoadInitialParams params,
+ @NonNull LoadInitialCallback<T> callback) {
final int totalCount = mList.size();
- final int firstLoadPosition = computeFirstLoadPosition(
- requestedStartPosition, requestedLoadSize, pageSize, totalCount);
- final int firstLoadSize = Math.min(totalCount - firstLoadPosition, requestedLoadSize);
+ final int position = computeInitialLoadPosition(params, totalCount);
+ final int loadSize = computeInitialLoadSize(params, position, totalCount);
// for simplicity, we could return everything immediately,
// but we tile here since it's expected behavior
- List<T> sublist = mList.subList(firstLoadPosition, firstLoadPosition + firstLoadSize);
- callback.onResult(sublist, firstLoadPosition, totalCount);
+ List<T> sublist = mList.subList(position, position + loadSize);
+ callback.onResult(sublist, position, totalCount);
}
@Override
- public void loadRange(int startPosition, int count, @NonNull LoadCallback<T> callback) {
- callback.onResult(mList.subList(startPosition, startPosition + count));
+ public void loadRange(@NonNull LoadRangeParams params,
+ @NonNull LoadRangeCallback<T> callback) {
+ callback.onResult(mList.subList(params.startPosition,
+ params.startPosition + params.loadSize));
}
}
diff --git a/paging/common/src/main/java/android/arch/paging/PageKeyedDataSource.java b/paging/common/src/main/java/android/arch/paging/PageKeyedDataSource.java
new file mode 100644
index 0000000..a10ecee
--- /dev/null
+++ b/paging/common/src/main/java/android/arch/paging/PageKeyedDataSource.java
@@ -0,0 +1,391 @@
+/*
+ * 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 android.arch.paging;
+
+import android.support.annotation.GuardedBy;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Incremental data loader for page-keyed content, where requests return keys for next/previous
+ * pages.
+ * <p>
+ * Implement a DataSource using PageKeyedDataSource if you need to use data from page {@code N - 1}
+ * to load page {@code N}. This is common, for example, in network APIs that include a next/previous
+ * link or key with each page load.
+ * <p>
+ * The {@code InMemoryByPageRepository} in the
+ * <a href="https://github.com/googlesamples/android-architecture-components/blob/master/PagingWithNetworkSample/README.md">PagingWithNetworkSample</a>
+ * shows how to implement a network PageKeyedDataSource using
+ * <a href="https://square.github.io/retrofit/">Retrofit</a>, while
+ * handling swipe-to-refresh, network errors, and retry.
+ *
+ * @param <Key> Type of data used to query Value types out of the DataSource.
+ * @param <Value> Type of items being loaded by the DataSource.
+ */
+public abstract class PageKeyedDataSource<Key, Value> extends ContiguousDataSource<Key, Value> {
+ private final Object mKeyLock = new Object();
+
+ @Nullable
+ @GuardedBy("mKeyLock")
+ private Key mNextKey = null;
+
+ @Nullable
+ @GuardedBy("mKeyLock")
+ private Key mPreviousKey = null;
+
+ private void initKeys(@Nullable Key previousKey, @Nullable Key nextKey) {
+ synchronized (mKeyLock) {
+ mPreviousKey = previousKey;
+ mNextKey = nextKey;
+ }
+ }
+
+ private void setPreviousKey(@Nullable Key previousKey) {
+ synchronized (mKeyLock) {
+ mPreviousKey = previousKey;
+ }
+ }
+
+ private void setNextKey(@Nullable Key nextKey) {
+ synchronized (mKeyLock) {
+ mNextKey = nextKey;
+ }
+ }
+
+ private @Nullable Key getPreviousKey() {
+ synchronized (mKeyLock) {
+ return mPreviousKey;
+ }
+ }
+
+ private @Nullable Key getNextKey() {
+ synchronized (mKeyLock) {
+ return mNextKey;
+ }
+ }
+
+ /**
+ * Holder object for inputs to {@link #loadInitial(LoadInitialParams, LoadInitialCallback)}.
+ *
+ * @param <Key> Type of data used to query pages.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public static class LoadInitialParams<Key> {
+ /**
+ * Requested number of items to load.
+ * <p>
+ * Note that this may be larger than available data.
+ */
+ public final int requestedLoadSize;
+
+ /**
+ * Defines whether placeholders are enabled, and whether the total count passed to
+ * {@link LoadInitialCallback#onResult(List, int, int, Key, Key)} will be ignored.
+ */
+ public final boolean placeholdersEnabled;
+
+
+ LoadInitialParams(int requestedLoadSize,
+ boolean placeholdersEnabled) {
+ this.requestedLoadSize = requestedLoadSize;
+ this.placeholdersEnabled = placeholdersEnabled;
+ }
+ }
+
+ /**
+ * Holder object for inputs to {@link #loadBefore(LoadParams, LoadCallback)} and
+ * {@link #loadAfter(LoadParams, LoadCallback)}.
+ *
+ * @param <Key> Type of data used to query pages.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public static class LoadParams<Key> {
+ /**
+ * Load items before/after this key.
+ * <p>
+ * Returned data must begin directly adjacent to this position.
+ */
+ public final Key key;
+
+ /**
+ * Requested number of items to load.
+ * <p>
+ * Returned page can be of this size, but it may be altered if that is easier, e.g. a
+ * network data source where the backend defines page size.
+ */
+ public final int requestedLoadSize;
+
+ LoadParams(Key key, int requestedLoadSize) {
+ this.key = key;
+ this.requestedLoadSize = requestedLoadSize;
+ }
+ }
+
+ /**
+ * Callback for {@link #loadInitial(LoadInitialParams, LoadInitialCallback)}
+ * to return data and, optionally, position/count information.
+ * <p>
+ * A callback can be called only once, and will throw if called again.
+ * <p>
+ * If you can compute the number of items in the data set before and after the loaded range,
+ * call the five parameter {@link #onResult(List, int, int, Object, Object)} to pass that
+ * information. You can skip passing this information by calling the three parameter
+ * {@link #onResult(List, Object, Object)}, either if it's difficult to compute, or if
+ * {@link LoadInitialParams#placeholdersEnabled} is {@code false}, so the positioning
+ * information will be ignored.
+ * <p>
+ * It is always valid for a DataSource loading method that takes a callback to stash the
+ * callback and call it later. This enables DataSources to be fully asynchronous, and to handle
+ * temporary, recoverable error states (such as a network error that can be retried).
+ *
+ * @param <Key> Type of data used to query pages.
+ * @param <Value> Type of items being loaded.
+ */
+ public static class LoadInitialCallback<Key, Value> extends BaseLoadCallback<Value> {
+ private final PageKeyedDataSource<Key, Value> mDataSource;
+ private final boolean mCountingEnabled;
+ LoadInitialCallback(@NonNull PageKeyedDataSource<Key, Value> dataSource,
+ boolean countingEnabled, @NonNull PageResult.Receiver<Value> receiver) {
+ super(dataSource, PageResult.INIT, null, receiver);
+ mDataSource = dataSource;
+ mCountingEnabled = countingEnabled;
+ }
+
+ /**
+ * Called to pass initial load state from a DataSource.
+ * <p>
+ * Call this method from your DataSource's {@code loadInitial} function to return data,
+ * and inform how many placeholders should be shown before and after. If counting is cheap
+ * to compute (for example, if a network load returns the information regardless), it's
+ * recommended to pass data back through this method.
+ * <p>
+ * It is always valid to pass a different amount of data than what is requested. Pass an
+ * empty list if there is no more data to load.
+ *
+ * @param data List of items loaded from the DataSource. If this is empty, the DataSource
+ * is treated as empty, and no further loads will occur.
+ * @param position Position of the item at the front of the list. If there are {@code N}
+ * items before the items in data that can be loaded from this DataSource,
+ * pass {@code N}.
+ * @param totalCount Total number of items that may be returned from this DataSource.
+ * Includes the number in the initial {@code data} parameter
+ * as well as any items that can be loaded in front or behind of
+ * {@code data}.
+ */
+ public void onResult(@NonNull List<Value> data, int position, int totalCount,
+ @Nullable Key previousPageKey, @Nullable Key nextPageKey) {
+ if (!dispatchInvalidResultIfInvalid()) {
+ validateInitialLoadParams(data, position, totalCount);
+
+ // setup keys before dispatching data, so guaranteed to be ready
+ mDataSource.initKeys(previousPageKey, nextPageKey);
+
+ int trailingUnloadedCount = totalCount - position - data.size();
+ if (mCountingEnabled) {
+ dispatchResultToReceiver(new PageResult<>(
+ data, position, trailingUnloadedCount, 0));
+ } else {
+ dispatchResultToReceiver(new PageResult<>(data, position));
+ }
+ }
+ }
+
+ /**
+ * Called to pass loaded data from a DataSource.
+ * <p>
+ * Call this from {@link #loadInitial(LoadInitialParams, LoadInitialCallback)} to
+ * initialize without counting available data, or supporting placeholders.
+ * <p>
+ * It is always valid to pass a different amount of data than what is requested. Pass an
+ * empty list if there is no more data to load.
+ *
+ * @param data List of items loaded from the PageKeyedDataSource.
+ * @param previousPageKey Key for page before the initial load result, or {@code null} if no
+ * more data can be loaded before.
+ * @param nextPageKey Key for page after the initial load result, or {@code null} if no
+ * more data can be loaded after.
+ */
+ public void onResult(@NonNull List<Value> data, @Nullable Key previousPageKey,
+ @Nullable Key nextPageKey) {
+ if (!dispatchInvalidResultIfInvalid()) {
+ mDataSource.initKeys(previousPageKey, nextPageKey);
+ dispatchResultToReceiver(new PageResult<>(data, 0, 0, 0));
+ }
+ }
+ }
+
+ /**
+ * Callback for PageKeyedDataSource {@link #loadBefore(LoadParams, LoadCallback)} and
+ * {@link #loadAfter(LoadParams, LoadCallback)} to return data.
+ * <p>
+ * A callback can be called only once, and will throw if called again.
+ * <p>
+ * It is always valid for a DataSource loading method that takes a callback to stash the
+ * callback and call it later. This enables DataSources to be fully asynchronous, and to handle
+ * temporary, recoverable error states (such as a network error that can be retried).
+ *
+ * @param <Key> Type of data used to query pages.
+ * @param <Value> Type of items being loaded.
+ */
+ public static class LoadCallback<Key, Value> extends BaseLoadCallback<Value> {
+ private final PageKeyedDataSource<Key, Value> mDataSource;
+ LoadCallback(@NonNull PageKeyedDataSource<Key, Value> dataSource,
+ @PageResult.ResultType int type, @Nullable Executor mainThreadExecutor,
+ @NonNull PageResult.Receiver<Value> receiver) {
+ super(dataSource, type, mainThreadExecutor, receiver);
+ mDataSource = dataSource;
+ }
+
+ /**
+ * Called to pass loaded data from a DataSource.
+ * <p>
+ * Call this method from your PageKeyedDataSource's
+ * {@link #loadBefore(LoadParams, LoadCallback)} and
+ * {@link #loadAfter(LoadParams, LoadCallback)} methods to return data.
+ * <p>
+ * It is always valid to pass a different amount of data than what is requested. Pass an
+ * empty list if there is no more data to load.
+ * <p>
+ * Pass the key for the subsequent page to load to adjacentPageKey. For example, if you've
+ * loaded a page in {@link #loadBefore(LoadParams, LoadCallback)}, pass the key for the
+ * previous page, or {@code null} if the loaded page is the first. If in
+ * {@link #loadAfter(LoadParams, LoadCallback)}, pass the key for the next page, or
+ * {@code null} if the loaded page is the last.
+ *
+ * @param data List of items loaded from the PageKeyedDataSource.
+ * @param adjacentPageKey Key for subsequent page load (previous page in {@link #loadBefore}
+ * / next page in {@link #loadAfter}), or {@code null} if there are
+ * no more pages to load in the current load direction.
+ */
+ public void onResult(@NonNull List<Value> data, @Nullable Key adjacentPageKey) {
+ if (!dispatchInvalidResultIfInvalid()) {
+ if (mResultType == PageResult.APPEND) {
+ mDataSource.setNextKey(adjacentPageKey);
+ } else {
+ mDataSource.setPreviousKey(adjacentPageKey);
+ }
+ dispatchResultToReceiver(new PageResult<>(data, 0, 0, 0));
+ }
+ }
+ }
+
+ @Nullable
+ @Override
+ final Key getKey(int position, Value item) {
+ // don't attempt to persist keys, since we currently don't pass them to initial load
+ return null;
+ }
+
+ @Override
+ final void dispatchLoadInitial(@Nullable Key key, int initialLoadSize, int pageSize,
+ boolean enablePlaceholders, @NonNull Executor mainThreadExecutor,
+ @NonNull PageResult.Receiver<Value> receiver) {
+ LoadInitialCallback<Key, Value> callback =
+ new LoadInitialCallback<>(this, enablePlaceholders, receiver);
+ loadInitial(new LoadInitialParams<Key>(initialLoadSize, enablePlaceholders), callback);
+
+ // If initialLoad's callback is not called within the body, we force any following calls
+ // to post to the UI thread. This constructor may be run on a background thread, but
+ // after constructor, mutation must happen on UI thread.
+ callback.setPostExecutor(mainThreadExecutor);
+ }
+
+
+ @Override
+ final void dispatchLoadAfter(int currentEndIndex, @NonNull Value currentEndItem,
+ int pageSize, @NonNull Executor mainThreadExecutor,
+ @NonNull PageResult.Receiver<Value> receiver) {
+ @Nullable Key key = getNextKey();
+ if (key != null) {
+ loadAfter(new LoadParams<>(key, pageSize),
+ new LoadCallback<>(this, PageResult.APPEND, mainThreadExecutor, receiver));
+ }
+ }
+
+ @Override
+ final void dispatchLoadBefore(int currentBeginIndex, @NonNull Value currentBeginItem,
+ int pageSize, @NonNull Executor mainThreadExecutor,
+ @NonNull PageResult.Receiver<Value> receiver) {
+ @Nullable Key key = getPreviousKey();
+ if (key != null) {
+ loadBefore(new LoadParams<>(key, pageSize),
+ new LoadCallback<>(this, PageResult.PREPEND, mainThreadExecutor, receiver));
+ }
+ }
+
+ /**
+ * Load initial data.
+ * <p>
+ * This method is called first to initialize a PagedList with data. If it's possible to count
+ * the items that can be loaded by the DataSource, it's recommended to pass the loaded data to
+ * the callback via the three-parameter
+ * {@link LoadInitialCallback#onResult(List, int, int, Object, Object)}. This enables PagedLists
+ * presenting data from this source to display placeholders to represent unloaded items.
+ * <p>
+ * {@link LoadInitialParams#requestedLoadSize} is a hint, not a requirement, so it may be may be
+ * altered or ignored.
+ *
+ * @param params Parameters for initial load, including requested load size.
+ * @param callback Callback that receives initial load data.
+ */
+ public abstract void loadInitial(@NonNull LoadInitialParams<Key> params,
+ @NonNull LoadInitialCallback<Key, Value> callback);
+
+ /**
+ * Prepend page with the key specified by {@link LoadParams#key LoadParams.key}.
+ * <p>
+ * It's valid to return a different list size than the page size if it's easier, e.g. if your
+ * backend defines page sizes. It is generally safer to increase the number loaded than reduce.
+ * <p>
+ * Data may be passed synchronously during the load method, or deferred and called at a
+ * later time. Further loads going down will be blocked until the callback is called.
+ * <p>
+ * If data cannot be loaded (for example, if the request is invalid, or the data would be stale
+ * and inconsistent, it is valid to call {@link #invalidate()} to invalidate the data source,
+ * and prevent further loading.
+ *
+ * @param params Parameters for the load, including the key for the new page, and requested load
+ * size.
+ * @param callback Callback that receives loaded data.
+ */
+ public abstract void loadBefore(@NonNull LoadParams<Key> params,
+ @NonNull LoadCallback<Key, Value> callback);
+
+ /**
+ * Append page with the key specified by {@link LoadParams#key LoadParams.key}.
+ * <p>
+ * It's valid to return a different list size than the page size if it's easier, e.g. if your
+ * backend defines page sizes. It is generally safer to increase the number loaded than reduce.
+ * <p>
+ * Data may be passed synchronously during the load method, or deferred and called at a
+ * later time. Further loads going down will be blocked until the callback is called.
+ * <p>
+ * If data cannot be loaded (for example, if the request is invalid, or the data would be stale
+ * and inconsistent, it is valid to call {@link #invalidate()} to invalidate the data source,
+ * and prevent further loading.
+ *
+ * @param params Parameters for the load, including the key for the new page, and requested load
+ * size.
+ * @param callback Callback that receives loaded data.
+ */
+ public abstract void loadAfter(@NonNull LoadParams<Key> params,
+ @NonNull LoadCallback<Key, Value> callback);
+}
diff --git a/paging/common/src/main/java/android/arch/paging/PagedList.java b/paging/common/src/main/java/android/arch/paging/PagedList.java
index 70d4075..c6de5c5 100644
--- a/paging/common/src/main/java/android/arch/paging/PagedList.java
+++ b/paging/common/src/main/java/android/arch/paging/PagedList.java
@@ -578,7 +578,8 @@
* If data is supplied by a {@link PositionalDataSource}, the item returned from
* <code>get(i)</code> has a position of <code>i + getPositionOffset()</code>.
* <p>
- * If the DataSource is a {@link KeyedDataSource}, and thus doesn't use positions, returns 0.
+ * If the DataSource is a {@link ItemKeyedDataSource} or {@link PageKeyedDataSource}, it
+ * doesn't use positions, returns 0.
*/
public int getPositionOffset() {
return mStorage.getPositionOffset();
@@ -602,7 +603,8 @@
* GC'd.
*
* @param previousSnapshot Snapshot previously captured from this List, or null.
- * @param callback LoadCallback to dispatch to.
+ * @param callback Callback to dispatch to.
+ *
* @see #removeWeakCallback(Callback)
*/
@SuppressWarnings("WeakerAccess")
@@ -637,7 +639,7 @@
/**
* Removes a previously added callback.
*
- * @param callback LoadCallback, previously added.
+ * @param callback Callback, previously added.
* @see #addWeakCallback(List, Callback)
*/
@SuppressWarnings("WeakerAccess")
@@ -680,7 +682,7 @@
* Dispatch updates since the non-empty snapshot was taken.
*
* @param snapshot Non-empty snapshot.
- * @param callback LoadCallback for updates that have occurred since snapshot.
+ * @param callback Callback for updates that have occurred since snapshot.
*/
abstract void dispatchUpdatesSinceSnapshot(@NonNull PagedList<T> snapshot,
@NonNull Callback callback);
@@ -857,12 +859,14 @@
}
/**
- * Defines how many items to load when first load occurs, if you are using a
- * {@link KeyedDataSource}.
+ * Defines how many items to load when first load occurs.
* <p>
* 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.
* <p>
+ * When using a {@link PositionalDataSource}, the initial load size will be coerced to
+ * an integer multiple of pageSize, to enable efficient tiling.
+ * <p>
* If not set, defaults to three times page size.
*
* @param initialLoadSizeHint Number of items to load while initializing the PagedList.
@@ -874,7 +878,6 @@
return this;
}
-
/**
* Creates a {@link Config} with the given parameters.
*
@@ -905,13 +908,32 @@
/**
* Signals when a PagedList has reached the end of available data.
* <p>
- * This can be used to implement paging from the network into a local database - when the
- * database has no more data to present, a BoundaryCallback can be used to fetch more data.
+ * When local storage is a cache of network data, it's common to set up a streaming pipeline:
+ * Network data is paged into the database, database is paged into UI. Paging from the database
+ * to UI can be done with a {@code LiveData<PagedList>}, but it's still necessary to know when
+ * to trigger network loads.
* <p>
- * If an instance is shared across multiple PagedLists (e.g. when passed to
+ * BoundaryCallback does this signaling - when a DataSource runs out of data at the end of
+ * the list, {@link #onItemAtEndLoaded(Object)} is called, and you can start an async network
+ * load that will write the result directly to the database. Because the database is being
+ * observed, the UI bound to the {@code LiveData<PagedList>} will update automatically to
+ * account for the new items.
+ * <p>
+ * Note that a BoundaryCallback instance shared across multiple PagedLists (e.g. when passed to
* {@link LivePagedListBuilder#setBoundaryCallback}), the callbacks may be issued multiple
* times. If for example {@link #onItemAtEndLoaded(Object)} triggers a network load, it should
* avoid triggering it again while the load is ongoing.
+ * <p>
+ * BoundaryCallback only passes the item at front or end of the list. Number of items is not
+ * passed, since it may not be fully computed by the DataSource if placeholders are not
+ * supplied. Keys are not known because the BoundaryCallback is independent of the
+ * DataSource-specific keys, which may be different for local vs remote storage.
+ * <p>
+ * The database + network Repository in the
+ * <a href="https://github.com/googlesamples/android-architecture-components/blob/master/PagingWithNetworkSample/README.md">PagingWithNetworkSample</a>
+ * shows how to implement a network BoundaryCallback using
+ * <a href="https://square.github.io/retrofit/">Retrofit</a>, while
+ * handling swipe-to-refresh, network errors, and retry.
*
* @param <T> Type loaded by the PagedList.
*/
@@ -920,7 +942,7 @@
/**
* Called when zero items are returned from an initial load of the PagedList's data source.
*/
- public abstract void onZeroItemsLoaded();
+ public void onZeroItemsLoaded() {}
/**
* Called when the item at the front of the PagedList has been loaded, and access has
@@ -930,7 +952,7 @@
*
* @param itemAtFront The first item of PagedList
*/
- public abstract void onItemAtFrontLoaded(@NonNull T itemAtFront);
+ public void onItemAtFrontLoaded(@NonNull T itemAtFront) {}
/**
* Called when the item at the end of the PagedList has been loaded, and access has
@@ -940,6 +962,6 @@
*
* @param itemAtEnd The first item of PagedList
*/
- public abstract void onItemAtEndLoaded(@NonNull T itemAtEnd);
+ public void onItemAtEndLoaded(@NonNull T itemAtEnd) {}
}
}
diff --git a/paging/common/src/main/java/android/arch/paging/PositionalDataSource.java b/paging/common/src/main/java/android/arch/paging/PositionalDataSource.java
index 5dd3a83..780bcf6 100644
--- a/paging/common/src/main/java/android/arch/paging/PositionalDataSource.java
+++ b/paging/common/src/main/java/android/arch/paging/PositionalDataSource.java
@@ -21,17 +21,23 @@
import android.support.annotation.WorkerThread;
import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Executor;
/**
- * Position-based data loader for a fixed-size, countable data set, supporting loads at arbitrary
- * positions.
+ * Position-based data loader for a fixed-size, countable data set, supporting fixed-size loads at
+ * arbitrary page positions.
* <p>
- * Extend PositionalDataSource if you can support counting your data set, and loading based on
- * position information.
+ * Extend PositionalDataSource if you can load pages of a requested size at arbitrary
+ * positions, and provide a fixed item count. If your data source can't support loading arbitrary
+ * requested page sizes (e.g. when network page size constraints are only known at runtime), use
+ * either {@link PageKeyedDataSource} or {@link ItemKeyedDataSource} instead.
* <p>
* Note that unless {@link PagedList.Config#enablePlaceholders placeholders are disabled}
- * PositionalDataSource requires counting the size of the dataset. This allows pages to be tiled in
+ * PositionalDataSource requires counting the size of the data set. This allows pages to be tiled in
* at arbitrary, non-contiguous locations based upon what the user observes in a {@link PagedList}.
+ * If placeholders are disabled, initialize with the two parameter
+ * {@link LoadInitialCallback#onResult(List, int)}.
* <p>
* Room can generate a Factory of PositionalDataSources for you:
* <pre>
@@ -46,42 +52,269 @@
public abstract class PositionalDataSource<T> extends DataSource<Integer, T> {
/**
+ * Holder object for inputs to {@link #loadInitial(LoadInitialParams, LoadInitialCallback)}.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public static class LoadInitialParams {
+ /**
+ * Initial load position requested.
+ * <p>
+ * Note that this may not be within the bounds of your data set, it may need to be adjusted
+ * before you execute your load.
+ */
+ public final int requestedStartPosition;
+
+ /**
+ * Requested number of items to load.
+ * <p>
+ * Note that this may be larger than available data.
+ */
+ public final int requestedLoadSize;
+
+ /**
+ * Defines page size acceptable for return values.
+ * <p>
+ * List of items passed to the callback must be an integer multiple of page size.
+ */
+ public final int pageSize;
+
+ /**
+ * Defines whether placeholders are enabled, and whether the total count passed to
+ * {@link LoadInitialCallback#onResult(List, int, int)} will be ignored.
+ */
+ public final boolean placeholdersEnabled;
+
+ LoadInitialParams(
+ int requestedStartPosition,
+ int requestedLoadSize,
+ int pageSize,
+ boolean placeholdersEnabled) {
+ this.requestedStartPosition = requestedStartPosition;
+ this.requestedLoadSize = requestedLoadSize;
+ this.pageSize = pageSize;
+ this.placeholdersEnabled = placeholdersEnabled;
+ }
+ }
+
+ /**
+ * Holder object for inputs to {@link #loadRange(LoadRangeParams, LoadRangeCallback)}.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public static class LoadRangeParams {
+ /**
+ * Start position of data to load.
+ * <p>
+ * Returned data must start at this position.
+ */
+ public final int startPosition;
+ /**
+ * Number of items to load.
+ * <p>
+ * Returned data must be of this size, unless at end of the list.
+ */
+ public final int loadSize;
+
+ LoadRangeParams(int startPosition, int loadSize) {
+ this.startPosition = startPosition;
+ this.loadSize = loadSize;
+ }
+ }
+
+ /**
+ * Callback for {@link #loadInitial(LoadInitialParams, LoadInitialCallback)}
+ * to return data, position, and count.
+ * <p>
+ * A callback can be called only once, and will throw if called again.
+ * <p>
+ * It is always valid for a DataSource loading method that takes a callback to stash the
+ * callback and call it later. This enables DataSources to be fully asynchronous, and to handle
+ * temporary, recoverable error states (such as a network error that can be retried).
+ *
+ * @param <T> Type of items being loaded.
+ */
+ public static class LoadInitialCallback<T> extends BaseLoadCallback<T> {
+ private final boolean mCountingEnabled;
+ private final int mPageSize;
+
+ LoadInitialCallback(@NonNull PositionalDataSource dataSource, boolean countingEnabled,
+ int pageSize, PageResult.Receiver<T> receiver) {
+ super(dataSource, PageResult.INIT, null, receiver);
+ mCountingEnabled = countingEnabled;
+ mPageSize = pageSize;
+ if (mPageSize < 1) {
+ throw new IllegalArgumentException("Page size must be non-negative");
+ }
+ }
+
+ /**
+ * Called to pass initial load state from a DataSource.
+ * <p>
+ * Call this method from your DataSource's {@code loadInitial} function to return data,
+ * and inform how many placeholders should be shown before and after. If counting is cheap
+ * to compute (for example, if a network load returns the information regardless), it's
+ * recommended to pass the total size to the totalCount parameter. If placeholders are not
+ * requested (when {@link LoadInitialParams#placeholdersEnabled} is false), you can instead
+ * call {@link #onResult(List, int)}.
+ *
+ * @param data List of items loaded from the DataSource. If this is empty, the DataSource
+ * is treated as empty, and no further loads will occur.
+ * @param position Position of the item at the front of the list. If there are {@code N}
+ * items before the items in data that can be loaded from this DataSource,
+ * pass {@code N}.
+ * @param totalCount Total number of items that may be returned from this DataSource.
+ * Includes the number in the initial {@code data} parameter
+ * as well as any items that can be loaded in front or behind of
+ * {@code data}.
+ */
+ public void onResult(@NonNull List<T> data, int position, int totalCount) {
+ if (!dispatchInvalidResultIfInvalid()) {
+ validateInitialLoadParams(data, position, totalCount);
+ if (position + data.size() != totalCount
+ && data.size() % mPageSize != 0) {
+ throw new IllegalArgumentException("PositionalDataSource requires initial load"
+ + " size to be a multiple of page size to support internal tiling.");
+ }
+
+ if (mCountingEnabled) {
+ int trailingUnloadedCount = totalCount - position - data.size();
+ dispatchResultToReceiver(
+ new PageResult<>(data, position, trailingUnloadedCount, 0));
+ } else {
+ // Only occurs when wrapped as contiguous
+ dispatchResultToReceiver(new PageResult<>(data, position));
+ }
+ }
+ }
+
+ /**
+ * Called to pass initial load state from a DataSource without total count,
+ * when placeholders aren't requested.
+ * <p class="note"><strong>Note:</strong> This method can only be called when placeholders
+ * are disabled ({@link LoadInitialParams#placeholdersEnabled} is false).
+ * <p>
+ * Call this method from your DataSource's {@code loadInitial} function to return data,
+ * if position is known but total size is not. If placeholders are requested, call the three
+ * parameter variant: {@link #onResult(List, int, int)}.
+ *
+ * @param data List of items loaded from the DataSource. If this is empty, the DataSource
+ * is treated as empty, and no further loads will occur.
+ * @param position Position of the item at the front of the list. If there are {@code N}
+ * items before the items in data that can be provided by this DataSource,
+ * pass {@code N}.
+ */
+ @SuppressWarnings("WeakerAccess")
+ public void onResult(@NonNull List<T> data, int position) {
+ if (!dispatchInvalidResultIfInvalid()) {
+ if (position < 0) {
+ throw new IllegalArgumentException("Position must be non-negative");
+ }
+ if (data.isEmpty() && position != 0) {
+ throw new IllegalArgumentException(
+ "Initial result cannot be empty if items are present in data set.");
+ }
+ if (mCountingEnabled) {
+ throw new IllegalStateException("Placeholders requested, but totalCount not"
+ + " provided. Please call the three-parameter onResult method, or"
+ + " disable placeholders in the PagedList.Config");
+ }
+ dispatchResultToReceiver(new PageResult<>(data, position));
+ }
+ }
+ }
+
+ /**
+ * Callback for PositionalDataSource {@link #loadRange(LoadRangeParams, LoadRangeCallback)}
+ * to return data.
+ * <p>
+ * A callback can be called only once, and will throw if called again.
+ * <p>
+ * It is always valid for a DataSource loading method that takes a callback to stash the
+ * callback and call it later. This enables DataSources to be fully asynchronous, and to handle
+ * temporary, recoverable error states (such as a network error that can be retried).
+ *
+ * @param <T> Type of items being loaded.
+ */
+ public static class LoadRangeCallback<T> extends BaseLoadCallback<T> {
+ private final int mPositionOffset;
+ LoadRangeCallback(@NonNull PositionalDataSource dataSource, int positionOffset,
+ Executor mainThreadExecutor, PageResult.Receiver<T> receiver) {
+ super(dataSource, PageResult.TILE, mainThreadExecutor, receiver);
+ mPositionOffset = positionOffset;
+ }
+
+ /**
+ * Called to pass loaded data from {@link #loadRange(LoadRangeParams, LoadRangeCallback)}.
+ *
+ * @param data List of items loaded from the DataSource. Must be same size as requested,
+ * unless at end of list.
+ */
+ public void onResult(@NonNull List<T> data) {
+ if (!dispatchInvalidResultIfInvalid()) {
+ dispatchResultToReceiver(new PageResult<>(
+ data, 0, 0, mPositionOffset));
+ }
+ }
+ }
+
+ final void dispatchLoadInitial(boolean acceptCount,
+ int requestedStartPosition, int requestedLoadSize, int pageSize,
+ @NonNull Executor mainThreadExecutor, @NonNull PageResult.Receiver<T> receiver) {
+ LoadInitialCallback<T> callback =
+ new LoadInitialCallback<>(this, acceptCount, pageSize, receiver);
+
+ LoadInitialParams params = new LoadInitialParams(
+ requestedStartPosition, requestedLoadSize, pageSize, acceptCount);
+ loadInitial(params, callback);
+
+ // If initialLoad's callback is not called within the body, we force any following calls
+ // to post to the UI thread. This constructor may be run on a background thread, but
+ // after constructor, mutation must happen on UI thread.
+ callback.setPostExecutor(mainThreadExecutor);
+ }
+
+ final void dispatchLoadRange(int startPosition, int count,
+ @NonNull Executor mainThreadExecutor, @NonNull PageResult.Receiver<T> receiver) {
+ LoadRangeCallback<T> callback =
+ new LoadRangeCallback<>(this, startPosition, mainThreadExecutor, receiver);
+ if (count == 0) {
+ callback.onResult(Collections.<T>emptyList());
+ } else {
+ loadRange(new LoadRangeParams(startPosition, count), callback);
+ }
+ }
+
+ /**
* Load initial list data.
* <p>
* This method is called to load the initial page(s) from the DataSource.
* <p>
* Result list must be a multiple of pageSize to enable efficient tiling.
*
- * @param requestedStartPosition Initial load position requested. Note that this may not be
- * within the bounds of your data set, it should be corrected
- * before you make your query.
- * @param requestedLoadSize Requested number of items to load. Note that this may be larger than
- * available data.
- * @param pageSize Defines page size acceptable for return values. List of items passed to the
- * callback must be an integer multiple of page size.
- * @param callback DataSource.InitialLoadCallback that receives initial load data, including
+ * @param params Parameters for initial load, including requested start position, load size, and
+ * page size.
+ * @param callback Callback that receives initial load data, including
* position and total data set size.
*/
@WorkerThread
- public abstract void loadInitial(int requestedStartPosition, int requestedLoadSize,
- int pageSize, @NonNull InitialLoadCallback<T> callback);
+ public abstract void loadInitial(
+ @NonNull LoadInitialParams params,
+ @NonNull LoadInitialCallback<T> callback);
/**
* Called to load a range of data from the DataSource.
* <p>
* This method is called to load additional pages from the DataSource after the
- * InitialLoadCallback passed to loadInitial has initialized a PagedList.
+ * LoadInitialCallback passed to dispatchLoadInitial has initialized a PagedList.
* <p>
- * Unlike {@link #loadInitial(int, int, int, InitialLoadCallback)}, this method must return the
- * number of items requested, at the position requested.
+ * Unlike {@link #loadInitial(LoadInitialParams, LoadInitialCallback)}, this method must return
+ * the number of items requested, at the position requested.
*
- * @param startPosition Initial load position.
- * @param count Number of items to load.
- * @param callback DataSource.LoadCallback that receives loaded data.
+ * @param params Parameters for load, including start position and load size.
+ * @param callback Callback that receives loaded data.
*/
@WorkerThread
- public abstract void loadRange(int startPosition, int count,
- @NonNull LoadCallback<T> callback);
+ public abstract void loadRange(@NonNull LoadRangeParams params,
+ @NonNull LoadRangeCallback<T> callback);
@Override
boolean isContiguous() {
@@ -93,11 +326,58 @@
return new ContiguousWithoutPlaceholdersWrapper<>(this);
}
- static int computeFirstLoadPosition(int position, int firstLoadSize, int pageSize, int size) {
+ /**
+ * Helper for computing an initial position in
+ * {@link #loadInitial(LoadInitialParams, LoadInitialCallback)} when total data set size can be
+ * computed ahead of loading.
+ * <p>
+ * The value computed by this function will do bounds checking, page alignment, and positioning
+ * based on initial load size requested.
+ * <p>
+ * Example usage in a PositionalDataSource subclass:
+ * <pre>
+ * class ItemDataSource extends PositionalDataSource<Item> {
+ * private int computeCount() {
+ * // actual count code here
+ * }
+ *
+ * private List<Item> loadRangeInternal(int startPosition, int loadCount) {
+ * // actual load code here
+ * }
+ *
+ * {@literal @}Override
+ * public void loadInitial({@literal @}NonNull LoadInitialParams params,
+ * {@literal @}NonNull LoadInitialCallback<Item> callback) {
+ * int totalCount = computeCount();
+ * int position = computeInitialLoadPosition(params, totalCount);
+ * int loadSize = computeInitialLoadSize(params, position, totalCount);
+ * callback.onResult(loadRangeInternal(position, loadSize), position, totalCount);
+ * }
+ *
+ * {@literal @}Override
+ * public void loadRange({@literal @}NonNull LoadRangeParams params,
+ * {@literal @}NonNull LoadRangeCallback<Item> callback) {
+ * callback.onResult(loadRangeInternal(params.startPosition, params.loadSize));
+ * }
+ * }</pre>
+ *
+ * @param params Params passed to {@link #loadInitial(LoadInitialParams, LoadInitialCallback)},
+ * including page size, and requested start/loadSize.
+ * @param totalCount Total size of the data set.
+ * @return Position to start loading at.
+ *
+ * @see #computeInitialLoadSize(LoadInitialParams, int, int)
+ */
+ public static int computeInitialLoadPosition(@NonNull LoadInitialParams params,
+ int totalCount) {
+ int position = params.requestedStartPosition;
+ int initialLoadSize = params.requestedLoadSize;
+ int pageSize = params.pageSize;
+
int roundedPageStart = Math.round(position / pageSize) * pageSize;
// maximum start pos is that which will encompass end of list
- int maximumLoadPage = ((size - firstLoadSize + pageSize - 1) / pageSize) * pageSize;
+ int maximumLoadPage = ((totalCount - initialLoadSize + pageSize - 1) / pageSize) * pageSize;
roundedPageStart = Math.min(maximumLoadPage, roundedPageStart);
// minimum start position is 0
@@ -106,6 +386,56 @@
return roundedPageStart;
}
+ /**
+ * Helper for computing an initial load size in
+ * {@link #loadInitial(LoadInitialParams, LoadInitialCallback)} when total data set size can be
+ * computed ahead of loading.
+ * <p>
+ * This function takes the requested load size, and bounds checks it against the value returned
+ * by {@link #computeInitialLoadPosition(LoadInitialParams, int)}.
+ * <p>
+ * Example usage in a PositionalDataSource subclass:
+ * <pre>
+ * class ItemDataSource extends PositionalDataSource<Item> {
+ * private int computeCount() {
+ * // actual count code here
+ * }
+ *
+ * private List<Item> loadRangeInternal(int startPosition, int loadCount) {
+ * // actual load code here
+ * }
+ *
+ * {@literal @}Override
+ * public void loadInitial({@literal @}NonNull LoadInitialParams params,
+ * {@literal @}NonNull LoadInitialCallback<Item> callback) {
+ * int totalCount = computeCount();
+ * int position = computeInitialLoadPosition(params, totalCount);
+ * int loadSize = computeInitialLoadSize(params, position, totalCount);
+ * callback.onResult(loadRangeInternal(position, loadSize), position, totalCount);
+ * }
+ *
+ * {@literal @}Override
+ * public void loadRange({@literal @}NonNull LoadRangeParams params,
+ * {@literal @}NonNull LoadRangeCallback<Item> callback) {
+ * callback.onResult(loadRangeInternal(params.startPosition, params.loadSize));
+ * }
+ * }</pre>
+ *
+ * @param params Params passed to {@link #loadInitial(LoadInitialParams, LoadInitialCallback)},
+ * including page size, and requested start/loadSize.
+ * @param initialLoadPosition Value returned by
+ * {@link #computeInitialLoadPosition(LoadInitialParams, int)}
+ * @param totalCount Total size of the data set.
+ * @return Number of items to load.
+ *
+ * @see #computeInitialLoadPosition(LoadInitialParams, int)
+ */
+ @SuppressWarnings("WeakerAccess")
+ public static int computeInitialLoadSize(@NonNull LoadInitialParams params,
+ int initialLoadPosition, int totalCount) {
+ return Math.min(totalCount - initialLoadPosition, params.requestedLoadSize);
+ }
+
@SuppressWarnings("deprecation")
static class ContiguousWithoutPlaceholdersWrapper<Value>
extends ContiguousDataSource<Integer, Value> {
@@ -119,34 +449,42 @@
}
@Override
- public void loadInitial(@Nullable Integer position, int initialLoadSize,
- boolean enablePlaceholders, @NonNull InitialLoadCallback<Value> callback) {
+ void dispatchLoadInitial(@Nullable Integer position, int initialLoadSize, int pageSize,
+ boolean enablePlaceholders, @NonNull Executor mainThreadExecutor,
+ @NonNull PageResult.Receiver<Value> receiver) {
final int convertPosition = position == null ? 0 : position;
// Note enablePlaceholders will be false here, but we don't have a way to communicate
// this to PositionalDataSource. This is fine, because only the list and its position
- // offset will be consumed by the InitialLoadCallback.
- mPositionalDataSource.loadInitial(
- convertPosition, initialLoadSize, initialLoadSize, callback);
+ // offset will be consumed by the LoadInitialCallback.
+ mPositionalDataSource.dispatchLoadInitial(false, convertPosition, initialLoadSize,
+ pageSize, mainThreadExecutor, receiver);
}
@Override
- void loadAfter(int currentEndIndex, @NonNull Value currentEndItem, int pageSize,
- @NonNull LoadCallback<Value> callback) {
+ void dispatchLoadAfter(int currentEndIndex, @NonNull Value currentEndItem, int pageSize,
+ @NonNull Executor mainThreadExecutor,
+ @NonNull PageResult.Receiver<Value> receiver) {
int startIndex = currentEndIndex + 1;
- mPositionalDataSource.loadRange(startIndex, pageSize, callback);
+ mPositionalDataSource.dispatchLoadRange(
+ startIndex, pageSize, mainThreadExecutor, receiver);
}
@Override
- void loadBefore(int currentBeginIndex, @NonNull Value currentBeginItem, int pageSize,
- @NonNull LoadCallback<Value> callback) {
+ void dispatchLoadBefore(int currentBeginIndex, @NonNull Value currentBeginItem,
+ int pageSize, @NonNull Executor mainThreadExecutor,
+ @NonNull PageResult.Receiver<Value> receiver) {
+
int startIndex = currentBeginIndex - 1;
if (startIndex < 0) {
- callback.onResult(Collections.<Value>emptyList());
+ // trigger empty list load
+ mPositionalDataSource.dispatchLoadRange(
+ startIndex, 0, mainThreadExecutor, receiver);
} else {
int loadSize = Math.min(pageSize, startIndex + 1);
startIndex = startIndex - loadSize + 1;
- mPositionalDataSource.loadRange(startIndex, loadSize, callback);
+ mPositionalDataSource.dispatchLoadRange(
+ startIndex, loadSize, mainThreadExecutor, receiver);
}
}
diff --git a/paging/common/src/main/java/android/arch/paging/TiledDataSource.java b/paging/common/src/main/java/android/arch/paging/TiledDataSource.java
index 27aeda0..77695e5 100644
--- a/paging/common/src/main/java/android/arch/paging/TiledDataSource.java
+++ b/paging/common/src/main/java/android/arch/paging/TiledDataSource.java
@@ -46,18 +46,17 @@
public abstract List<T> loadRange(int startPosition, int count);
@Override
- public void loadInitial(int requestedStartPosition, int requestedLoadSize, int pageSize,
- @NonNull InitialLoadCallback<T> callback) {
+ public void loadInitial(@NonNull LoadInitialParams params,
+ @NonNull LoadInitialCallback<T> callback) {
int totalCount = countItems();
if (totalCount == 0) {
- callback.onResult(Collections.<T>emptyList());
+ callback.onResult(Collections.<T>emptyList(), 0, 0);
return;
}
// bound the size requested, based on known count
- final int firstLoadPosition = computeFirstLoadPosition(
- requestedStartPosition, requestedLoadSize, pageSize, totalCount);
- final int firstLoadSize = Math.min(totalCount - firstLoadPosition, requestedLoadSize);
+ final int firstLoadPosition = computeInitialLoadPosition(params, totalCount);
+ final int firstLoadSize = computeInitialLoadSize(params, firstLoadPosition, totalCount);
// convert from legacy behavior
List<T> list = loadRange(firstLoadPosition, firstLoadSize);
@@ -69,8 +68,9 @@
}
@Override
- public void loadRange(int startPosition, int count, @NonNull LoadCallback<T> callback) {
- List<T> list = loadRange(startPosition, count);
+ public void loadRange(@NonNull LoadRangeParams params,
+ @NonNull LoadRangeCallback<T> callback) {
+ List<T> list = loadRange(params.startPosition, params.loadSize);
if (list != null) {
callback.onResult(list);
} else {
diff --git a/paging/common/src/main/java/android/arch/paging/TiledPagedList.java b/paging/common/src/main/java/android/arch/paging/TiledPagedList.java
index 652b489..f7aae98 100644
--- a/paging/common/src/main/java/android/arch/paging/TiledPagedList.java
+++ b/paging/common/src/main/java/android/arch/paging/TiledPagedList.java
@@ -92,15 +92,8 @@
final int idealStart = position - firstLoadSize / 2;
final int roundedPageStart = Math.max(0, Math.round(idealStart / pageSize) * pageSize);
- DataSource.InitialLoadCallback<T> callback = new DataSource.InitialLoadCallback<>(
- DataSource.LOAD_COUNT_REQUIRED_TILED,
- mConfig.pageSize, mDataSource, mReceiver);
- mDataSource.loadInitial(roundedPageStart, firstLoadSize, pageSize, callback);
-
- // If initialLoad's callback is not called within the body, we force any following calls
- // to post to the UI thread. This constructor may be run on a background thread, but
- // after constructor, mutation must happen on UI thread.
- callback.setPostExecutor(mMainThreadExecutor);
+ mDataSource.dispatchLoadInitial(true, roundedPageStart, firstLoadSize,
+ pageSize, mMainThreadExecutor, mReceiver);
}
}
@@ -185,10 +178,8 @@
} else {
int startPosition = pageIndex * pageSize;
int count = Math.min(pageSize, mStorage.size() - startPosition);
- DataSource.LoadCallback<T> callback = new DataSource.LoadCallback<>(
- PageResult.TILE, mMainThreadExecutor, mDataSource, mReceiver);
- callback.setPositionOffset(startPosition);
- mDataSource.loadRange(startPosition, count, callback);
+ mDataSource.dispatchLoadRange(
+ startPosition, count, mMainThreadExecutor, mReceiver);
}
}
});
diff --git a/paging/common/src/test/java/android/arch/paging/AsyncListDataSource.kt b/paging/common/src/test/java/android/arch/paging/AsyncListDataSource.kt
index 48d6e29..e1c113d 100644
--- a/paging/common/src/test/java/android/arch/paging/AsyncListDataSource.kt
+++ b/paging/common/src/test/java/android/arch/paging/AsyncListDataSource.kt
@@ -18,19 +18,18 @@
class AsyncListDataSource<T>(list: List<T>)
: PositionalDataSource<T>() {
- val workItems: MutableList<() -> Unit> = ArrayList()
+ private val workItems: MutableList<() -> Unit> = ArrayList()
private val listDataSource = ListDataSource(list)
- override fun loadInitial(requestedStartPosition: Int, requestedLoadSize: Int, pageSize: Int,
- callback: InitialLoadCallback<T>) {
+ override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback<T>) {
workItems.add {
- listDataSource.loadInitial(requestedStartPosition, requestedLoadSize, pageSize, callback)
+ listDataSource.loadInitial(params, callback)
}
}
- override fun loadRange(startPosition: Int, count: Int, callback: LoadCallback<T>) {
+ override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<T>) {
workItems.add {
- listDataSource.loadRange(startPosition, count, callback)
+ listDataSource.loadRange(params, callback)
}
}
diff --git a/paging/common/src/test/java/android/arch/paging/ContiguousPagedListTest.kt b/paging/common/src/test/java/android/arch/paging/ContiguousPagedListTest.kt
index 5ae0f9f..cc53c1b 100644
--- a/paging/common/src/test/java/android/arch/paging/ContiguousPagedListTest.kt
+++ b/paging/common/src/test/java/android/arch/paging/ContiguousPagedListTest.kt
@@ -27,7 +27,7 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.verifyZeroInteractions
-
+import java.util.concurrent.Executor
@RunWith(Parameterized::class)
class ContiguousPagedListTest(private val mCounted: Boolean) {
@@ -44,33 +44,56 @@
private inner class TestSource(val listData: List<Item> = ITEMS)
: ContiguousDataSource<Int, Item>() {
- override fun loadInitial(key: Int?, initialLoadSize: Int,
- enablePlaceholders: Boolean, callback: InitialLoadCallback<Item>) {
+ override fun dispatchLoadInitial(
+ key: Int?,
+ initialLoadSize: Int,
+ pageSize: Int,
+ enablePlaceholders: Boolean,
+ mainThreadExecutor: Executor,
+ receiver: PageResult.Receiver<Item>) {
val convertPosition = key ?: 0
- val loadPosition = Math.max(0, (convertPosition - initialLoadSize / 2))
-
- val data = getClampedRange(loadPosition, loadPosition + initialLoadSize)
-
+ val position = Math.max(0, (convertPosition - initialLoadSize / 2))
+ val data = getClampedRange(position, position + initialLoadSize)
+ val trailingUnloadedCount = listData.size - position - data.size
if (enablePlaceholders && mCounted) {
- callback.onResult(data, loadPosition, listData.size)
+ receiver.onPageResult(PageResult.INIT,
+ PageResult(data, position, trailingUnloadedCount, 0))
} else {
// still must pass offset, even if not counted
- callback.onResult(data, loadPosition)
+ receiver.onPageResult(PageResult.INIT,
+ PageResult(data, position))
}
}
- override fun loadAfter(currentEndIndex: Int, currentEndItem: Item, pageSize: Int,
- callback: LoadCallback<Item>) {
+ override fun dispatchLoadAfter(
+ currentEndIndex: Int,
+ currentEndItem: Item,
+ pageSize: Int,
+ mainThreadExecutor: Executor,
+ receiver: PageResult.Receiver<Item>) {
val startIndex = currentEndIndex + 1
- callback.onResult(getClampedRange(startIndex, startIndex + pageSize))
+ val data = getClampedRange(startIndex, startIndex + pageSize)
+
+ mainThreadExecutor.execute {
+ receiver.onPageResult(PageResult.APPEND, PageResult(data, 0, 0, 0))
+ }
}
- override fun loadBefore(currentBeginIndex: Int, currentBeginItem: Item, pageSize: Int,
- callback: LoadCallback<Item>) {
+ override fun dispatchLoadBefore(
+ currentBeginIndex: Int,
+ currentBeginItem: Item,
+ pageSize: Int,
+ mainThreadExecutor: Executor,
+ receiver: PageResult.Receiver<Item>) {
+
val startIndex = currentBeginIndex - 1
- callback.onResult(getClampedRange(startIndex - pageSize + 1, startIndex + 1))
+ val data = getClampedRange(startIndex - pageSize + 1, startIndex + 1)
+
+ mainThreadExecutor.execute {
+ receiver.onPageResult(PageResult.PREPEND, PageResult(data, 0, 0, 0))
+ }
}
override fun getKey(position: Int, item: Item?): Int {
@@ -95,7 +118,6 @@
actual.storageCount)
assertEquals(start, actual.leadingNullCount)
assertEquals(expectedTrailing, actual.trailingNullCount)
-
} else {
assertEquals(ITEMS.subList(start, start + count), actual)
@@ -116,8 +138,8 @@
initLoadSize: Int = 40,
prefetchDistance: Int = 20,
listData: List<Item> = ITEMS,
- boundaryCallback: PagedList.BoundaryCallback<Item>? = null)
- : ContiguousPagedList<Int, Item> {
+ boundaryCallback: PagedList.BoundaryCallback<Item>? = null
+ ): ContiguousPagedList<Int, Item> {
return ContiguousPagedList(
TestSource(listData), mMainThread, mBackgroundThread, boundaryCallback,
PagedList.Config.Builder()
@@ -294,6 +316,8 @@
val pagedList = ContiguousPagedList(
dataSource, mMainThread, mBackgroundThread, null,
PagedList.Config.Builder().setPageSize(10).build(), null)
+ val callback = mock(PagedList.Callback::class.java)
+ pagedList.addWeakCallback(null, callback)
assertTrue(pagedList.isEmpty())
drain()
@@ -302,11 +326,14 @@
assertTrue(pagedList.isEmpty())
mBackgroundThread.executeAll()
assertTrue(pagedList.isEmpty())
+ verifyZeroInteractions(callback)
// Data source defers callbacks until flush, which posts result to main thread
mMainThread.executeAll()
assertFalse(pagedList.isEmpty())
-
+ // callback onInsert called once with initial size
+ verify(callback).onInserted(0, pagedList.size)
+ verifyNoMoreInteractions(callback)
}
@Test
@@ -367,7 +394,6 @@
initLoadSize = 20, prefetchDistance = 5, boundaryCallback = boundaryCallback)
verifyRange(80, 20, pagedList)
-
// nothing yet
verifyZeroInteractions(boundaryCallback)
drain()
@@ -380,7 +406,6 @@
verify(boundaryCallback).onItemAtEndLoaded(ITEMS.last())
verifyNoMoreInteractions(boundaryCallback)
-
// prepending doesn't trigger callback...
pagedList.loadAround(if (mCounted) 80 else 0)
drain()
diff --git a/paging/common/src/test/java/android/arch/paging/TestExecutor.kt b/paging/common/src/test/java/android/arch/paging/Executors.kt
similarity index 79%
rename from paging/common/src/test/java/android/arch/paging/TestExecutor.kt
rename to paging/common/src/test/java/android/arch/paging/Executors.kt
index 7034aa0..e1c45a7 100644
--- a/paging/common/src/test/java/android/arch/paging/TestExecutor.kt
+++ b/paging/common/src/test/java/android/arch/paging/Executors.kt
@@ -16,14 +16,15 @@
package android.arch.paging
+import org.junit.Assert.fail
import java.util.LinkedList
import java.util.concurrent.Executor
class TestExecutor : Executor {
private val mTasks = LinkedList<Runnable>()
- override fun execute(command: Runnable) {
- mTasks.add(command)
+ override fun execute(runnable: Runnable) {
+ mTasks.add(runnable)
}
internal fun executeAll(): Boolean {
@@ -37,3 +38,9 @@
return consumed
}
}
+
+class FailExecutor(val string: String = "Executor expected to be unused") : Executor {
+ override fun execute(runnable: Runnable?) {
+ fail(string)
+ }
+}
diff --git a/paging/common/src/test/java/android/arch/paging/KeyedDataSourceTest.kt b/paging/common/src/test/java/android/arch/paging/ItemKeyedDataSourceTest.kt
similarity index 60%
rename from paging/common/src/test/java/android/arch/paging/KeyedDataSourceTest.kt
rename to paging/common/src/test/java/android/arch/paging/ItemKeyedDataSourceTest.kt
index 82ad9ac..4998d06 100644
--- a/paging/common/src/test/java/android/arch/paging/KeyedDataSourceTest.kt
+++ b/paging/common/src/test/java/android/arch/paging/ItemKeyedDataSourceTest.kt
@@ -19,6 +19,7 @@
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
+import org.junit.Assert.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -29,7 +30,7 @@
import org.mockito.Mockito.verifyNoMoreInteractions
@RunWith(JUnit4::class)
-class KeyedDataSourceTest {
+class ItemKeyedDataSourceTest {
// ----- STANDARD -----
@@ -41,10 +42,8 @@
val captor = ArgumentCaptor.forClass(PageResult::class.java)
as ArgumentCaptor<PageResult<Item>>
- val callback = DataSource.InitialLoadCallback(
- DataSource.LOAD_COUNT_ACCEPTED, /* ignored page size */ 10, dataSource, receiver)
-
- dataSource.loadInitial(key, initialLoadSize, enablePlaceholders, callback)
+ dataSource.dispatchLoadInitial(key, initialLoadSize,
+ /* ignored pageSize */ 10, enablePlaceholders, FailExecutor(), receiver)
verify(receiver).onPageResult(anyInt(), captor.capture())
verifyNoMoreInteractions(receiver)
@@ -91,7 +90,7 @@
fun loadInitial_nullKey() {
val dataSource = ItemDataSource()
- // loadInitial(null, count) == loadInitial(count)
+ // dispatchLoadInitial(null, count) == dispatchLoadInitial(count)
val result = loadInitial(dataSource, null, 10, true)
assertEquals(0, result.leadingNulls)
@@ -121,7 +120,7 @@
fun loadInitial_disablePlaceholders() {
val dataSource = ItemDataSource()
- // loadInitial(key, count) == null padding, loadAfter(key, count), null padding
+ // dispatchLoadInitial(key, count) == null padding, loadAfter(key, count), null padding
val key = dataSource.getKey(ITEMS_BY_NAME_ID[49])
val result = loadInitial(dataSource, key, 10, false)
@@ -134,7 +133,7 @@
fun loadInitial_uncounted() {
val dataSource = ItemDataSource(counted = false)
- // loadInitial(key, count) == null padding, loadAfter(key, count), null padding
+ // dispatchLoadInitial(key, count) == null padding, loadAfter(key, count), null padding
val key = dataSource.getKey(ITEMS_BY_NAME_ID[49])
val result = loadInitial(dataSource, key, 10, true)
@@ -147,7 +146,7 @@
fun loadInitial_nullKey_uncounted() {
val dataSource = ItemDataSource(counted = false)
- // loadInitial(null, count) == loadInitial(count)
+ // dispatchLoadInitial(null, count) == dispatchLoadInitial(count)
val result = loadInitial(dataSource, null, 10, true)
assertEquals(0, result.leadingNulls)
@@ -161,7 +160,7 @@
fun loadInitial_empty() {
val dataSource = ItemDataSource(items = ArrayList())
- // loadInitial(key, count) == null padding, loadAfter(key, count), null padding
+ // dispatchLoadInitial(key, count) == null padding, loadAfter(key, count), null padding
val key = dataSource.getKey(ITEMS_BY_NAME_ID[49])
val result = loadInitial(dataSource, key, 10, true)
@@ -186,9 +185,11 @@
fun loadBefore() {
val dataSource = ItemDataSource()
@Suppress("UNCHECKED_CAST")
- val callback = mock(DataSource.LoadCallback::class.java) as DataSource.LoadCallback<Item>
+ val callback = mock(ItemKeyedDataSource.LoadCallback::class.java)
+ as ItemKeyedDataSource.LoadCallback<Item>
- dataSource.loadBefore(5, ITEMS_BY_NAME_ID[5], 5, callback)
+ dataSource.loadBefore(
+ ItemKeyedDataSource.LoadParams(dataSource.getKey(ITEMS_BY_NAME_ID[5]), 5), callback)
@Suppress("UNCHECKED_CAST")
val argument = ArgumentCaptor.forClass(List::class.java) as ArgumentCaptor<List<Item>>
@@ -207,32 +208,33 @@
internal class ItemDataSource(private val counted: Boolean = true,
private val items: List<Item> = ITEMS_BY_NAME_ID)
- : KeyedDataSource<Key, Item>() {
- override fun loadInitial(initialLoadKey: Key?, initialLoadSize: Int,
- enablePlaceholders: Boolean, callback: InitialLoadCallback<Item>) {
- val key = initialLoadKey ?: Key("", Integer.MAX_VALUE)
- val start = Math.max(0, findFirstIndexAfter(key) - initialLoadSize / 2)
- val endExclusive = Math.min(start + initialLoadSize, items.size)
+ : ItemKeyedDataSource<Key, Item>() {
+ override fun loadInitial(
+ params: LoadInitialParams<Key>,
+ callback: LoadInitialCallback<Item>) {
+ val key = params.requestedInitialKey ?: Key("", Integer.MAX_VALUE)
+ val start = Math.max(0, findFirstIndexAfter(key) - params.requestedLoadSize / 2)
+ val endExclusive = Math.min(start + params.requestedLoadSize, items.size)
- if (enablePlaceholders && counted) {
+ if (params.placeholdersEnabled && counted) {
callback.onResult(items.subList(start, endExclusive), start, items.size)
} else {
callback.onResult(items.subList(start, endExclusive))
}
}
- override fun loadAfter(currentEndKey: Key, pageSize: Int, callback: LoadCallback<Item>) {
- val start = findFirstIndexAfter(currentEndKey)
- val endExclusive = Math.min(start + pageSize, items.size)
+ override fun loadAfter(params: LoadParams<Key>, callback: LoadCallback<Item>) {
+ val start = findFirstIndexAfter(params.key)
+ val endExclusive = Math.min(start + params.requestedLoadSize, items.size)
callback.onResult(items.subList(start, endExclusive))
}
- override fun loadBefore(currentBeginKey: Key, pageSize: Int, callback: LoadCallback<Item>) {
- val firstIndexBefore = findFirstIndexBefore(currentBeginKey)
+ override fun loadBefore(params: LoadParams<Key>, callback: LoadCallback<Item>) {
+ val firstIndexBefore = findFirstIndexBefore(params.key)
val endExclusive = Math.max(0, firstIndexBefore + 1)
- val start = Math.max(0, firstIndexBefore - pageSize + 1)
+ val start = Math.max(0, firstIndexBefore - params.requestedLoadSize + 1)
callback.onResult(items.subList(start, endExclusive))
}
@@ -254,16 +256,94 @@
}
}
+ private fun performLoadInitial(
+ invalidateDataSource: Boolean = false,
+ callbackInvoker: (callback: ItemKeyedDataSource.LoadInitialCallback<String>) -> Unit) {
+ val dataSource = object : ItemKeyedDataSource<String, String>() {
+ override fun getKey(item: String): String {
+ return ""
+ }
+
+ override fun loadInitial(
+ params: LoadInitialParams<String>,
+ callback: LoadInitialCallback<String>) {
+ if (invalidateDataSource) {
+ // invalidate data source so it's invalid when onResult() called
+ invalidate()
+ }
+ callbackInvoker(callback)
+ }
+
+ override fun loadAfter(params: LoadParams<String>, callback: LoadCallback<String>) {
+ fail("loadAfter not expected")
+ }
+
+ override fun loadBefore(params: LoadParams<String>, callback: LoadCallback<String>) {
+ fail("loadBefore not expected")
+ }
+ }
+
+ ContiguousPagedList<String, String>(
+ dataSource, FailExecutor(), FailExecutor(), null,
+ PagedList.Config.Builder()
+ .setPageSize(10)
+ .build(),
+ "")
+ }
+
+ @Test
+ fun loadInitialCallbackSuccess() = performLoadInitial {
+ // LoadInitialCallback correct usage
+ it.onResult(listOf("a", "b"), 0, 2)
+ }
+
+ @Test
+ fun loadInitialCallbackNotPageSizeMultiple() = performLoadInitial {
+ // Keyed LoadInitialCallback *can* accept result that's not a multiple of page size
+ val elevenLetterList = List(11) { "" + 'a' + it }
+ it.onResult(elevenLetterList, 0, 12)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun loadInitialCallbackListTooBig() = performLoadInitial {
+ // LoadInitialCallback can't accept pos + list > totalCount
+ it.onResult(listOf("a", "b", "c"), 0, 2)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun loadInitialCallbackPositionTooLarge() = performLoadInitial {
+ // LoadInitialCallback can't accept pos + list > totalCount
+ it.onResult(listOf("a", "b"), 1, 2)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun loadInitialCallbackPositionNegative() = performLoadInitial {
+ // LoadInitialCallback can't accept negative position
+ it.onResult(listOf("a", "b", "c"), -1, 2)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun loadInitialCallbackEmptyCannotHavePlaceholders() = performLoadInitial {
+ // LoadInitialCallback can't accept empty result unless data set is empty
+ it.onResult(emptyList(), 0, 2)
+ }
+
+ @Test
+ fun initialLoadCallbackInvalidThreeArg() = performLoadInitial(invalidateDataSource = true) {
+ // LoadInitialCallback doesn't throw on invalid args if DataSource is invalid
+ it.onResult(emptyList(), 0, 1)
+ }
+
companion object {
- private val ITEM_COMPARATOR = compareBy<Item>( {it.name} ).thenByDescending( {it.id} )
- private val KEY_COMPARATOR = compareBy<Key>( {it.name} ).thenByDescending( {it.id} )
+ private val ITEM_COMPARATOR = compareBy<Item>({ it.name }).thenByDescending({ it.id })
+ private val KEY_COMPARATOR = compareBy<Key>({ it.name }).thenByDescending({ it.id })
private val ITEMS_BY_NAME_ID = List(100) {
val names = Array(10) { "f" + ('a' + it) }
Item(names[it % 10],
- it,
- Math.random() * 1000,
- (Math.random() * 200).toInt().toString() + " fake st.")
+ it,
+ Math.random() * 1000,
+ (Math.random() * 200).toInt().toString() + " fake st.")
}.sortedWith(ITEM_COMPARATOR)
}
}
diff --git a/paging/common/src/test/java/android/arch/paging/PageKeyedDataSourceTest.kt b/paging/common/src/test/java/android/arch/paging/PageKeyedDataSourceTest.kt
new file mode 100644
index 0000000..d4bbbb5
--- /dev/null
+++ b/paging/common/src/test/java/android/arch/paging/PageKeyedDataSourceTest.kt
@@ -0,0 +1,187 @@
+/*
+ * 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 android.arch.paging
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.fail
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class PageKeyedDataSourceTest {
+ private val mMainThread = TestExecutor()
+ private val mBackgroundThread = TestExecutor()
+
+ internal data class Item(val name: String)
+
+ internal data class Page(val prev: String?, val data: List<Item>, val next: String?)
+
+ internal class ItemDataSource(val data: Map<String, Page> = PAGE_MAP)
+ : PageKeyedDataSource<String, Item>() {
+
+ private fun getPage(key: String): Page = data[key]!!
+
+ override fun loadInitial(
+ params: LoadInitialParams<String>,
+ callback: LoadInitialCallback<String, Item>) {
+ val page = getPage(INIT_KEY)
+ callback.onResult(page.data, page.prev, page.next)
+ }
+
+ override fun loadBefore(params: LoadParams<String>, callback: LoadCallback<String, Item>) {
+ val page = getPage(params.key)
+ callback.onResult(page.data, page.prev)
+ }
+
+ override fun loadAfter(params: LoadParams<String>, callback: LoadCallback<String, Item>) {
+ val page = getPage(params.key)
+ callback.onResult(page.data, page.next)
+ }
+ }
+
+ @Test
+ fun loadFullVerify() {
+ // validate paging entire ItemDataSource results in full, correctly ordered data
+ val pagedList = ContiguousPagedList<String, Item>(ItemDataSource(),
+ mMainThread, mBackgroundThread,
+ null, PagedList.Config.Builder().setPageSize(100).build(), null)
+
+ // validate initial load
+ assertEquals(PAGE_MAP[INIT_KEY]!!.data, pagedList)
+
+ // flush the remaining loads
+ for (i in 0..PAGE_MAP.keys.size) {
+ pagedList.loadAround(0)
+ pagedList.loadAround(pagedList.size - 1)
+ drain()
+ }
+
+ // validate full load
+ assertEquals(ITEM_LIST, pagedList)
+ }
+
+ private fun performLoadInitial(invalidateDataSource: Boolean = false,
+ callbackInvoker:
+ (callback: PageKeyedDataSource.LoadInitialCallback<String, String>) -> Unit) {
+ val dataSource = object : PageKeyedDataSource<String, String>() {
+ override fun loadInitial(
+ params: LoadInitialParams<String>,
+ callback: LoadInitialCallback<String, String>) {
+ if (invalidateDataSource) {
+ // invalidate data source so it's invalid when onResult() called
+ invalidate()
+ }
+ callbackInvoker(callback)
+ }
+
+ override fun loadBefore(
+ params: LoadParams<String>,
+ callback: LoadCallback<String, String>) {
+ fail("loadBefore not expected")
+ }
+
+ override fun loadAfter(
+ params: LoadParams<String>,
+ callback: LoadCallback<String, String>) {
+ fail("loadAfter not expected")
+ }
+ }
+
+ ContiguousPagedList<String, String>(
+ dataSource, FailExecutor(), FailExecutor(), null,
+ PagedList.Config.Builder()
+ .setPageSize(10)
+ .build(),
+ "")
+ }
+
+ @Test
+ fun loadInitialCallbackSuccess() = performLoadInitial {
+ // LoadInitialCallback correct usage
+ it.onResult(listOf("a", "b"), 0, 2, null, null)
+ }
+
+ @Test
+ fun loadInitialCallbackNotPageSizeMultiple() = performLoadInitial {
+ // Keyed LoadInitialCallback *can* accept result that's not a multiple of page size
+ val elevenLetterList = List(11) { "" + 'a' + it }
+ it.onResult(elevenLetterList, 0, 12, null, null)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun loadInitialCallbackListTooBig() = performLoadInitial {
+ // LoadInitialCallback can't accept pos + list > totalCount
+ it.onResult(listOf("a", "b", "c"), 0, 2, null, null)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun loadInitialCallbackPositionTooLarge() = performLoadInitial {
+ // LoadInitialCallback can't accept pos + list > totalCount
+ it.onResult(listOf("a", "b"), 1, 2, null, null)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun loadInitialCallbackPositionNegative() = performLoadInitial {
+ // LoadInitialCallback can't accept negative position
+ it.onResult(listOf("a", "b", "c"), -1, 2, null, null)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun loadInitialCallbackEmptyCannotHavePlaceholders() = performLoadInitial {
+ // LoadInitialCallback can't accept empty result unless data set is empty
+ it.onResult(emptyList(), 0, 2, null, null)
+ }
+
+ @Test
+ fun initialLoadCallbackInvalidThreeArg() = performLoadInitial(invalidateDataSource = true) {
+ // LoadInitialCallback doesn't throw on invalid args if DataSource is invalid
+ it.onResult(emptyList(), 0, 1, null, null)
+ }
+
+ companion object {
+ // first load is 2nd page to ensure we test prepend as well as append behavior
+ private val INIT_KEY: String = "key 2"
+ private val PAGE_MAP: Map<String, Page>
+ private val ITEM_LIST: List<Item>
+
+ init {
+ val map = HashMap<String, Page>()
+ val list = ArrayList<Item>()
+ val pageCount = 5
+ for (i in 1..pageCount) {
+ val data = List(4) { Item("name $i $it") }
+ list.addAll(data)
+
+ val key = "key $i"
+ val prev = if (i > 1) ("key " + (i - 1)) else null
+ val next = if (i < pageCount) ("key " + (i + 1)) else null
+ map.put(key, Page(prev, data, next))
+ }
+ PAGE_MAP = map
+ ITEM_LIST = list
+ }
+ }
+
+ private fun drain() {
+ var executed: Boolean
+ do {
+ executed = mBackgroundThread.executeAll()
+ executed = mMainThread.executeAll() || executed
+ } while (executed)
+ }
+}
diff --git a/paging/common/src/test/java/android/arch/paging/PagedStorageTest.kt b/paging/common/src/test/java/android/arch/paging/PagedStorageTest.kt
index 8fb54e0..9b53f62 100644
--- a/paging/common/src/test/java/android/arch/paging/PagedStorageTest.kt
+++ b/paging/common/src/test/java/android/arch/paging/PagedStorageTest.kt
@@ -48,7 +48,6 @@
val storage = PagedStorage(2, createPage("a", "b"), 2)
storage.appendPage(createPage("c", "d"), callback)
-
assertArrayEquals(arrayOf(null, null, "a", "b", "c", "d"), storage.toArray())
verify(callback).onPageAppended(4, 2, 0)
verifyNoMoreInteractions(callback)
@@ -106,7 +105,6 @@
val storage = PagedStorage(0, createPage("c", "d"), 2)
storage.prependPage(createPage("a", "b"), callback)
-
assertArrayEquals(arrayOf("a", "b", "c", "d", null, null), storage.toArray())
verify(callback).onPagePrepended(0, 0, 2)
verifyNoMoreInteractions(callback)
@@ -361,7 +359,6 @@
storage.allocatePlaceholders(0, 2, 1, callback)
}
-
@Test(expected = IllegalArgumentException::class)
fun allocatePlaceholders_cannotAdoptPageSize() {
val callback = mock(PagedStorage.Callback::class.java)
diff --git a/paging/common/src/test/java/android/arch/paging/PositionalDataSourceTest.kt b/paging/common/src/test/java/android/arch/paging/PositionalDataSourceTest.kt
index 34e0a57..1113777 100644
--- a/paging/common/src/test/java/android/arch/paging/PositionalDataSourceTest.kt
+++ b/paging/common/src/test/java/android/arch/paging/PositionalDataSourceTest.kt
@@ -17,34 +17,170 @@
package android.arch.paging
import org.junit.Assert.assertEquals
+import org.junit.Assert.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@RunWith(JUnit4::class)
class PositionalDataSourceTest {
- @Test
- fun computeFirstLoadPositionZero() {
- assertEquals(0, PositionalDataSource.computeFirstLoadPosition(0, 30, 10, 100))
+ private fun computeInitialLoadPos(
+ requestedStartPosition: Int,
+ requestedLoadSize: Int,
+ pageSize: Int,
+ totalCount: Int): Int {
+ val params = PositionalDataSource.LoadInitialParams(
+ requestedStartPosition, requestedLoadSize, pageSize, true)
+ return PositionalDataSource.computeInitialLoadPosition(params, totalCount)
}
@Test
- fun computeFirstLoadPositionRequestedPositionIncluded() {
- assertEquals(10, PositionalDataSource.computeFirstLoadPosition(10, 10, 10, 100))
+ fun computeInitialLoadPositionZero() {
+ assertEquals(0, computeInitialLoadPos(
+ requestedStartPosition = 0,
+ requestedLoadSize = 30,
+ pageSize = 10,
+ totalCount = 100))
}
@Test
- fun computeFirstLoadPositionRound() {
- assertEquals(10, PositionalDataSource.computeFirstLoadPosition(13, 30, 10, 100))
+ fun computeInitialLoadPositionRequestedPositionIncluded() {
+ assertEquals(10, computeInitialLoadPos(
+ requestedStartPosition = 10,
+ requestedLoadSize = 10,
+ pageSize = 10,
+ totalCount = 100))
}
@Test
- fun computeFirstLoadPositionEndAdjusted() {
- assertEquals(70, PositionalDataSource.computeFirstLoadPosition(99, 30, 10, 100))
+ fun computeInitialLoadPositionRound() {
+ assertEquals(10, computeInitialLoadPos(
+ requestedStartPosition = 13,
+ requestedLoadSize = 30,
+ pageSize = 10,
+ totalCount = 100))
}
@Test
- fun computeFirstLoadPositionEndAdjustedAndAligned() {
- assertEquals(70, PositionalDataSource.computeFirstLoadPosition(99, 35, 10, 100))
+ fun computeInitialLoadPositionEndAdjusted() {
+ assertEquals(70, computeInitialLoadPos(
+ requestedStartPosition = 99,
+ requestedLoadSize = 30,
+ pageSize = 10,
+ totalCount = 100))
+ }
+
+ @Test
+ fun computeInitialLoadPositionEndAdjustedAndAligned() {
+ assertEquals(70, computeInitialLoadPos(
+ requestedStartPosition = 99,
+ requestedLoadSize = 35,
+ pageSize = 10,
+ totalCount = 100))
+ }
+
+ private fun performLoadInitial(
+ enablePlaceholders: Boolean = true,
+ invalidateDataSource: Boolean = false,
+ callbackInvoker: (callback: PositionalDataSource.LoadInitialCallback<String>) -> Unit) {
+ val dataSource = object : PositionalDataSource<String>() {
+ override fun loadInitial(
+ params: LoadInitialParams,
+ callback: LoadInitialCallback<String>) {
+ if (invalidateDataSource) {
+ // invalidate data source so it's invalid when onResult() called
+ invalidate()
+ }
+ callbackInvoker(callback)
+ }
+
+ override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<String>) {
+ fail("loadRange not expected")
+ }
+ }
+
+ val config = PagedList.Config.Builder()
+ .setPageSize(10)
+ .setEnablePlaceholders(enablePlaceholders)
+ .build()
+ if (enablePlaceholders) {
+ TiledPagedList(dataSource, FailExecutor(), FailExecutor(), null, config, 0)
+ } else {
+ ContiguousPagedList(dataSource.wrapAsContiguousWithoutPlaceholders(),
+ FailExecutor(), FailExecutor(), null, config, null)
+ }
+ }
+
+ @Test
+ fun initialLoadCallbackSuccess() = performLoadInitial {
+ // LoadInitialCallback correct usage
+ it.onResult(listOf("a", "b"), 0, 2)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun initialLoadCallbackNotPageSizeMultiple() = performLoadInitial {
+ // Positional LoadInitialCallback can't accept result that's not a multiple of page size
+ val elevenLetterList = List(11) { "" + 'a' + it }
+ it.onResult(elevenLetterList, 0, 12)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun initialLoadCallbackListTooBig() = performLoadInitial {
+ // LoadInitialCallback can't accept pos + list > totalCount
+ it.onResult(listOf("a", "b", "c"), 0, 2)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun initialLoadCallbackPositionTooLarge() = performLoadInitial {
+ // LoadInitialCallback can't accept pos + list > totalCount
+ it.onResult(listOf("a", "b"), 1, 2)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun initialLoadCallbackPositionNegative() = performLoadInitial {
+ // LoadInitialCallback can't accept negative position
+ it.onResult(listOf("a", "b", "c"), -1, 2)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun initialLoadCallbackEmptyCannotHavePlaceholders() = performLoadInitial {
+ // LoadInitialCallback can't accept empty result unless data set is empty
+ it.onResult(emptyList(), 0, 2)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun initialLoadCallbackRequireTotalCount() = performLoadInitial(enablePlaceholders = true) {
+ // LoadInitialCallback requires 3 args when placeholders enabled
+ it.onResult(listOf("a", "b"), 0)
+ }
+
+ @Test
+ fun initialLoadCallbackSuccessTwoArg() = performLoadInitial(enablePlaceholders = false) {
+ // LoadInitialCallback correct 2 arg usage
+ it.onResult(listOf("a", "b"), 0)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun initialLoadCallbackPosNegativeTwoArg() = performLoadInitial(enablePlaceholders = false) {
+ // LoadInitialCallback can't accept negative position
+ it.onResult(listOf("a", "b"), -1)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun initialLoadCallbackEmptyWithOffset() = performLoadInitial(enablePlaceholders = false) {
+ // LoadInitialCallback can't accept empty result unless pos is 0
+ it.onResult(emptyList(), 1)
+ }
+
+ @Test
+ fun initialLoadCallbackInvalidTwoArg() = performLoadInitial(invalidateDataSource = true) {
+ // LoadInitialCallback doesn't throw on invalid args if DataSource is invalid
+ it.onResult(emptyList(), 1)
+ }
+
+ @Test
+ fun initialLoadCallbackInvalidThreeArg() = performLoadInitial(invalidateDataSource = true) {
+ // LoadInitialCallback doesn't throw on invalid args if DataSource is invalid
+ it.onResult(emptyList(), 0, 1)
}
}
diff --git a/paging/common/src/test/java/android/arch/paging/TiledDataSourceTest.kt b/paging/common/src/test/java/android/arch/paging/TiledDataSourceTest.kt
index fe8b9e8..f41e6a6 100644
--- a/paging/common/src/test/java/android/arch/paging/TiledDataSourceTest.kt
+++ b/paging/common/src/test/java/android/arch/paging/TiledDataSourceTest.kt
@@ -31,15 +31,12 @@
@RunWith(JUnit4::class)
class TiledDataSourceTest {
- fun TiledDataSource<String>.loadInitial(startPosition: Int, count: Int, pageSize: Int)
- : List<String> {
+ fun TiledDataSource<String>.loadInitial(
+ startPosition: Int, count: Int, pageSize: Int): List<String> {
@Suppress("UNCHECKED_CAST")
val receiver = mock(PageResult.Receiver::class.java) as PageResult.Receiver<String>
- val callback = DataSource.InitialLoadCallback(
- DataSource.LOAD_COUNT_REQUIRED_TILED, pageSize, this, receiver)
-
- this.loadInitial(startPosition, count, pageSize, callback)
+ this.dispatchLoadInitial(true, startPosition, count, pageSize, FailExecutor(), receiver)
@Suppress("UNCHECKED_CAST")
val argument = ArgumentCaptor.forClass(PageResult::class.java)
@@ -69,7 +66,7 @@
@Test
fun loadInitialTooLong() {
- val list = List(26) { "" + 'a' + it}
+ val list = List(26) { "" + 'a' + it }
class AlphabetDataSource : TiledDataSource<String>() {
override fun countItems(): Int {
return list.size
diff --git a/paging/common/src/test/java/android/arch/paging/TiledPagedListTest.kt b/paging/common/src/test/java/android/arch/paging/TiledPagedListTest.kt
index 3e2a60d..9069a1a 100644
--- a/paging/common/src/test/java/android/arch/paging/TiledPagedListTest.kt
+++ b/paging/common/src/test/java/android/arch/paging/TiledPagedListTest.kt
@@ -21,7 +21,6 @@
import org.junit.Assert.assertNull
import org.junit.Assert.assertSame
import org.junit.Assert.assertTrue
-import org.junit.Assert.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -399,74 +398,6 @@
verifyNoMoreInteractions(boundaryCallback)
}
- private fun performInitialLoad(
- callbackInvoker: (callback: DataSource.InitialLoadCallback<String>) -> Unit) {
- val dataSource = object: PositionalDataSource<String>() {
- override fun loadInitial(requestedStartPosition: Int, requestedLoadSize: Int,
- pageSize: Int, callback: InitialLoadCallback<String>) {
- callbackInvoker(callback)
- }
- override fun loadRange(startPosition: Int, count: Int, callback: LoadCallback<String>) {
- fail("loadRange not expected")
- }
- }
- TiledPagedList(
- dataSource, mMainThread, mBackgroundThread, null,
- PagedList.Config.Builder()
- .setPageSize(PAGE_SIZE)
- .build(),
- 0)
- }
-
- @Test
- fun initialLoadCallbackSuccess() = performInitialLoad {
- // InitialLoadCallback correct usage
- it.onResult(listOf("a", "b"), 0, 2)
- }
-
- @Test
- fun initialLoadCallbackEmptySuccess() = performInitialLoad {
- // InitialLoadCallback correct usage - empty special case
- it.onResult(emptyList())
- }
-
- @Test(expected = IllegalArgumentException::class)
- fun initialLoadCallbackNotPageSizeMultiple() = performInitialLoad {
- // Positional InitialLoadCallback can't accept result that's not a multiple of page size
- val elevenLetterList = List(11) { "" + 'a' + it }
- it.onResult(elevenLetterList, 0, 12)
- }
-
- @Test(expected = IllegalArgumentException::class)
- fun initialLoadCallbackMissingPlaceholders() = performInitialLoad {
- // Positional InitialLoadCallback can't accept list-only call
- it.onResult(listOf("a", "b"))
- }
-
- @Test(expected = IllegalArgumentException::class)
- fun initialLoadCallbackListTooBig() = performInitialLoad {
- // InitialLoadCallback can't accept pos + list > totalCount
- it.onResult(listOf("a", "b", "c"), 0, 2)
- }
-
- @Test(expected = IllegalArgumentException::class)
- fun initialLoadCallbackPositionTooLarge() = performInitialLoad {
- // InitialLoadCallback can't accept pos + list > totalCount
- it.onResult(listOf("a", "b"), 1, 2)
- }
-
- @Test(expected = IllegalArgumentException::class)
- fun initialLoadCallbackPositionNegative() = performInitialLoad {
- // InitialLoadCallback can't accept negative position
- it.onResult(listOf("a", "b", "c"), -1, 2)
- }
-
- @Test(expected = IllegalArgumentException::class)
- fun initialLoadCallbackEmptyCannotHavePlaceholders() = performInitialLoad {
- // Positional InitialLoadCallback can't accept empty result unless data set is empty
- it.onResult(emptyList(), 0, 2)
- }
-
private fun drain() {
var executed: Boolean
do {
diff --git a/paging/integration-tests/testapp/build.gradle b/paging/integration-tests/testapp/build.gradle
index fb19ba0..99c2ef6 100644
--- a/paging/integration-tests/testapp/build.gradle
+++ b/paging/integration-tests/testapp/build.gradle
@@ -15,8 +15,6 @@
*/
apply plugin: 'com.android.application'
-project.ext.noDocs = true
-
android {
compileSdkVersion tools.current_sdk
buildToolsVersion tools.build_tools_version
@@ -45,20 +43,19 @@
}
dependencies {
- implementation project(':arch:runtime')
- implementation project(':arch:common')
- implementation project(':paging:common')
- implementation project(':lifecycle:extensions')
- implementation project(':lifecycle:runtime')
- implementation project(':lifecycle:common')
- implementation project(':paging:runtime')
+ implementation(project(":arch:runtime"))
+ implementation(project(":arch:common"))
+ implementation(project(":paging:common"))
+ implementation(project(":lifecycle:extensions"))
+ implementation(project(":lifecycle:runtime"))
+ implementation(project(":lifecycle:common"))
+ implementation(project(":paging:runtime"))
implementation 'com.android.support:multidex:1.0.1'
implementation libs.support.recyclerview, libs.support_exclude_config
implementation libs.support.app_compat, libs.support_exclude_config
}
-createAndroidCheckstyle(project)
tasks['check'].dependsOn(tasks['connectedCheck'])
uploadArchives.enabled = false
diff --git a/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/ItemDataSource.java b/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/ItemDataSource.java
index bbbfabb..c53d361 100644
--- a/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/ItemDataSource.java
+++ b/paging/integration-tests/testapp/src/main/java/android/arch/paging/integration/testapp/ItemDataSource.java
@@ -56,35 +56,19 @@
return items;
}
- // TODO: open up this API in PositionalDataSource?
- private static int computeFirstLoadPosition(int position, int firstLoadSize,
- int pageSize, int size) {
- int roundedPageStart = Math.round(position / pageSize) * pageSize;
-
- // minimum start position is 0
- roundedPageStart = Math.max(0, roundedPageStart);
-
- // maximum start pos is that which will encompass end of list
- int maximumLoadPage = ((size - firstLoadSize + pageSize - 1) / pageSize) * pageSize;
- roundedPageStart = Math.min(maximumLoadPage, roundedPageStart);
-
- return roundedPageStart;
+ @Override
+ public void loadInitial(@NonNull LoadInitialParams params,
+ @NonNull LoadInitialCallback<Item> callback) {
+ int position = computeInitialLoadPosition(params, COUNT);
+ int loadSize = computeInitialLoadSize(params, position, COUNT);
+ List<Item> data = loadRangeInternal(position, loadSize);
+ callback.onResult(data, position, COUNT);
}
@Override
- public void loadInitial(int requestedStartPosition, int requestedLoadSize,
- int pageSize, @NonNull InitialLoadCallback<Item> callback) {
- requestedStartPosition = computeFirstLoadPosition(
- requestedStartPosition, requestedLoadSize, pageSize, COUNT);
-
- requestedLoadSize = Math.min(COUNT - requestedStartPosition, requestedLoadSize);
- List<Item> data = loadRangeInternal(requestedStartPosition, requestedLoadSize);
- callback.onResult(data, requestedStartPosition, COUNT);
- }
-
- @Override
- public void loadRange(int startPosition, int count, @NonNull LoadCallback<Item> callback) {
- List<Item> data = loadRangeInternal(startPosition, count);
+ public void loadRange(@NonNull LoadRangeParams params,
+ @NonNull LoadRangeCallback<Item> callback) {
+ List<Item> data = loadRangeInternal(params.startPosition, params.loadSize);
callback.onResult(data);
}
}
diff --git a/paging/runtime/build.gradle b/paging/runtime/build.gradle
index 187acb9..1a2bd2d 100644
--- a/paging/runtime/build.gradle
+++ b/paging/runtime/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
import android.support.SupportLibraryExtension
@@ -30,25 +31,21 @@
}
dependencies {
- api project(":arch:runtime")
- api project(":paging:common")
- api project(":lifecycle:runtime")
- api project(':lifecycle:extensions')
+ api(project(":arch:runtime"))
+ api(project(":paging:common"))
+ api(project(":lifecycle:runtime"))
+ api(project(":lifecycle:extensions"))
api libs.support.recyclerview, libs.support_exclude_config
- androidTestImplementation libs.junit
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.kotlin.stdlib
-
+ androidTestImplementation(JUNIT)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(KOTLIN_STDLIB)
}
-createAndroidCheckstyle(project)
-createKotlinCheckstyle(project)
-
supportLibrary {
name = "Android Lifecycle Extensions"
publish = true
diff --git a/paging/runtime/lint-baseline.xml b/paging/runtime/lint-baseline.xml
deleted file mode 100644
index 2cadde1..0000000
--- a/paging/runtime/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0">
-
-</issues>
diff --git a/paging/runtime/src/androidTest/java/android/arch/paging/PagedListAdapterHelperTest.kt b/paging/runtime/src/androidTest/java/android/arch/paging/PagedListAdapterHelperTest.kt
index d3a910d..d50b8d9 100644
--- a/paging/runtime/src/androidTest/java/android/arch/paging/PagedListAdapterHelperTest.kt
+++ b/paging/runtime/src/androidTest/java/android/arch/paging/PagedListAdapterHelperTest.kt
@@ -41,7 +41,6 @@
private val mDiffThread = TestExecutor()
private val mPageLoadingThread = TestExecutor()
-
private fun <T> createHelper(listUpdateCallback: ListUpdateCallback,
diffCallback: DiffCallback<T>): PagedListAdapterHelper<T> {
return PagedListAdapterHelper(listUpdateCallback,
diff --git a/paging/runtime/src/androidTest/java/android/support/v7/recyclerview/extensions/ListAdapterHelperTest.kt b/paging/runtime/src/androidTest/java/android/support/v7/recyclerview/extensions/ListAdapterHelperTest.kt
index 433f4c1..85521af 100644
--- a/paging/runtime/src/androidTest/java/android/support/v7/recyclerview/extensions/ListAdapterHelperTest.kt
+++ b/paging/runtime/src/androidTest/java/android/support/v7/recyclerview/extensions/ListAdapterHelperTest.kt
@@ -114,7 +114,6 @@
verifyNoMoreInteractions(callback)
drain()
verifyNoMoreInteractions(callback)
-
}
private fun drain() {
diff --git a/paging/runtime/src/main/java/android/arch/paging/LivePagedListBuilder.java b/paging/runtime/src/main/java/android/arch/paging/LivePagedListBuilder.java
index b0fddba..f2d09cc 100644
--- a/paging/runtime/src/main/java/android/arch/paging/LivePagedListBuilder.java
+++ b/paging/runtime/src/main/java/android/arch/paging/LivePagedListBuilder.java
@@ -88,9 +88,21 @@
}
/**
- * Sets a {@link PagedList.BoundaryCallback} on each PagedList created.
+ * Sets a {@link PagedList.BoundaryCallback} on each PagedList created, typically used to load
+ * additional data from network when paging from local storage.
* <p>
- * This can be used to
+ * Pass a BoundaryCallback to listen to when the PagedList runs out of data to load. If this
+ * method is not called, or {@code null} is passed, you will not be notified when each
+ * DataSource runs out of data to provide to its PagedList.
+ * <p>
+ * If you are paging from a DataSource.Factory backed by local storage, you can set a
+ * BoundaryCallback to know when there is no more information to page from local storage.
+ * This is useful to page from the network when local storage is a cache of network data.
+ * <p>
+ * Note that when using a BoundaryCallback with a {@code LiveData<PagedList>}, method calls
+ * on the callback may be dispatched multiple times - one for each PagedList/DataSource
+ * pair. If loading network data from a BoundaryCallback, you should prevent multiple
+ * dispatches of the same method from triggering multiple simultaneous network loads.
*
* @param boundaryCallback The boundary callback for listening to PagedList load state.
* @return this
@@ -106,6 +118,8 @@
/**
* Sets executor which will be used for background loading of pages.
* <p>
+ * If not set, defaults to the Arch components I/O thread.
+ * <p>
* Does not affect initial load, which will be always be done on done on the Arch components
* I/O thread.
*
diff --git a/percent/build.gradle b/percent/build.gradle
index ccee3d2..7d5a651 100644
--- a/percent/build.gradle
+++ b/percent/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,10 +7,10 @@
}
dependencies {
- api project(':support-compat')
+ api(project(":support-compat"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
}
android {
diff --git a/percent/lint-baseline.xml b/percent/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/percent/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/persistence/db-framework/api/1.0.0.txt b/persistence/db-framework/api/1.0.0.txt
index f460993..7051765 100644
--- a/persistence/db-framework/api/1.0.0.txt
+++ b/persistence/db-framework/api/1.0.0.txt
@@ -1,6 +1,6 @@
package android.arch.persistence.db.framework {
- public final class FrameworkSQLiteOpenHelperFactory {
+ public final class FrameworkSQLiteOpenHelperFactory implements android.arch.persistence.db.SupportSQLiteOpenHelper.Factory {
ctor public FrameworkSQLiteOpenHelperFactory();
method public android.arch.persistence.db.SupportSQLiteOpenHelper create(android.arch.persistence.db.SupportSQLiteOpenHelper.Configuration);
}
diff --git a/persistence/db-framework/build.gradle b/persistence/db-framework/build.gradle
index 8607bf6..6ce2b94 100644
--- a/persistence/db-framework/build.gradle
+++ b/persistence/db-framework/build.gradle
@@ -30,11 +30,9 @@
dependencies {
api libs.support.annotations
- api project(":persistence:db")
+ api(project(":persistence:db"))
}
-createAndroidCheckstyle(project)
-
supportLibrary {
name = "Android Support SQLite - Framework Implementation"
publish = true
diff --git a/persistence/db-framework/lint-baseline.xml b/persistence/db-framework/lint-baseline.xml
deleted file mode 100644
index 2cadde1..0000000
--- a/persistence/db-framework/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0">
-
-</issues>
diff --git a/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteProgram.java b/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteProgram.java
index 6c2bb72..73c98c6 100644
--- a/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteProgram.java
+++ b/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteProgram.java
@@ -60,7 +60,7 @@
}
@Override
- public void close() throws Exception {
+ public void close() {
mDelegate.close();
}
}
diff --git a/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteStatement.java b/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteStatement.java
index 53a04bd..ccb5614 100644
--- a/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteStatement.java
+++ b/persistence/db-framework/src/main/java/android/arch/persistence/db/framework/FrameworkSQLiteStatement.java
@@ -90,7 +90,7 @@
}
@Override
- public void close() throws Exception {
+ public void close() {
mDelegate.close();
}
}
diff --git a/persistence/db/api/1.0.0.txt b/persistence/db/api/1.0.0.txt
index 0e7aea9..f96f17a 100644
--- a/persistence/db/api/1.0.0.txt
+++ b/persistence/db/api/1.0.0.txt
@@ -8,7 +8,7 @@
method public java.lang.String getSql();
}
- public abstract interface SupportSQLiteDatabase {
+ public abstract interface SupportSQLiteDatabase implements java.io.Closeable {
method public abstract void beginTransaction();
method public abstract void beginTransactionNonExclusive();
method public abstract void beginTransactionWithListener(android.database.sqlite.SQLiteTransactionListener);
@@ -85,7 +85,7 @@
method public abstract android.arch.persistence.db.SupportSQLiteOpenHelper create(android.arch.persistence.db.SupportSQLiteOpenHelper.Configuration);
}
- public abstract interface SupportSQLiteProgram {
+ public abstract interface SupportSQLiteProgram implements java.io.Closeable {
method public abstract void bindBlob(int, byte[]);
method public abstract void bindDouble(int, double);
method public abstract void bindLong(int, long);
diff --git a/persistence/db/build.gradle b/persistence/db/build.gradle
index 085676d..6f5c7f5 100644
--- a/persistence/db/build.gradle
+++ b/persistence/db/build.gradle
@@ -32,8 +32,6 @@
api libs.support.annotations
}
-createAndroidCheckstyle(project)
-
// Used by testCompile in room-compiler
android.libraryVariants.all { variant ->
def name = variant.buildType.name
diff --git a/persistence/db/lint-baseline.xml b/persistence/db/lint-baseline.xml
deleted file mode 100644
index 2cadde1..0000000
--- a/persistence/db/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0">
-
-</issues>
diff --git a/persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteProgram.java b/persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteProgram.java
index c6d43cc..38c1ac1 100644
--- a/persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteProgram.java
+++ b/persistence/db/src/main/java/android/arch/persistence/db/SupportSQLiteProgram.java
@@ -16,16 +16,14 @@
package android.arch.persistence.db;
-import android.annotation.TargetApi;
-import android.os.Build;
+import java.io.Closeable;
/**
* An interface to map the behavior of {@link android.database.sqlite.SQLiteProgram}.
*/
-@TargetApi(Build.VERSION_CODES.KITKAT)
@SuppressWarnings("unused")
-public interface SupportSQLiteProgram extends AutoCloseable {
+public interface SupportSQLiteProgram extends Closeable {
/**
* Bind a NULL value to this statement. The value remains bound until
* {@link #clearBindings} is called.
diff --git a/preference-leanback/api/current.txt b/preference-leanback/api/current.txt
index 7bae10d..4703ae3 100644
--- a/preference-leanback/api/current.txt
+++ b/preference-leanback/api/current.txt
@@ -50,7 +50,7 @@
method public void setTitle(java.lang.CharSequence);
}
- public abstract class LeanbackSettingsFragment extends android.app.Fragment {
+ public abstract class LeanbackSettingsFragment extends android.app.Fragment implements android.support.v14.preference.PreferenceFragment.OnPreferenceDisplayDialogCallback android.support.v14.preference.PreferenceFragment.OnPreferenceStartFragmentCallback android.support.v14.preference.PreferenceFragment.OnPreferenceStartScreenCallback {
ctor public LeanbackSettingsFragment();
method public boolean onPreferenceDisplayDialog(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
method public abstract void onPreferenceStartInitialScreen();
diff --git a/preference-leanback/build.gradle b/preference-leanback/build.gradle
index 85d2577..f4d2fd6 100644
--- a/preference-leanback/build.gradle
+++ b/preference-leanback/build.gradle
@@ -6,12 +6,12 @@
}
dependencies {
- api project(':support-v4')
- api project(':appcompat-v7')
- api project(':recyclerview-v7')
- api project(':preference-v7')
- api project(':preference-v14')
- api project(':leanback-v17')
+ api(project(":support-v4"))
+ api(project(":appcompat-v7"))
+ api(project(":recyclerview-v7"))
+ api(project(":preference-v7"))
+ api(project(":preference-v14"))
+ api(project(":leanback-v17"))
}
android {
diff --git a/recommendation/build.gradle b/recommendation/build.gradle
index f6adcb9..83fa375 100644
--- a/recommendation/build.gradle
+++ b/recommendation/build.gradle
@@ -6,7 +6,7 @@
}
dependencies {
- api project(':support-annotations')
+ api(project(":support-annotations"))
}
android {
diff --git a/recommendation/lint-baseline.xml b/recommendation/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/recommendation/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/recyclerview-selection/build.gradle b/recyclerview-selection/build.gradle
index ab1ab23..06dc730 100644
--- a/recyclerview-selection/build.gradle
+++ b/recyclerview-selection/build.gradle
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
+
plugins {
id("SupportAndroidLibraryPlugin")
}
@@ -23,14 +25,13 @@
api project(':support-annotations')
api project(':support-compat')
- androidTestImplementation libs.junit
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(JUNIT)
}
-
android {
defaultConfig {
minSdkVersion 14
diff --git a/recyclerview-selection/lint-baseline.xml b/recyclerview-selection/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/recyclerview-selection/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/recyclerview-selection/src/main/java/androidx/recyclerview/selection/MouseInputHandler.java b/recyclerview-selection/src/main/java/androidx/recyclerview/selection/MouseInputHandler.java
index 0b4ea2c..b6fe36b 100644
--- a/recyclerview-selection/src/main/java/androidx/recyclerview/selection/MouseInputHandler.java
+++ b/recyclerview-selection/src/main/java/androidx/recyclerview/selection/MouseInputHandler.java
@@ -30,9 +30,9 @@
import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
/**
- * A MotionInputHandler that provides the high-level glue for mouse/stylus driven selection. This
+ * A MotionInputHandler that provides the high-level glue for mouse driven selection. This
* class works with {@link RecyclerView}, {@link GestureRouter}, and {@link GestureSelectionHelper}
- * to provide robust user drive selection support.
+ * to provide robust user driven selection support.
*/
final class MouseInputHandler<K> extends MotionInputHandler<K> {
diff --git a/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionHelperBuilder.java b/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionHelperBuilder.java
index abdefaf..127a511 100644
--- a/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionHelperBuilder.java
+++ b/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionHelperBuilder.java
@@ -88,8 +88,7 @@
};
private int[] mBandToolTypes = new int[] {
- MotionEvent.TOOL_TYPE_MOUSE,
- MotionEvent.TOOL_TYPE_STYLUS
+ MotionEvent.TOOL_TYPE_MOUSE
};
public SelectionHelperBuilder(
@@ -296,7 +295,7 @@
eventRouter.register(toolType, gestureHelper);
}
- // Provides high level glue for binding mouse/stylus events and gestures
+ // Provides high level glue for binding mouse events and gestures
// to selection framework.
MouseInputHandler<K> mouseHandler = new MouseInputHandler<>(
selectionHelper,
diff --git a/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionStorage.java b/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionStorage.java
index 81db30f..454a76b 100644
--- a/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionStorage.java
+++ b/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionStorage.java
@@ -139,7 +139,7 @@
}
}
- private @Nullable Selection<String> readStringSelection(@Nullable Bundle state) {
+ private @Nullable Selection<String> readStringSelection(Bundle state) {
@Nullable ArrayList<String> stored =
state.getStringArrayList(EXTRA_SAVED_SELECTION_ENTRIES);
if (stored == null) {
@@ -151,7 +151,7 @@
return selection;
}
- private @Nullable Selection<Long> readLongSelection(@Nullable Bundle state) {
+ private @Nullable Selection<Long> readLongSelection(Bundle state) {
@Nullable long[] stored = state.getLongArray(EXTRA_SAVED_SELECTION_ENTRIES);
if (stored == null) {
return null;
diff --git a/room/common/build.gradle b/room/common/build.gradle
index 21441a2..05b63c9 100644
--- a/room/common/build.gradle
+++ b/room/common/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
import android.support.SupportLibraryExtension;
@@ -24,12 +25,10 @@
dependencies {
compile libs.support.annotations
- testCompile libs.junit
- testCompile libs.mockito_core
+ testCompile(JUNIT)
+ testCompile(MOCKITO_CORE)
}
-createAndroidCheckstyle(project)
-
supportLibrary {
name = "Android Room-Common"
publish = true
diff --git a/room/common/src/main/java/android/arch/persistence/room/Database.java b/room/common/src/main/java/android/arch/persistence/room/Database.java
index f12d1b9..14e722f 100644
--- a/room/common/src/main/java/android/arch/persistence/room/Database.java
+++ b/room/common/src/main/java/android/arch/persistence/room/Database.java
@@ -34,7 +34,7 @@
* <pre>
* // User and Book are classes annotated with {@literal @}Entity.
* {@literal @}Database(version = 1, entities = {User.class, Book.class})
- * abstract class AppDatabase extends RoomDatabase() {
+ * abstract class AppDatabase extends RoomDatabase {
* // BookDao is a class annotated with {@literal @}Dao.
* abstract public BookDao bookDao();
* // UserDao is a class annotated with {@literal @}Dao.
diff --git a/room/compiler/build.gradle b/room/compiler/build.gradle
index eb9628c..57ff63f 100644
--- a/room/compiler/build.gradle
+++ b/room/compiler/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
import android.support.SupportLibraryExtension
@@ -26,13 +27,11 @@
test.java.srcDirs += 'src/tests/kotlin'
main.java.srcDirs += antlrOut
}
-project.ext.noDocs = true
-version = LibraryVersions.ROOM.toString()
// Temporary hack to stop AS to adding two guavas into test's classpath
configurations.all {
resolutionStrategy {
- force libs.guava
+ force GUAVA
}
}
@@ -40,20 +39,20 @@
// taken from ButterKnife
def logger = new com.android.build.gradle.internal.LoggerWrapper(project.logger)
def sdkHandler = new com.android.build.gradle.internal.SdkHandler(project, logger)
- compile project(":room:common")
- compile project(":room:migration")
- compile libs.kotlin.stdlib
- compile libs.auto_common
- compile libs.javapoet
- compile libs.antlr
- compile libs.xerial
- compile libs.apache.commons.codec
- testCompile libs.google_compile_testing
+ compile(project(":room:common"))
+ compile(project(":room:migration"))
+ compile(KOTLIN_STDLIB)
+ compile(AUTO_COMMON)
+ compile(JAVAPOET)
+ compile(ANTLR)
+ compile(XERIAL)
+ compile(APACHE_COMMONS_CODEC)
+ testCompile(GOOGLE_COMPILE_TESTING)
testCompile project(":paging:common")
- testCompile libs.junit
- testCompile libs.ij_annotations
- testCompile libs.jsr250
- testCompile libs.mockito_core
+ testCompile(JUNIT)
+ testCompile(INTELLIJ_ANNOTATIONS)
+ testCompile(JSR250)
+ testCompile(MOCKITO_CORE)
testCompile fileTree(dir: "${sdkHandler.sdkFolder}/platforms/android-$tools.current_sdk/",
include : "android.jar")
testCompile fileTree(dir: "${new File(project(":room:runtime").buildDir, "libJar")}",
@@ -77,11 +76,10 @@
tasks.findByName("compileKotlin").dependsOn(":room:runtime:jarDebug")
tasks.findByName("compileKotlin").dependsOn(":persistence:db:jarDebug")
-createKotlinCheckstyle(project)
-
supportLibrary {
name = "Android Room Compiler"
publish = true
+ generateDocs = false
mavenVersion = LibraryVersions.ROOM
mavenGroup = LibraryGroups.ROOM
inceptionYear = "2017"
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/RoomProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/RoomProcessor.kt
index 76051c8..57070fd 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/RoomProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/RoomProcessor.kt
@@ -27,7 +27,6 @@
import com.google.auto.common.MoreElements
import com.google.common.collect.SetMultimap
import java.io.File
-import javax.annotation.processing.SupportedSourceVersion
import javax.lang.model.SourceVersion
import javax.lang.model.element.Element
@@ -49,8 +48,9 @@
}
class DatabaseProcessingStep(context: Context) : ContextBoundProcessingStep(context) {
- override fun process(elementsByAnnotation: SetMultimap<Class<out Annotation>, Element>)
- : MutableSet<Element> {
+ override fun process(
+ elementsByAnnotation: SetMultimap<Class<out Annotation>, Element>
+ ): MutableSet<Element> {
// TODO multi step support
val databases = elementsByAnnotation[Database::class.java]
?.map {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/element_ext.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/element_ext.kt
index a74031d..5f61e21 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/element_ext.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/element_ext.kt
@@ -69,15 +69,13 @@
// compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java
private val TO_LIST_OF_TYPES = object
: SimpleAnnotationValueVisitor6<List<TypeMirror>, Void?>() {
- override fun visitArray(values: MutableList<out AnnotationValue>?, p: Void?)
- : List<TypeMirror> {
+ override fun visitArray(values: MutableList<out AnnotationValue>?, p: Void?): List<TypeMirror> {
return values?.map {
val tmp = TO_TYPE.visit(it)
tmp
}?.filterNotNull() ?: emptyList()
}
-
override fun defaultAction(o: Any?, p: Void?): List<TypeMirror>? {
return emptyList()
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt
index 066bd1f..367c926 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt
@@ -33,59 +33,59 @@
object SupportDbTypeNames {
val DB: ClassName = ClassName.get("android.arch.persistence.db", "SupportSQLiteDatabase")
- val SQLITE_STMT : ClassName =
+ val SQLITE_STMT: ClassName =
ClassName.get("android.arch.persistence.db", "SupportSQLiteStatement")
- val SQLITE_OPEN_HELPER : ClassName =
+ val SQLITE_OPEN_HELPER: ClassName =
ClassName.get("android.arch.persistence.db", "SupportSQLiteOpenHelper")
- val SQLITE_OPEN_HELPER_CALLBACK : ClassName =
+ val SQLITE_OPEN_HELPER_CALLBACK: ClassName =
ClassName.get("android.arch.persistence.db", "SupportSQLiteOpenHelper.Callback")
- val SQLITE_OPEN_HELPER_FACTORY : ClassName =
+ val SQLITE_OPEN_HELPER_FACTORY: ClassName =
ClassName.get("android.arch.persistence.db", "SupportSQLiteOpenHelper.Factory")
- val SQLITE_OPEN_HELPER_CONFIG : ClassName =
+ val SQLITE_OPEN_HELPER_CONFIG: ClassName =
ClassName.get("android.arch.persistence.db", "SupportSQLiteOpenHelper.Configuration")
- val SQLITE_OPEN_HELPER_CONFIG_BUILDER : ClassName =
+ val SQLITE_OPEN_HELPER_CONFIG_BUILDER: ClassName =
ClassName.get("android.arch.persistence.db",
"SupportSQLiteOpenHelper.Configuration.Builder")
}
object RoomTypeNames {
val STRING_UTIL: ClassName = ClassName.get("android.arch.persistence.room.util", "StringUtil")
- val CURSOR_CONVERTER : ClassName =
+ val CURSOR_CONVERTER: ClassName =
ClassName.get("android.arch.persistence.room", "CursorConverter")
- val ROOM : ClassName = ClassName.get("android.arch.persistence.room", "Room")
- val ROOM_DB : ClassName = ClassName.get("android.arch.persistence.room", "RoomDatabase")
- val ROOM_DB_CONFIG : ClassName = ClassName.get("android.arch.persistence.room",
+ val ROOM: ClassName = ClassName.get("android.arch.persistence.room", "Room")
+ val ROOM_DB: ClassName = ClassName.get("android.arch.persistence.room", "RoomDatabase")
+ val ROOM_DB_CONFIG: ClassName = ClassName.get("android.arch.persistence.room",
"DatabaseConfiguration")
- val INSERTION_ADAPTER : ClassName =
+ val INSERTION_ADAPTER: ClassName =
ClassName.get("android.arch.persistence.room", "EntityInsertionAdapter")
- val DELETE_OR_UPDATE_ADAPTER : ClassName =
+ val DELETE_OR_UPDATE_ADAPTER: ClassName =
ClassName.get("android.arch.persistence.room", "EntityDeletionOrUpdateAdapter")
- val SHARED_SQLITE_STMT : ClassName =
+ val SHARED_SQLITE_STMT: ClassName =
ClassName.get("android.arch.persistence.room", "SharedSQLiteStatement")
- val INVALIDATION_TRACKER : ClassName =
+ val INVALIDATION_TRACKER: ClassName =
ClassName.get("android.arch.persistence.room", "InvalidationTracker")
- val INVALIDATION_OBSERVER : ClassName =
+ val INVALIDATION_OBSERVER: ClassName =
ClassName.get("android.arch.persistence.room.InvalidationTracker", "Observer")
- val ROOM_SQL_QUERY : ClassName =
+ val ROOM_SQL_QUERY: ClassName =
ClassName.get("android.arch.persistence.room", "RoomSQLiteQuery")
- val OPEN_HELPER : ClassName =
+ val OPEN_HELPER: ClassName =
ClassName.get("android.arch.persistence.room", "RoomOpenHelper")
val OPEN_HELPER_DELEGATE: ClassName =
ClassName.get("android.arch.persistence.room", "RoomOpenHelper.Delegate")
- val TABLE_INFO : ClassName =
+ val TABLE_INFO: ClassName =
ClassName.get("android.arch.persistence.room.util", "TableInfo")
- val TABLE_INFO_COLUMN : ClassName =
+ val TABLE_INFO_COLUMN: ClassName =
ClassName.get("android.arch.persistence.room.util", "TableInfo.Column")
- val TABLE_INFO_FOREIGN_KEY : ClassName =
+ val TABLE_INFO_FOREIGN_KEY: ClassName =
ClassName.get("android.arch.persistence.room.util", "TableInfo.ForeignKey")
- val TABLE_INFO_INDEX : ClassName =
+ val TABLE_INFO_INDEX: ClassName =
ClassName.get("android.arch.persistence.room.util", "TableInfo.Index")
- val LIMIT_OFFSET_DATA_SOURCE : ClassName =
+ val LIMIT_OFFSET_DATA_SOURCE: ClassName =
ClassName.get("android.arch.persistence.room.paging", "LimitOffsetDataSource")
}
object ArchTypeNames {
- val APP_EXECUTOR : ClassName =
+ val APP_EXECUTOR: ClassName =
ClassName.get("android.arch.core.executor", "ArchTaskExecutor")
}
@@ -96,18 +96,17 @@
ClassName.get("android.arch.paging", "TiledDataSource")
val LIVE_PAGED_LIST_PROVIDER: ClassName =
ClassName.get("android.arch.paging", "LivePagedListProvider")
-
}
object LifecyclesTypeNames {
val LIVE_DATA: ClassName = ClassName.get("android.arch.lifecycle", "LiveData")
- val COMPUTABLE_LIVE_DATA : ClassName = ClassName.get("android.arch.lifecycle",
+ val COMPUTABLE_LIVE_DATA: ClassName = ClassName.get("android.arch.lifecycle",
"ComputableLiveData")
}
object AndroidTypeNames {
- val CURSOR : ClassName = ClassName.get("android.database", "Cursor")
- val ARRAY_MAP : ClassName = ClassName.get("android.support.v4.util", "ArrayMap")
+ val CURSOR: ClassName = ClassName.get("android.database", "Cursor")
+ val ARRAY_MAP: ClassName = ClassName.get("android.support.v4.util", "ArrayMap")
}
object CommonTypeNames {
@@ -133,7 +132,7 @@
"EmptyResultSetException")
}
-fun TypeName.defaultValue() : String {
+fun TypeName.defaultValue(): String {
return if (!isPrimitive) {
"null"
} else if (this == TypeName.BOOLEAN) {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/string_ext.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/string_ext.kt
index 9b07e27..52594db 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/string_ext.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/string_ext.kt
@@ -14,27 +14,27 @@
* limitations under the License.
*/
-private fun String.toCamelCase() : String {
+private fun String.toCamelCase(): String {
val split = this.split("_")
if (split.isEmpty()) return ""
if (split.size == 1) return split[0].capitalize()
return split.joinToCamelCase()
}
-private fun String.toCamelCaseAsVar() : String {
+private fun String.toCamelCaseAsVar(): String {
val split = this.split("_")
if (split.isEmpty()) return ""
if (split.size == 1) return split[0]
return split.joinToCamelCaseAsVar()
}
-private fun List<String>.joinToCamelCase(): String = when(size) {
+private fun List<String>.joinToCamelCase(): String = when (size) {
0 -> throw IllegalArgumentException("invalid section size, cannot be zero")
1 -> this[0].toCamelCase()
- else -> this.map {it.toCamelCase()}.joinToString("")
+ else -> this.map { it.toCamelCase() }.joinToString("")
}
-private fun List<String>.joinToCamelCaseAsVar(): String = when(size) {
+private fun List<String>.joinToCamelCaseAsVar(): String = when (size) {
0 -> throw IllegalArgumentException("invalid section size, cannot be zero")
1 -> this[0].toCamelCaseAsVar()
else -> get(0).toCamelCaseAsVar() + drop(1).joinToCamelCase()
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/type_mirror_ext.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/type_mirror_ext.kt
index 97cd051..13779e9 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/type_mirror_ext.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/type_mirror_ext.kt
@@ -23,8 +23,8 @@
import javax.lang.model.type.TypeKind.SHORT
import javax.lang.model.type.TypeMirror
-fun TypeMirror.defaultValue() : String {
- return when(this.kind) {
+fun TypeMirror.defaultValue(): String {
+ return when (this.kind) {
BOOLEAN -> "false"
BYTE, SHORT, INT, LONG, CHAR, FLOAT, DOUBLE -> "0"
else -> "null"
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/log/RLog.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/log/RLog.kt
index 10614ce..9832996 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/log/RLog.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/log/RLog.kt
@@ -27,8 +27,8 @@
import javax.tools.Diagnostic.Kind.NOTE
import javax.tools.Diagnostic.Kind.WARNING
-class RLog(val messager : Messager, val suppressedWarnings : Set<Warning>,
- val defaultElement : Element?) {
+class RLog(val messager: Messager, val suppressedWarnings: Set<Warning>,
+ val defaultElement: Element?) {
private fun String.safeFormat(vararg args: Any): String {
try {
return format(args)
@@ -90,7 +90,7 @@
fun hasErrors() = messages.containsKey(Diagnostic.Kind.ERROR)
- fun writeTo(env : ProcessingEnvironment) {
+ fun writeTo(env: ProcessingEnvironment) {
messages.forEach { pair ->
val kind = pair.key
pair.value.forEach {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt
index d165b55..affa8c9 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt
@@ -99,14 +99,15 @@
if (tableName != null) {
val tableAlias = ctx.table_alias()?.text
if (tableName !in withClauseNames) {
- tableNames.add(Table(unescapeIdentifier(tableName),
- unescapeIdentifier(tableAlias ?: tableName)))
+ tableNames.add(Table(
+ unescapeIdentifier(tableName),
+ unescapeIdentifier(tableAlias ?: tableName)))
}
}
return super.visitTable_or_subquery(ctx)
}
- private fun unescapeIdentifier(text : String) : String {
+ private fun unescapeIdentifier(text: String): String {
val trimmed = text.trim()
if (trimmed.startsWith("`") && trimmed.endsWith('`')) {
return unescapeIdentifier(trimmed.substring(1, trimmed.length - 1))
@@ -155,7 +156,7 @@
}
}
- fun isValidIdentifier(input : String) : Boolean =
+ fun isValidIdentifier(input: String): Boolean =
input.isNotBlank() && INVALID_IDENTIFIER_CHARS.none { input.contains(it) }
}
}
@@ -180,9 +181,9 @@
INTEGER,
REAL,
BLOB;
- fun getTypeMirrors(env : ProcessingEnvironment) : List<TypeMirror>? {
+ fun getTypeMirrors(env: ProcessingEnvironment): List<TypeMirror>? {
val typeUtils = env.typeUtils
- return when(this) {
+ return when (this) {
TEXT -> listOf(env.elementUtils.getTypeElement("java.lang.String").asType())
INTEGER -> withBoxedTypes(env, TypeKind.INT, TypeKind.BYTE, TypeKind.CHAR,
TypeKind.BOOLEAN, TypeKind.LONG, TypeKind.SHORT)
@@ -193,7 +194,7 @@
}
}
- private fun withBoxedTypes(env : ProcessingEnvironment, vararg primitives : TypeKind) :
+ private fun withBoxedTypes(env: ProcessingEnvironment, vararg primitives: TypeKind):
List<TypeMirror> {
return primitives.flatMap {
val primitiveType = env.typeUtils.getPrimitiveType(it)
@@ -203,8 +204,8 @@
companion object {
// converts from ColumnInfo#SQLiteTypeAffinity
- fun fromAnnotationValue(value : Int) : SQLTypeAffinity? {
- return when(value) {
+ fun fromAnnotationValue(value: Int): SQLTypeAffinity? {
+ return when (value) {
ColumnInfo.BLOB -> BLOB
ColumnInfo.INTEGER -> INTEGER
ColumnInfo.REAL -> REAL
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/preconditions/Checks.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/preconditions/Checks.kt
index dad5c1c..588ce94 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/preconditions/Checks.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/preconditions/Checks.kt
@@ -63,7 +63,7 @@
return !failed
}
- fun notBlank(value: String?, element: Element, msg: String, vararg args: Any) : Boolean {
+ fun notBlank(value: String?, element: Element, msg: String, vararg args: Any): Boolean {
return check(value != null && value.isNotBlank(), element, msg, args)
}
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/Context.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/Context.kt
index 4e84be3..def5107 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/Context.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/Context.kt
@@ -27,12 +27,12 @@
import javax.lang.model.element.Element
import javax.lang.model.type.TypeMirror
-class Context private constructor(val processingEnv: ProcessingEnvironment,
- val logger: RLog,
- private val typeConverters
- : CustomConverterProcessor.ProcessResult,
- private val inheritedAdapterStore: TypeAdapterStore?,
- val cache: Cache) {
+class Context private constructor(
+ val processingEnv: ProcessingEnvironment,
+ val logger: RLog,
+ private val typeConverters: CustomConverterProcessor.ProcessResult,
+ private val inheritedAdapterStore: TypeAdapterStore?,
+ val cache: Cache) {
val checker: Checks = Checks(logger)
val COMMON_TYPES: Context.CommonTypes = Context.CommonTypes(processingEnv)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/CustomConverterProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/CustomConverterProcessor.kt
index 1ed245d..622621d 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/CustomConverterProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/CustomConverterProcessor.kt
@@ -58,7 +58,7 @@
?.toListOfClassTypes()
?.filter {
MoreTypes.isType(it)
- }?.mapTo(LinkedHashSet(), {it}) ?: LinkedHashSet<TypeMirror>()
+ }?.mapTo(LinkedHashSet(), { it }) ?: LinkedHashSet<TypeMirror>()
val converters = classes
.flatMap {
CustomConverterProcessor(context, MoreTypes.asTypeElement(it))
@@ -71,7 +71,7 @@
} ?: ProcessResult.EMPTY
}
- fun reportDuplicates(context: Context, converters : List<CustomTypeConverter>) {
+ fun reportDuplicates(context: Context, converters: List<CustomTypeConverter>) {
val groupedByFrom = converters.groupBy { it.from.typeName() }
groupedByFrom.forEach {
it.value.groupBy { it.to.typeName() }.forEach {
@@ -106,8 +106,8 @@
}.filterNotNull()
}
- private fun processMethod(container: DeclaredType, methodElement: ExecutableElement)
- : CustomTypeConverter? {
+ private fun processMethod(
+ container: DeclaredType, methodElement: ExecutableElement): CustomTypeConverter? {
val asMember = context.processingEnv.typeUtils.asMemberOf(container, methodElement)
val executableType = MoreTypes.asExecutable(asMember)
val returnType = executableType.returnType
@@ -136,10 +136,12 @@
/**
* Order of classes is important hence they are a LinkedHashSet not a set.
*/
- open class ProcessResult(val classes: LinkedHashSet<TypeMirror>,
- val converters: List<CustomTypeConverterWrapper>) {
+ open class ProcessResult(
+ val classes: LinkedHashSet<TypeMirror>,
+ val converters: List<CustomTypeConverterWrapper>
+ ) {
object EMPTY : ProcessResult(LinkedHashSet(), emptyList())
- operator fun plus(other : ProcessResult) : ProcessResult {
+ operator fun plus(other: ProcessResult): ProcessResult {
val newClasses = LinkedHashSet<TypeMirror>()
newClasses.addAll(classes)
newClasses.addAll(other.classes)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/DaoProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/DaoProcessor.kt
index c705eef..5e273b6 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/DaoProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/DaoProcessor.kt
@@ -36,8 +36,8 @@
import javax.lang.model.element.TypeElement
import javax.lang.model.type.DeclaredType
-class DaoProcessor(baseContext : Context, val element: TypeElement, val dbType: DeclaredType,
- val dbVerifier : DatabaseVerifier?) {
+class DaoProcessor(baseContext: Context, val element: TypeElement, val dbType: DeclaredType,
+ val dbVerifier: DatabaseVerifier?) {
val context = baseContext.fork(element)
companion object {
@@ -45,7 +45,7 @@
Update::class)
}
- fun process() : Dao {
+ fun process(): Dao {
context.checker.hasAnnotation(element, android.arch.persistence.room.Dao::class,
ProcessorErrors.DAO_MUST_BE_ANNOTATED_WITH_DAO)
context.checker.check(element.hasAnyOf(ABSTRACT) || element.kind == ElementKind.INTERFACE,
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/DatabaseProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/DatabaseProcessor.kt
index 90b24e1..30acbf4 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/DatabaseProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/DatabaseProcessor.kt
@@ -39,7 +39,6 @@
import javax.lang.model.element.TypeElement
import javax.lang.model.type.TypeMirror
-
class DatabaseProcessor(baseContext: Context, val element: TypeElement) {
val context = baseContext.fork(element)
@@ -175,7 +174,7 @@
}
private fun validateUniqueDaoClasses(dbElement: TypeElement, daoMethods: List<DaoMethod>,
- entities : List<Entity>) {
+ entities: List<Entity>) {
val entityTypeNames = entities.map { it.typeName }.toSet()
daoMethods.groupBy { it.dao.typeName }
.forEach {
@@ -189,8 +188,8 @@
context.logger.e(dbElement, error)
}
}
- val check = fun(element : Element, dao : Dao,
- typeName : TypeName?) {
+ val check = fun(element: Element, dao: Dao,
+ typeName: TypeName?) {
typeName?.let {
if (!entityTypeNames.contains(typeName)) {
context.logger.e(element,
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt
index 405c6b1..fc0df44 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt
@@ -57,7 +57,7 @@
doProcess()
})
}
- private fun doProcess() : Entity {
+ private fun doProcess(): Entity {
context.checker.hasAnnotation(element, android.arch.persistence.room.Entity::class,
ProcessorErrors.ENTITY_MUST_BE_ANNOTATED_WITH_ENTITY)
val pojo = PojoProcessor(
@@ -151,7 +151,7 @@
private fun checkIndicesForForeignKeys(entityForeignKeys: List<ForeignKey>,
primaryKey: PrimaryKey,
indices: List<Index>) {
- fun covers(columnNames: List<String>, fields : List<Field>) : Boolean =
+ fun covers(columnNames: List<String>, fields: List<Field>): Boolean =
fields.size >= columnNames.size && columnNames.withIndex().all {
fields[it.index].columnName == it.value
}
@@ -238,8 +238,8 @@
}.filterNotNull()
}
- private fun findAndValidatePrimaryKey(fields: List<Field>, embeddedFields: List<EmbeddedField>)
- : PrimaryKey {
+ private fun findAndValidatePrimaryKey(
+ fields: List<Field>, embeddedFields: List<EmbeddedField>): PrimaryKey {
val candidates = collectPrimaryKeysFromEntityAnnotations(element, fields) +
collectPrimaryKeysFromPrimaryKeyAnnotations(fields) +
collectPrimaryKeysFromEmbeddedFields(embeddedFields)
@@ -311,9 +311,8 @@
/**
* Check classes for @Entity(primaryKeys = ?).
*/
- private fun collectPrimaryKeysFromEntityAnnotations(typeElement: TypeElement,
- availableFields: List<Field>)
- : List<PrimaryKey> {
+ private fun collectPrimaryKeysFromEntityAnnotations(
+ typeElement: TypeElement, availableFields: List<Field>): List<PrimaryKey> {
val myPkeys = MoreElements.getAnnotationMirror(typeElement,
android.arch.persistence.room.Entity::class.java).orNull()?.let {
val primaryKeyColumns = AnnotationMirrors.getAnnotationValue(it, "primaryKeys")
@@ -348,8 +347,8 @@
return superPKeys + myPkeys
}
- private fun collectPrimaryKeysFromEmbeddedFields(embeddedFields: List<EmbeddedField>)
- : List<PrimaryKey> {
+ private fun collectPrimaryKeysFromEmbeddedFields(
+ embeddedFields: List<EmbeddedField>): List<PrimaryKey> {
return embeddedFields.map { embeddedField ->
MoreElements.getAnnotationMirror(embeddedField.field.element,
android.arch.persistence.room.PrimaryKey::class.java).orNull()?.let {
@@ -367,8 +366,8 @@
// start from my element and check if anywhere in the list we can find the only well defined
// pkey, if so, use it.
- private fun choosePrimaryKey(candidates: List<PrimaryKey>, typeElement: TypeElement)
- : PrimaryKey {
+ private fun choosePrimaryKey(
+ candidates: List<PrimaryKey>, typeElement: TypeElement): PrimaryKey {
// If 1 of these primary keys is declared in this class, then it is the winner. Just print
// a note for the others.
// If 0 is declared, check the parent.
@@ -398,7 +397,8 @@
}
}
- private fun validateAndCreateIndices(inputs: List<IndexInput>, pojo: Pojo): List<Index> {
+ private fun validateAndCreateIndices(
+ inputs: List<IndexInput>, pojo: Pojo): List<Index> {
// check for columns
val indices = inputs.map { input ->
context.checker.check(input.columnNames.isNotEmpty(), element,
@@ -448,8 +448,8 @@
}
// check if parent is an Entity, if so, report its annotation indices
- private fun loadSuperIndices(typeMirror: TypeMirror?, tableName: String, inherit: Boolean)
- : List<IndexInput> {
+ private fun loadSuperIndices(
+ typeMirror: TypeMirror?, tableName: String, inherit: Boolean): List<IndexInput> {
if (typeMirror == null || typeMirror.kind == TypeKind.NONE) {
return emptyList()
}
@@ -480,8 +480,7 @@
}
companion object {
- private fun extractTableName(element: TypeElement, annotation: AnnotationMirror)
- : String {
+ private fun extractTableName(element: TypeElement, annotation: AnnotationMirror): String {
val annotationValue = AnnotationMirrors
.getAnnotationValue(annotation, "tableName").value.toString()
return if (annotationValue == "") {
@@ -491,8 +490,8 @@
}
}
- private fun extractIndices(annotation: AnnotationMirror, tableName: String)
- : List<IndexInput> {
+ private fun extractIndices(
+ annotation: AnnotationMirror, tableName: String): List<IndexInput> {
val arrayOfIndexAnnotations = AnnotationMirrors.getAnnotationValue(annotation,
"indices")
return INDEX_LIST_VISITOR.visit(arrayOfIndexAnnotations, tableName)
@@ -500,8 +499,10 @@
private val INDEX_LIST_VISITOR = object
: SimpleAnnotationValueVisitor6<List<IndexInput>, String>() {
- override fun visitArray(values: MutableList<out AnnotationValue>?, tableName: String)
- : List<IndexInput> {
+ override fun visitArray(
+ values: MutableList<out AnnotationValue>?,
+ tableName: String
+ ): List<IndexInput> {
return values?.map {
INDEX_VISITOR.visit(it, tableName)
}?.filterNotNull() ?: emptyList<IndexInput>()
@@ -534,8 +535,10 @@
private val FOREIGN_KEY_LIST_VISITOR = object
: SimpleAnnotationValueVisitor6<List<ForeignKeyInput>, Void?>() {
- override fun visitArray(values: MutableList<out AnnotationValue>?, void: Void?)
- : List<ForeignKeyInput> {
+ override fun visitArray(
+ values: MutableList<out AnnotationValue>?,
+ void: Void?
+ ): List<ForeignKeyInput> {
return values?.map {
FOREIGN_KEY_VISITOR.visit(it)
}?.filterNotNull() ?: emptyList<ForeignKeyInput>()
@@ -576,7 +579,11 @@
/**
* ForeignKey, before it is processed in the context of a database.
*/
- data class ForeignKeyInput(val parent : TypeMirror, val parentColumns : List<String>,
- val childColumns : List<String>, val onDelete : ForeignKeyAction?,
- val onUpdate : ForeignKeyAction?, val deferred : Boolean)
+ data class ForeignKeyInput(
+ val parent: TypeMirror,
+ val parentColumns: List<String>,
+ val childColumns: List<String>,
+ val onDelete: ForeignKeyAction?,
+ val onUpdate: ForeignKeyAction?,
+ val deferred: Boolean)
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/FieldProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/FieldProcessor.kt
index 8677bf6..f03d7da 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/FieldProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/FieldProcessor.kt
@@ -42,10 +42,10 @@
ColumnInfo::class.java)
val name = element.simpleName.toString()
val columnName: String
- val affinity : SQLTypeAffinity?
+ val affinity: SQLTypeAffinity?
val collate: Collate?
val fieldPrefix = fieldParent?.prefix ?: ""
- val indexed : Boolean
+ val indexed: Boolean
if (columnInfoAnnotation.isPresent) {
val nameInAnnotation = AnnotationMirrors
.getAnnotationValue(columnInfoAnnotation.get(), "name")
@@ -61,7 +61,7 @@
.getAnnotationValue(columnInfoAnnotation.get(), "typeAffinity")
.getAsInt(ColumnInfo.UNDEFINED)!!
SQLTypeAffinity.fromAnnotationValue(userDefinedAffinity)
- } catch (ex : NumberFormatException) {
+ } catch (ex: NumberFormatException) {
null
}
@@ -71,7 +71,6 @@
indexed = AnnotationMirrors
.getAnnotationValue(columnInfoAnnotation.get(), "index")
.getAsBoolean(false)
-
} else {
columnName = fieldPrefix + name
affinity = null
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/InsertionMethodProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/InsertionMethodProcessor.kt
index dba4a87..02b191c 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/InsertionMethodProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/InsertionMethodProcessor.kt
@@ -134,7 +134,7 @@
setOf(Type.INSERT_VOID, Type.INSERT_ID_ARRAY, Type.INSERT_ID_ARRAY_BOX,
Type.INSERT_ID_LIST)
}
- fun acceptableTypes(params : List<ShortcutQueryParameter>) : Set<InsertionMethod.Type> {
+ fun acceptableTypes(params: List<ShortcutQueryParameter>): Set<InsertionMethod.Type> {
if (params.isEmpty()) {
return VOID_SET
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt
index f4cd5f3..cb63b6d 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt
@@ -73,13 +73,12 @@
val PROCESSED_ANNOTATIONS = listOf(ColumnInfo::class, Embedded::class,
Relation::class)
}
- fun process() : Pojo {
+ fun process(): Pojo {
return context.cache.pojos.get(Cache.PojoKey(element, bindingScope, parent), {
referenceStack.add(element.qualifiedName)
try {
doProcess()
- }
- finally {
+ } finally {
referenceStack.remove(element.qualifiedName)
}
})
@@ -198,8 +197,8 @@
constructor = constructor)
}
- private fun chooseConstructor(myFields: List<Field>, embedded: List<EmbeddedField>)
- : Constructor? {
+ private fun chooseConstructor(
+ myFields: List<Field>, embedded: List<EmbeddedField>): Constructor? {
val constructors = ElementFilter.constructorsIn(element.enclosedElements)
.filterNot { it.hasAnnotation(Ignore::class) || it.hasAnyOf(PRIVATE) }
val fieldMap = myFields.associateBy { it.name }
@@ -294,8 +293,8 @@
}
}
- private fun processEmbeddedField(declaredType: DeclaredType?, variableElement: VariableElement)
- : EmbeddedField? {
+ private fun processEmbeddedField(
+ declaredType: DeclaredType?, variableElement: VariableElement): EmbeddedField? {
val asTypeElement = MoreTypes.asTypeElement(variableElement.asType())
@@ -308,14 +307,15 @@
?.toString()
?: ""
val inheritedPrefix = parent?.prefix ?: ""
- val embeddedField = Field(variableElement,
- variableElement.simpleName.toString(),
- type = context
- .processingEnv
- .typeUtils
- .asMemberOf(declaredType, variableElement),
- affinity = null,
- parent = parent)
+ val embeddedField = Field(
+ variableElement,
+ variableElement.simpleName.toString(),
+ type = context
+ .processingEnv
+ .typeUtils
+ .asMemberOf(declaredType, variableElement),
+ affinity = null,
+ parent = parent)
val subParent = EmbeddedField(
field = embeddedField,
prefix = inheritedPrefix + fieldPrefix,
@@ -329,10 +329,10 @@
return subParent
}
- private fun processRelationField(myFields : List<Field>, container: DeclaredType?,
- relationElement: VariableElement)
- : android.arch.persistence.room.vo.Relation? {
-
+ private fun processRelationField(
+ myFields: List<Field>, container: DeclaredType?,
+ relationElement: VariableElement
+ ): android.arch.persistence.room.vo.Relation? {
val asTypeElement = MoreTypes.asTypeElement(
MoreElements.asVariable(relationElement).asType())
@@ -376,15 +376,15 @@
val typeArgElement = MoreTypes.asTypeElement(typeArg)
val entityClassInput = AnnotationMirrors
.getAnnotationValue(annotation, "entity").toClassType()
- val pojo : Pojo
- val entity : Entity
+ val pojo: Pojo
+ val entity: Entity
if (entityClassInput == null
|| MoreTypes.isTypeOf(Any::class.java, entityClassInput)) {
entity = EntityProcessor(context, typeArgElement, referenceStack).process()
pojo = entity
} else {
entity = EntityProcessor(context, MoreTypes.asTypeElement(entityClassInput),
- referenceStack).process()
+ referenceStack).process()
pojo = PojoProcessor(
baseContext = context,
element = typeArgElement,
@@ -417,7 +417,7 @@
val projection = AnnotationMirrors.getAnnotationValue(annotation, "projection")
.getAsStringList()
- if(projection.isNotEmpty()) {
+ if (projection.isNotEmpty()) {
val missingColumns = projection.filterNot { columnName ->
entity.fields.any { columnName == it.columnName }
}
@@ -497,7 +497,7 @@
}
private fun assignSetters(fields: List<Field>, setterCandidates: List<ExecutableElement>,
- constructor : Constructor?) {
+ constructor: Constructor?) {
fields.forEach { field ->
assignSetter(field, setterCandidates, constructor)
}
@@ -580,9 +580,10 @@
}
}
- private fun verifyAndChooseOneFrom(candidates: List<ExecutableElement>?,
- reportAmbiguity: (List<String>) -> Unit)
- : ExecutableElement? {
+ private fun verifyAndChooseOneFrom(
+ candidates: List<ExecutableElement>?,
+ reportAmbiguity: (List<String>) -> Unit
+ ): ExecutableElement? {
if (candidates == null) {
return null
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt
index 4752478..f00cfa3 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt
@@ -40,8 +40,8 @@
val TRANSACTION_REFERENCE_DOCS = "https://developer.android.com/reference/android/arch/" +
"persistence/room/Transaction.html"
- fun insertionMethodReturnTypeMismatch(definedReturn : TypeName,
- expectedReturnTypes : List<TypeName>) : String {
+ fun insertionMethodReturnTypeMismatch(definedReturn: TypeName,
+ expectedReturnTypes: List<TypeName>): String {
return "Method returns $definedReturn but it should return one of the following: `" +
expectedReturnTypes.joinToString(", ") + "`. If you want to return the list of" +
" row ids from the query, your insertion method can receive only 1 parameter."
@@ -208,7 +208,7 @@
}
fun pojoMissingNonNull(pojoTypeName: TypeName, missingPojoFields: List<String>,
- allQueryColumns: List<String>) : String {
+ allQueryColumns: List<String>): String {
return """
The columns returned by the query does not have the fields
[${missingPojoFields.joinToString(",")}] in $pojoTypeName even though they are
@@ -301,8 +301,7 @@
" field in $grandParent."
}
- fun droppedEmbeddedIndex(entityName: String, fieldPath: String, grandParent: String)
- : String {
+ fun droppedEmbeddedIndex(entityName: String, fieldPath: String, grandParent: String): String {
return "Indices defined in $entityName will be dropped when it is merged into" +
" $grandParent ($fieldPath). You can re-declare them in $grandParent."
}
@@ -323,14 +322,14 @@
val RELATION_NOT_COLLECTION = "Fields annotated with @Relation must be a List or Set."
- fun relationCannotFindEntityField(entityName : String, columnName: String,
- availableColumns: List<String>) : String {
+ fun relationCannotFindEntityField(entityName: String, columnName: String,
+ availableColumns: List<String>): String {
return "Cannot find the child entity column `$columnName` in $entityName." +
" Options: ${availableColumns.joinToString(", ")}"
}
- fun relationCannotFindParentEntityField(entityName : String, columnName: String,
- availableColumns: List<String>) : String {
+ fun relationCannotFindParentEntityField(entityName: String, columnName: String,
+ availableColumns: List<String>): String {
return "Cannot find the parent entity column `$columnName` in $entityName." +
" Options: ${availableColumns.joinToString(", ")}"
}
@@ -340,8 +339,8 @@
val CANNOT_FIND_TYPE = "Cannot find type."
fun relationAffinityMismatch(parentColumn: String, childColumn: String,
- parentAffinity : SQLTypeAffinity?,
- childAffinity : SQLTypeAffinity?) : String {
+ parentAffinity: SQLTypeAffinity?,
+ childAffinity: SQLTypeAffinity?): String {
return """
The affinity of parent column ($parentColumn : $parentAffinity) does not match the type
affinity of the child column ($childColumn : $childAffinity).
@@ -353,8 +352,8 @@
it.java.simpleName
}
- fun relationBadProject(entityQName : String, missingColumnNames : List<String>,
- availableColumnNames : List<String>) : String {
+ fun relationBadProject(entityQName: String, missingColumnNames: List<String>,
+ availableColumnNames: List<String>): String {
return """
$entityQName does not have the following columns: ${missingColumnNames.joinToString(",")}.
Available columns are: ${availableColumnNames.joinToString(",")}
@@ -368,7 +367,7 @@
val INVALID_FOREIGN_KEY_ACTION = "Invalid foreign key action. It must be one of the constants" +
" defined in ForeignKey.Action"
- fun foreignKeyNotAnEntity(className : String) : String {
+ fun foreignKeyNotAnEntity(className: String): String {
return """
Classes referenced in Foreign Key annotations must be @Entity classes. $className is not
an entity
@@ -382,9 +381,9 @@
" Available column names:${allColumns.joinToString(", ")}"
}
- fun foreignKeyParentColumnDoesNotExist(parentEntity : String,
+ fun foreignKeyParentColumnDoesNotExist(parentEntity: String,
missingColumn: String,
- allColumns : List<String>): String {
+ allColumns: List<String>): String {
return "($missingColumn) does not exist in $parentEntity. Available columns are" +
" ${allColumns.joinToString(",")}"
}
@@ -393,8 +392,8 @@
val FOREIGN_KEY_EMPTY_PARENT_COLUMN_LIST = "Must specify at least 1 column name for the parent"
- fun foreignKeyColumnNumberMismatch(childColumns : List<String>, parentColumns : List<String>)
- : String {
+ fun foreignKeyColumnNumberMismatch(
+ childColumns: List<String>, parentColumns: List<String>): String {
return """
Number of child columns in foreign key must match number of parent columns.
Child reference has ${childColumns.joinToString(",")} and parent reference has
@@ -402,16 +401,15 @@
""".trim()
}
- fun foreignKeyMissingParentEntityInDatabase(parentTable : String, childEntity : String)
- : String {
+ fun foreignKeyMissingParentEntityInDatabase(parentTable: String, childEntity: String): String {
return """
$parentTable table referenced in the foreign keys of $childEntity does not exist in
the database. Maybe you forgot to add the referenced entity in the entities list of
the @Database annotation?""".trim()
}
- fun foreignKeyMissingIndexInParent(parentEntity : String, parentColumns: List<String>,
- childEntity : String, childColumns: List<String>): String {
+ fun foreignKeyMissingIndexInParent(parentEntity: String, parentColumns: List<String>,
+ childEntity: String, childColumns: List<String>): String {
return """
$childEntity has a foreign key (${childColumns.joinToString(",")}) that references
$parentEntity (${parentColumns.joinToString(",")}) but $parentEntity does not have
@@ -422,7 +420,7 @@
""".trim()
}
- fun foreignKeyMissingIndexInChildColumns(childColumns: List<String>) : String {
+ fun foreignKeyMissingIndexInChildColumns(childColumns: List<String>): String {
return """
(${childColumns.joinToString(",")}) column(s) reference a foreign key but
they are not part of an index. This may trigger full table scans whenever parent
@@ -431,7 +429,7 @@
""".trim()
}
- fun foreignKeyMissingIndexInChildColumn(childColumn: String) : String {
+ fun foreignKeyMissingIndexInChildColumn(childColumn: String): String {
return """
$childColumn column references a foreign key but it is not part of an index. This
may trigger full table scans whenever parent table is modified so you are highly
@@ -439,7 +437,7 @@
""".trim()
}
- fun shortcutEntityIsNotInDatabase(database : String, dao : String, entity : String) : String {
+ fun shortcutEntityIsNotInDatabase(database: String, dao: String, entity: String): String {
return """
$dao is part of $database but this entity is not in the database. Maybe you forgot
to add $entity to the entities section of the @Database?
@@ -448,8 +446,8 @@
val MISSING_ROOM_RXJAVA2_ARTIFACT = "To use RxJava2 features, you must add `rxjava2`" +
" artifact from Room as a dependency. android.arch.persistence.room:rxjava2:<version>"
- fun ambigiousConstructor(pojo : String, paramName:String, matchingFields : List<String>)
- : String {
+ fun ambigiousConstructor(
+ pojo: String, paramName: String, matchingFields: List<String>): String {
return """
Ambiguous constructor. The parameter ($paramName) in $pojo matches multiple fields:
[${matchingFields.joinToString(",")}]. If you don't want to use this constructor,
@@ -475,7 +473,7 @@
val PAGING_SPECIFY_DATA_SOURCE_TYPE = "For now, Room only supports TiledDataSource class."
- fun primaryKeyNull(field: String): String{
+ fun primaryKeyNull(field: String): String {
return "You must annotate primary keys with @NonNull. \"$field\" is nullable. SQLite " +
"considers this a " +
"bug and Room does not allow it. See SQLite docs for details: " +
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ShortcutMethodProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ShortcutMethodProcessor.kt
index 95d16f5..c13b818 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ShortcutMethodProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ShortcutMethodProcessor.kt
@@ -28,27 +28,28 @@
/**
* Common functionality for shortcut method processors
*/
-class ShortcutMethodProcessor(baseContext : Context,
+class ShortcutMethodProcessor(baseContext: Context,
val containing: DeclaredType,
val executableElement: ExecutableElement) {
val context = baseContext.fork(executableElement)
private val asMember = context.processingEnv.typeUtils.asMemberOf(containing, executableElement)
private val executableType = MoreTypes.asExecutable(asMember)
- fun extractAnnotation(klass : KClass<out Annotation>,
- errorMsg : String) : AnnotationMirror? {
+ fun extractAnnotation(klass: KClass<out Annotation>,
+ errorMsg: String): AnnotationMirror? {
val annotation = MoreElements.getAnnotationMirror(executableElement,
klass.java).orNull()
context.checker.check(annotation != null, executableElement, errorMsg)
return annotation
}
- fun extractReturnType() : TypeMirror {
+ fun extractReturnType(): TypeMirror {
return executableType.returnType
}
- fun extractParams(missingParamError: String)
- : Pair<Map<String, Entity>, List<ShortcutQueryParameter>> {
+ fun extractParams(
+ missingParamError: String
+ ): Pair<Map<String, Entity>, List<ShortcutQueryParameter>> {
val params = executableElement.parameters
.map { ShortcutParameterProcessor(
baseContext = context,
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ShortcutParameterProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ShortcutParameterProcessor.kt
index 4f66920..6ccd12a 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ShortcutParameterProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ShortcutParameterProcessor.kt
@@ -30,7 +30,7 @@
/**
* Processes parameters of methods that are annotated with Insert, Delete.
*/
-class ShortcutParameterProcessor(baseContext : Context,
+class ShortcutParameterProcessor(baseContext: Context,
val containing: DeclaredType,
val element: VariableElement) {
val context = baseContext.fork(element)
@@ -53,13 +53,12 @@
}
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
- fun extractEntityType(typeMirror: TypeMirror) : Pair<TypeMirror?, Boolean> {
+ fun extractEntityType(typeMirror: TypeMirror): Pair<TypeMirror?, Boolean> {
val elementUtils = context.processingEnv.elementUtils
val typeUtils = context.processingEnv.typeUtils
- fun verifyAndPair(entityType: TypeMirror, isMultiple : Boolean)
- : Pair<TypeMirror?, Boolean> {
+ fun verifyAndPair(entityType: TypeMirror, isMultiple: Boolean): Pair<TypeMirror?, Boolean> {
if (!MoreTypes.isType(entityType)) {
return Pair(null, isMultiple)
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/SuppressWarningProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/SuppressWarningProcessor.kt
index e2215d9..9edf2f9 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/SuppressWarningProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/SuppressWarningProcessor.kt
@@ -44,8 +44,8 @@
}
private object VISITOR : SimpleAnnotationValueVisitor6<Set<Warning>, String>() {
- override fun visitArray(values: List<AnnotationValue>?, elementName: String?)
- : Set<Warning> {
+ override fun visitArray(values: List<AnnotationValue>?, elementName: String?
+ ): Set<Warning> {
return values?.map {
Warning.fromPublicKey(it.value.toString())
}?.filterNotNull()?.toSet() ?: emptySet()
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/UpdateMethodProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/UpdateMethodProcessor.kt
index 452ea4a..27211ce 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/UpdateMethodProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/UpdateMethodProcessor.kt
@@ -25,9 +25,10 @@
import javax.lang.model.element.ExecutableElement
import javax.lang.model.type.DeclaredType
-class UpdateMethodProcessor(baseContext: Context,
- val containing: DeclaredType,
- val executableElement: ExecutableElement) {
+class UpdateMethodProcessor(
+ baseContext: Context,
+ val containing: DeclaredType,
+ val executableElement: ExecutableElement) {
val context = baseContext.fork(executableElement)
fun process(): UpdateMethod {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/cache/Cache.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/cache/Cache.kt
index 37f6c6d..0ef5dde 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/cache/Cache.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/cache/Cache.kt
@@ -40,7 +40,7 @@
inner class Bucket<K, T>(source: Bucket<K, T>?) {
private val entries: MutableMap<FullKey<K>, T> = source?.entries ?: mutableMapOf()
- fun get(key : K, calculate: () -> T): T {
+ fun get(key: K, calculate: () -> T): T {
val fullKey = FullKey(converters, suppressedWarnings, key)
return entries.getOrPut(fullKey, {
calculate()
@@ -56,15 +56,18 @@
/**
* Key for Pojo cache
*/
- data class PojoKey(val element: Element, val scope : FieldProcessor.BindingScope,
- val parent : EmbeddedField?)
+ data class PojoKey(
+ val element: Element,
+ val scope: FieldProcessor.BindingScope,
+ val parent: EmbeddedField?)
/**
* Internal key representation with adapters & warnings included.
* <p>
* Converters are kept in a linked set since the order is important for the TypeAdapterStore.
*/
- private data class FullKey<T>(val converters: LinkedHashSet<TypeMirror>,
- val suppressedWarnings: Set<Warning>,
- val key: T)
+ private data class FullKey<T>(
+ val converters: LinkedHashSet<TypeMirror>,
+ val suppressedWarnings: Set<Warning>,
+ val key: T)
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/CodeGenScope.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/CodeGenScope.kt
index 64e4f48..59c2283 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/CodeGenScope.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/CodeGenScope.kt
@@ -22,29 +22,29 @@
/**
* Defines a code generation scope where we can provide temporary variables, global variables etc
*/
-class CodeGenScope(val writer : ClassWriter) {
+class CodeGenScope(val writer: ClassWriter) {
private var tmpVarIndices = mutableMapOf<String, Int>()
- private var builder : CodeBlock.Builder? = null
+ private var builder: CodeBlock.Builder? = null
companion object {
const val TMP_VAR_DEFAULT_PREFIX = "_tmp"
const val CLASS_PROPERTY_PREFIX = "__"
@VisibleForTesting
- fun _tmpVar(index:Int) = _tmpVar(TMP_VAR_DEFAULT_PREFIX, index)
- fun _tmpVar(prefix : String, index:Int) = "$prefix${if(index == 0) "" else "_$index"}"
+ fun _tmpVar(index: Int) = _tmpVar(TMP_VAR_DEFAULT_PREFIX, index)
+ fun _tmpVar(prefix: String, index: Int) = "$prefix${if (index == 0) "" else "_$index"}"
}
- fun builder() : CodeBlock.Builder {
+ fun builder(): CodeBlock.Builder {
if (builder == null) {
builder = CodeBlock.builder()
}
return builder!!
}
- fun getTmpVar() : String {
+ fun getTmpVar(): String {
return getTmpVar(TMP_VAR_DEFAULT_PREFIX)
}
- fun getTmpVar(prefix : String) : String {
+ fun getTmpVar(prefix: String): String {
if (!prefix.startsWith("_")) {
throw IllegalArgumentException("tmp variable prefixes should start with _")
}
@@ -62,7 +62,7 @@
/**
* copies all variable indices but excludes generated code.
*/
- fun fork() : CodeGenScope {
+ fun fork(): CodeGenScope {
val forked = CodeGenScope(writer)
forked.tmpVarIndices.putAll(tmpVarIndices)
return forked
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/ObservableQueryResultBinderProvider.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/ObservableQueryResultBinderProvider.kt
index 89b0072..d64ef4b 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/ObservableQueryResultBinderProvider.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/ObservableQueryResultBinderProvider.kt
@@ -29,12 +29,12 @@
*/
abstract class ObservableQueryResultBinderProvider(val context: Context)
: QueryResultBinderProvider {
- protected abstract fun extractTypeArg(declared: DeclaredType) : TypeMirror
+ protected abstract fun extractTypeArg(declared: DeclaredType): TypeMirror
protected abstract fun create(typeArg: TypeMirror,
resultAdapter: QueryResultAdapter?,
- tableNames : Set<String>) : QueryResultBinder
+ tableNames: Set<String>): QueryResultBinder
- override final fun provide(declared: DeclaredType, query: ParsedQuery): QueryResultBinder {
+ final override fun provide(declared: DeclaredType, query: ParsedQuery): QueryResultBinder {
val typeArg = extractTypeArg(declared)
val adapter = context.typeAdapterStore.findQueryResultAdapter(typeArg, query)
val tableNames = ((adapter?.accessedTableNames() ?: emptyList()) +
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/QueryResultBinderProvider.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/QueryResultBinderProvider.kt
index b76be3e..ccc3597 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/QueryResultBinderProvider.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/QueryResultBinderProvider.kt
@@ -21,6 +21,6 @@
import javax.lang.model.type.DeclaredType
interface QueryResultBinderProvider {
- fun provide(declared : DeclaredType, query: ParsedQuery) : QueryResultBinder
- fun matches(declared: DeclaredType) : Boolean
+ fun provide(declared: DeclaredType, query: ParsedQuery): QueryResultBinder
+ fun matches(declared: DeclaredType): Boolean
}
\ No newline at end of file
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt
index 5b94111..dcd5ee6 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt
@@ -62,7 +62,7 @@
import com.google.auto.common.MoreElements
import com.google.auto.common.MoreTypes
import com.google.common.annotations.VisibleForTesting
-import java.util.LinkedList;
+import java.util.LinkedList
import javax.lang.model.type.ArrayType
import javax.lang.model.type.TypeKind
import javax.lang.model.type.TypeMirror
@@ -72,16 +72,16 @@
* Holds all type adapters and can create on demand composite type adapters to convert a type into a
* database column.
*/
-class TypeAdapterStore private constructor(val context: Context,
- /**
- * first type adapter has the highest priority
- */
- private val columnTypeAdapters: List<ColumnTypeAdapter>,
- /**
- * first converter has the highest priority
- */
- private val typeConverters: List<TypeConverter>) {
-
+class TypeAdapterStore private constructor(
+ val context: Context,
+ /**
+ * first type adapter has the highest priority
+ */
+ private val columnTypeAdapters: List<ColumnTypeAdapter>,
+ /**
+ * first converter has the highest priority
+ */
+ private val typeConverters: List<TypeConverter>) {
companion object {
fun copy(context: Context, store: TypeAdapterStore): TypeAdapterStore {
@@ -147,8 +147,10 @@
/**
* Searches 1 way to bind a value into a statement.
*/
- fun findStatementValueBinder(input: TypeMirror, affinity: SQLTypeAffinity?)
- : StatementValueBinder? {
+ fun findStatementValueBinder(
+ input: TypeMirror,
+ affinity: SQLTypeAffinity?
+ ): StatementValueBinder? {
if (input.kind == TypeKind.ERROR) {
return null
}
@@ -218,8 +220,7 @@
* Finds a two way converter, if you need 1 way, use findStatementValueBinder or
* findCursorValueReader.
*/
- fun findColumnTypeAdapter(out: TypeMirror, affinity: SQLTypeAffinity?)
- : ColumnTypeAdapter? {
+ fun findColumnTypeAdapter(out: TypeMirror, affinity: SQLTypeAffinity?): ColumnTypeAdapter? {
if (out.kind == TypeKind.ERROR) {
return null
}
@@ -236,8 +237,8 @@
fromCursor)
}
- private fun findDirectAdapterFor(out: TypeMirror, affinity: SQLTypeAffinity?)
- : ColumnTypeAdapter? {
+ private fun findDirectAdapterFor(
+ out: TypeMirror, affinity: SQLTypeAffinity?): ColumnTypeAdapter? {
val adapter = getAllColumnAdapters(out).firstOrNull {
affinity == null || it.typeAffinity == affinity
}
@@ -259,8 +260,7 @@
}
}
- fun findQueryResultAdapter(typeMirror: TypeMirror, query: ParsedQuery)
- : QueryResultAdapter? {
+ fun findQueryResultAdapter(typeMirror: TypeMirror, query: ParsedQuery): QueryResultAdapter? {
if (typeMirror.kind == TypeKind.ERROR) {
return null
}
@@ -382,8 +382,8 @@
return findTypeConverter(input, listOf(output))
}
- private fun findTypeConverter(inputs: List<TypeMirror>, outputs: List<TypeMirror>)
- : TypeConverter? {
+ private fun findTypeConverter(
+ inputs: List<TypeMirror>, outputs: List<TypeMirror>): TypeConverter? {
if (inputs.isEmpty()) {
return null
}
@@ -397,8 +397,7 @@
val excludes = arrayListOf<TypeMirror>()
val queue = LinkedList<TypeConverter>()
- fun exactMatch(candidates: List<TypeConverter>)
- : TypeConverter? {
+ fun exactMatch(candidates: List<TypeConverter>): TypeConverter? {
return candidates.firstOrNull {
outputs.any { output -> types.isSameType(output, it.to) }
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/InstantQueryResultBinderProvider.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/InstantQueryResultBinderProvider.kt
index af03a88..c7d1e2d 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/InstantQueryResultBinderProvider.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/InstantQueryResultBinderProvider.kt
@@ -23,7 +23,7 @@
import android.arch.persistence.room.solver.query.result.QueryResultBinder
import javax.lang.model.type.DeclaredType
-class InstantQueryResultBinderProvider(val context : Context) : QueryResultBinderProvider {
+class InstantQueryResultBinderProvider(val context: Context) : QueryResultBinderProvider {
override fun provide(declared: DeclaredType, query: ParsedQuery): QueryResultBinder {
return InstantQueryResultBinder(
context.typeAdapterStore.findQueryResultAdapter(declared, query))
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/LiveDataQueryResultBinderProvider.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/LiveDataQueryResultBinderProvider.kt
index 650ec19..b62eabd 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/LiveDataQueryResultBinderProvider.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/LiveDataQueryResultBinderProvider.kt
@@ -25,7 +25,7 @@
import javax.lang.model.type.DeclaredType
import javax.lang.model.type.TypeMirror
-class LiveDataQueryResultBinderProvider(context : Context)
+class LiveDataQueryResultBinderProvider(context: Context)
: ObservableQueryResultBinderProvider(context) {
private val liveDataTypeMirror: TypeMirror? by lazy {
context.processingEnv.elementUtils
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/RxCallableQueryResultBinderProvider.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/RxCallableQueryResultBinderProvider.kt
index 0bd3fb1..11b824f 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/RxCallableQueryResultBinderProvider.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/RxCallableQueryResultBinderProvider.kt
@@ -22,7 +22,6 @@
import android.arch.persistence.room.processor.Context
import android.arch.persistence.room.processor.ProcessorErrors
import android.arch.persistence.room.solver.QueryResultBinderProvider
-import android.arch.persistence.room.solver.query.result.InstantQueryResultBinder
import android.arch.persistence.room.solver.query.result.QueryResultBinder
import android.arch.persistence.room.solver.query.result.RxCallableQueryResultBinder
import javax.lang.model.type.DeclaredType
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/ArrayQueryParameterAdapter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/ArrayQueryParameterAdapter.kt
index 9cafb23..12756d8 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/ArrayQueryParameterAdapter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/ArrayQueryParameterAdapter.kt
@@ -26,7 +26,7 @@
/**
* Binds ARRAY(T) (e.g. int[]) into String[] args of a query.
*/
-class ArrayQueryParameterAdapter(val bindAdapter : StatementValueBinder)
+class ArrayQueryParameterAdapter(val bindAdapter: StatementValueBinder)
: QueryParameterAdapter(true) {
override fun bindToStmt(inputVarName: String, stmtVarName: String, startIndexVarName: String,
scope: CodeGenScope) {
@@ -41,7 +41,7 @@
}
}
- override fun getArgCount(inputVarName: String, outputVarName : String, scope: CodeGenScope) {
+ override fun getArgCount(inputVarName: String, outputVarName: String, scope: CodeGenScope) {
scope.builder()
.addStatement("final $T $L = $L.length", TypeName.INT, outputVarName, inputVarName)
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/BasicQueryParameterAdapter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/BasicQueryParameterAdapter.kt
index 11521f2..41ab2cf 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/BasicQueryParameterAdapter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/BasicQueryParameterAdapter.kt
@@ -22,7 +22,7 @@
/**
* Knows how to convert a query parameter into arguments
*/
-class BasicQueryParameterAdapter(val bindAdapter : StatementValueBinder)
+class BasicQueryParameterAdapter(val bindAdapter: StatementValueBinder)
: QueryParameterAdapter(false) {
override fun bindToStmt(inputVarName: String, stmtVarName: String, startIndexVarName: String,
scope: CodeGenScope) {
@@ -31,7 +31,7 @@
}
}
- override fun getArgCount(inputVarName: String, outputVarName : String, scope: CodeGenScope) {
+ override fun getArgCount(inputVarName: String, outputVarName: String, scope: CodeGenScope) {
throw UnsupportedOperationException("should not call getArgCount on basic adapters." +
"It is always one.")
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/CollectionQueryParameterAdapter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/CollectionQueryParameterAdapter.kt
index 7e0b206..00c350a 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/CollectionQueryParameterAdapter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/CollectionQueryParameterAdapter.kt
@@ -26,7 +26,7 @@
/**
* Binds Collection<T> (e.g. List<T>) into String[] query args.
*/
-class CollectionQueryParameterAdapter(val bindAdapter : StatementValueBinder)
+class CollectionQueryParameterAdapter(val bindAdapter: StatementValueBinder)
: QueryParameterAdapter(true) {
override fun bindToStmt(inputVarName: String, stmtVarName: String, startIndexVarName: String,
scope: CodeGenScope) {
@@ -41,7 +41,7 @@
}
}
- override fun getArgCount(inputVarName: String, outputVarName : String, scope: CodeGenScope) {
+ override fun getArgCount(inputVarName: String, outputVarName: String, scope: CodeGenScope) {
scope.builder()
.addStatement("final $T $L = $L.size()", TypeName.INT, outputVarName, inputVarName)
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/QueryParameterAdapter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/QueryParameterAdapter.kt
index b93659e..a42bfee 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/QueryParameterAdapter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/parameter/QueryParameterAdapter.kt
@@ -25,11 +25,14 @@
/**
* Must bind the value into the statement at the given index.
*/
- abstract fun bindToStmt(inputVarName: String, stmtVarName: String, startIndexVarName: String,
- scope: CodeGenScope)
+ abstract fun bindToStmt(
+ inputVarName: String,
+ stmtVarName: String,
+ startIndexVarName: String,
+ scope: CodeGenScope)
/**
* Should declare and set the given value with the count
*/
- abstract fun getArgCount(inputVarName: String, outputVarName : String, scope : CodeGenScope)
+ abstract fun getArgCount(inputVarName: String, outputVarName: String, scope: CodeGenScope)
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/CursorQueryResultBinder.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/CursorQueryResultBinder.kt
index 06ec339..fede566 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/CursorQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/CursorQueryResultBinder.kt
@@ -21,13 +21,12 @@
import android.arch.persistence.room.ext.N
import android.arch.persistence.room.ext.T
import android.arch.persistence.room.solver.CodeGenScope
-import android.arch.persistence.room.writer.DaoWriter
import com.squareup.javapoet.FieldSpec
class CursorQueryResultBinder : QueryResultBinder(NO_OP_RESULT_ADAPTER) {
override fun convertAndReturn(roomSQLiteQueryVar: String,
dbField: FieldSpec,
- inTransaction : Boolean,
+ inTransaction: Boolean,
scope: CodeGenScope) {
val builder = scope.builder()
val transactionWrapper = if (inTransaction) {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/FlowableQueryResultBinder.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/FlowableQueryResultBinder.kt
index e1a75b5..f4f1d43 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/FlowableQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/FlowableQueryResultBinder.kt
@@ -39,7 +39,7 @@
: BaseObservableQueryResultBinder(adapter) {
override fun convertAndReturn(roomSQLiteQueryVar: String,
dbField: FieldSpec,
- inTransaction : Boolean,
+ inTransaction: Boolean,
scope: CodeGenScope) {
val callableImpl = TypeSpec.anonymousClassBuilder("").apply {
val typeName = typeArg.typeName()
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/InstantQueryResultBinder.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/InstantQueryResultBinder.kt
index c18bf2d..b9623c1 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/InstantQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/InstantQueryResultBinder.kt
@@ -27,9 +27,9 @@
* Instantly runs and returns the query.
*/
class InstantQueryResultBinder(adapter: QueryResultAdapter?) : QueryResultBinder(adapter) {
- override fun convertAndReturn(roomSQLiteQueryVar : String,
+ override fun convertAndReturn(roomSQLiteQueryVar: String,
dbField: FieldSpec,
- inTransaction : Boolean,
+ inTransaction: Boolean,
scope: CodeGenScope) {
val transactionWrapper = if (inTransaction) {
scope.builder().transactionWrapper(dbField)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/LiveDataQueryResultBinder.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/LiveDataQueryResultBinder.kt
index 0ef8a93..1191ae3 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/LiveDataQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/LiveDataQueryResultBinder.kt
@@ -40,10 +40,12 @@
adapter: QueryResultAdapter?)
: BaseObservableQueryResultBinder(adapter) {
@Suppress("JoinDeclarationAndAssignment")
- override fun convertAndReturn(roomSQLiteQueryVar : String,
- dbField: FieldSpec,
- inTransaction : Boolean,
- scope: CodeGenScope) {
+ override fun convertAndReturn(
+ roomSQLiteQueryVar: String,
+ dbField: FieldSpec,
+ inTransaction: Boolean,
+ scope: CodeGenScope
+ ) {
val typeName = typeArg.typeName()
val liveDataImpl = TypeSpec.anonymousClassBuilder("").apply {
@@ -67,10 +69,14 @@
}
}
- private fun createComputeMethod(roomSQLiteQueryVar: String, typeName: TypeName,
- observerField: FieldSpec, dbField: FieldSpec,
- inTransaction: Boolean,
- scope: CodeGenScope): MethodSpec {
+ private fun createComputeMethod(
+ roomSQLiteQueryVar: String,
+ typeName: TypeName,
+ observerField: FieldSpec,
+ dbField: FieldSpec,
+ inTransaction: Boolean,
+ scope: CodeGenScope
+ ): MethodSpec {
return MethodSpec.methodBuilder("compute").apply {
addAnnotation(Override::class.java)
addModifiers(Modifier.PROTECTED)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/LivePagedListQueryResultBinder.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/LivePagedListQueryResultBinder.kt
index c10f9fb..ceb946e 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/LivePagedListQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/LivePagedListQueryResultBinder.kt
@@ -31,10 +31,12 @@
: QueryResultBinder(tiledDataSourceQueryResultBinder.listAdapter) {
@Suppress("HasPlatformType")
val typeName = tiledDataSourceQueryResultBinder.itemTypeName
- override fun convertAndReturn(roomSQLiteQueryVar: String,
- dbField: FieldSpec,
- inTransaction : Boolean,
- scope: CodeGenScope) {
+ override fun convertAndReturn(
+ roomSQLiteQueryVar: String,
+ dbField: FieldSpec,
+ inTransaction: Boolean,
+ scope: CodeGenScope
+ ) {
scope.builder().apply {
val pagedListProvider = TypeSpec
.anonymousClassBuilder("").apply {
@@ -50,11 +52,12 @@
}
}
- private fun createCreateDataSourceMethod(roomSQLiteQueryVar: String,
- dbField: FieldSpec,
- inTransaction : Boolean,
- scope: CodeGenScope): MethodSpec
- = MethodSpec.methodBuilder("createDataSource").apply {
+ private fun createCreateDataSourceMethod(
+ roomSQLiteQueryVar: String,
+ dbField: FieldSpec,
+ inTransaction: Boolean,
+ scope: CodeGenScope
+ ): MethodSpec = MethodSpec.methodBuilder("createDataSource").apply {
addAnnotation(Override::class.java)
addModifiers(Modifier.PROTECTED)
returns(tiledDataSourceQueryResultBinder.typeName)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/QueryResultAdapter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/QueryResultAdapter.kt
index aaf17cd..2f6ca75 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/QueryResultAdapter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/QueryResultAdapter.kt
@@ -21,10 +21,9 @@
/**
* Gets a Cursor and converts it into the return type of a method annotated with @Query.
*/
-abstract class QueryResultAdapter(val rowAdapter : RowAdapter?) {
+abstract class QueryResultAdapter(val rowAdapter: RowAdapter?) {
abstract fun convert(outVarName: String, cursorVarName: String, scope: CodeGenScope)
fun accessedTableNames(): List<String> {
return (rowAdapter as? PojoRowAdapter)?.relationTableNames() ?: emptyList<String>()
}
-
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/QueryResultBinder.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/QueryResultBinder.kt
index 652de46..a77d97f 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/QueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/QueryResultBinder.kt
@@ -33,6 +33,6 @@
*/
abstract fun convertAndReturn(roomSQLiteQueryVar: String,
dbField: FieldSpec,
- inTransaction : Boolean,
+ inTransaction: Boolean,
scope: CodeGenScope)
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/RowAdapter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/RowAdapter.kt
index 581baf2..cb25d97 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/RowAdapter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/RowAdapter.kt
@@ -24,11 +24,11 @@
* <p>
* An instance of this is created for each usage so that it can keep local variables.
*/
-abstract class RowAdapter(val out : TypeMirror) {
+abstract class RowAdapter(val out: TypeMirror) {
/**
* Called when cursor variable is ready, good place to put initialization code.
*/
- open fun onCursorReady(cursorVarName: String, scope : CodeGenScope) {}
+ open fun onCursorReady(cursorVarName: String, scope: CodeGenScope) {}
/**
* Called to convert a single row.
@@ -39,5 +39,5 @@
* Called when the cursor is finished. It is important to return null if no operation is
* necessary so that caller can understand that we can do lazy loading.
*/
- open fun onCursorFinished() : ((scope : CodeGenScope) -> Unit)? = null
+ open fun onCursorFinished(): ((scope: CodeGenScope) -> Unit)? = null
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/RxCallableQueryResultBinder.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/RxCallableQueryResultBinder.kt
index 1ab91e8..2aba076 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/RxCallableQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/RxCallableQueryResultBinder.kt
@@ -42,7 +42,7 @@
: QueryResultBinder(adapter) {
override fun convertAndReturn(roomSQLiteQueryVar: String,
dbField: FieldSpec,
- inTransaction : Boolean,
+ inTransaction: Boolean,
scope: CodeGenScope) {
val callable = TypeSpec.anonymousClassBuilder("").apply {
val typeName = typeArg.typeName()
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/TiledDataSourceQueryResultBinder.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/TiledDataSourceQueryResultBinder.kt
index 2281cfb..733fdee 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/TiledDataSourceQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/TiledDataSourceQueryResultBinder.kt
@@ -31,15 +31,15 @@
import com.squareup.javapoet.TypeSpec
import javax.lang.model.element.Modifier
-class TiledDataSourceQueryResultBinder(val listAdapter : ListQueryResultAdapter?,
- val tableNames : List<String>)
+class TiledDataSourceQueryResultBinder(val listAdapter: ListQueryResultAdapter?,
+ val tableNames: List<String>)
: QueryResultBinder(listAdapter) {
- val itemTypeName : TypeName = listAdapter?.rowAdapter?.out?.typeName() ?: TypeName.OBJECT
- val typeName : ParameterizedTypeName = ParameterizedTypeName.get(
+ val itemTypeName: TypeName = listAdapter?.rowAdapter?.out?.typeName() ?: TypeName.OBJECT
+ val typeName: ParameterizedTypeName = ParameterizedTypeName.get(
RoomTypeNames.LIMIT_OFFSET_DATA_SOURCE, itemTypeName)
override fun convertAndReturn(roomSQLiteQueryVar: String,
dbField: FieldSpec,
- inTransaction : Boolean,
+ inTransaction: Boolean,
scope: CodeGenScope) {
val tableNamesList = tableNames.joinToString(",") { "\"$it\"" }
val spec = TypeSpec.anonymousClassBuilder("$N, $L, $L, $L",
@@ -52,7 +52,7 @@
}
}
- fun createConvertRowsMethod(scope : CodeGenScope): MethodSpec =
+ fun createConvertRowsMethod(scope: CodeGenScope): MethodSpec =
MethodSpec.methodBuilder("convertRows").apply {
addAnnotation(Override::class.java)
addModifiers(Modifier.PROTECTED)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/TransactionWrapper.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/TransactionWrapper.kt
index 30d02ee..b48f179 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/TransactionWrapper.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/TransactionWrapper.kt
@@ -30,7 +30,7 @@
fun endTransactionWithControlFlow()
}
-fun MethodSpec.Builder.transactionWrapper(dbField : FieldSpec) = object : TransactionWrapper {
+fun MethodSpec.Builder.transactionWrapper(dbField: FieldSpec) = object : TransactionWrapper {
override fun beginTransactionWithControlFlow() {
addStatement("$N.beginTransaction()", dbField)
beginControlFlow("try")
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/BoxedBooleanToBoxedIntConverter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/BoxedBooleanToBoxedIntConverter.kt
index 552da9e..70030a8 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/BoxedBooleanToBoxedIntConverter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/BoxedBooleanToBoxedIntConverter.kt
@@ -43,7 +43,6 @@
scope.builder().addStatement("$L = $L == null ? null : $L != 0",
outputVarName, inputVarName, inputVarName)
}
-
}
)
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/BoxedPrimitiveColumnTypeAdapter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/BoxedPrimitiveColumnTypeAdapter.kt
index 1b34b46..debc59a 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/BoxedPrimitiveColumnTypeAdapter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/BoxedPrimitiveColumnTypeAdapter.kt
@@ -25,13 +25,15 @@
/**
* Adapters for all boxed primitives that has direct cursor mappings.
*/
-open class BoxedPrimitiveColumnTypeAdapter(boxed : TypeMirror,
- val primitiveAdapter : PrimitiveColumnTypeAdapter)
- : ColumnTypeAdapter(boxed, primitiveAdapter.typeAffinity) {
+open class BoxedPrimitiveColumnTypeAdapter(
+ boxed: TypeMirror,
+ val primitiveAdapter: PrimitiveColumnTypeAdapter
+) : ColumnTypeAdapter(boxed, primitiveAdapter.typeAffinity) {
companion object {
- fun createBoxedPrimitiveAdapters(processingEnvironment: ProcessingEnvironment,
- primitiveAdapters : List<PrimitiveColumnTypeAdapter>)
- : List<ColumnTypeAdapter> {
+ fun createBoxedPrimitiveAdapters(
+ processingEnvironment: ProcessingEnvironment,
+ primitiveAdapters: List<PrimitiveColumnTypeAdapter>
+ ): List<ColumnTypeAdapter> {
return primitiveAdapters.map {
BoxedPrimitiveColumnTypeAdapter(
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/ByteArrayColumnTypeAdapter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/ByteArrayColumnTypeAdapter.kt
index 014ea44..5de76de 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/ByteArrayColumnTypeAdapter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/ByteArrayColumnTypeAdapter.kt
@@ -22,7 +22,7 @@
import javax.annotation.processing.ProcessingEnvironment
import javax.lang.model.type.TypeKind
-class ByteArrayColumnTypeAdapter(env : ProcessingEnvironment) : ColumnTypeAdapter(
+class ByteArrayColumnTypeAdapter(env: ProcessingEnvironment) : ColumnTypeAdapter(
out = env.typeUtils.getArrayType(env.typeUtils.getPrimitiveType(TypeKind.BYTE)),
typeAffinity = SQLTypeAffinity.BLOB) {
override fun readFromCursor(outVarName: String, cursorVarName: String, indexVarName: String,
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/CompositeTypeConverter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/CompositeTypeConverter.kt
index 86a5272..b02709a 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/CompositeTypeConverter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/CompositeTypeConverter.kt
@@ -24,7 +24,7 @@
/**
* combines 2 type converters
*/
-class CompositeTypeConverter(val conv1 : TypeConverter, val conv2 : TypeConverter) : TypeConverter(
+class CompositeTypeConverter(val conv1: TypeConverter, val conv2: TypeConverter) : TypeConverter(
conv1.from, conv2.to) {
override fun convert(inputVarName: String, outputVarName: String, scope: CodeGenScope) {
scope.builder().apply {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/CursorValueReader.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/CursorValueReader.kt
index e6726cd..9293143 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/CursorValueReader.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/CursorValueReader.kt
@@ -25,8 +25,8 @@
* see: StatementValueBinder
*/
interface CursorValueReader {
- fun affinity() : SQLTypeAffinity
- fun typeMirror() : TypeMirror
- fun readFromCursor(outVarName : String, cursorVarName: String, indexVarName: String,
+ fun affinity(): SQLTypeAffinity
+ fun typeMirror(): TypeMirror
+ fun readFromCursor(outVarName: String, cursorVarName: String, indexVarName: String,
scope: CodeGenScope)
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/CustomTypeConverterWrapper.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/CustomTypeConverterWrapper.kt
index b4c7dc2..c127203 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/CustomTypeConverterWrapper.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/CustomTypeConverterWrapper.kt
@@ -46,7 +46,7 @@
}
}
- fun typeConverter(scope: CodeGenScope) : FieldSpec {
+ fun typeConverter(scope: CodeGenScope): FieldSpec {
val baseName = (custom.typeName as ClassName).simpleName().decapitalize()
return scope.writer.getOrCreateField(object : ClassWriter.SharedFieldSpec(
baseName, custom.typeName) {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/NoOpConverter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/NoOpConverter.kt
index e803d30..c37698b 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/NoOpConverter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/NoOpConverter.kt
@@ -28,7 +28,7 @@
* the query. Not having this would require us to special case handle String, String[], List<String>
* etc.
*/
-class NoOpConverter(type : TypeMirror) : TypeConverter(
+class NoOpConverter(type: TypeMirror) : TypeConverter(
type, type) {
override fun convert(inputVarName: String, outputVarName: String, scope: CodeGenScope) {
scope.builder()
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/PrimitiveColumnTypeAdapter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/PrimitiveColumnTypeAdapter.kt
index c04e7bb..69cc0f8 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/PrimitiveColumnTypeAdapter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/PrimitiveColumnTypeAdapter.kt
@@ -37,16 +37,17 @@
open class PrimitiveColumnTypeAdapter(out: PrimitiveType,
val cursorGetter: String,
val stmtSetter: String,
- typeAffinity : SQLTypeAffinity)
+ typeAffinity: SQLTypeAffinity)
: ColumnTypeAdapter(out, typeAffinity) {
- val cast = if (cursorGetter == "get${out.typeName().toString().capitalize()}")
+ val cast = if (cursorGetter == "get${out.typeName().toString().capitalize()}")
""
else
"(${out.typeName()}) "
companion object {
- fun createPrimitiveAdapters(processingEnvironment: ProcessingEnvironment)
- : List<PrimitiveColumnTypeAdapter> {
+ fun createPrimitiveAdapters(
+ processingEnvironment: ProcessingEnvironment
+ ): List<PrimitiveColumnTypeAdapter> {
return listOf(
Triple(INT, "getInt", "bindLong"),
Triple(SHORT, "getShort", "bindLong"),
@@ -60,7 +61,7 @@
out = processingEnvironment.typeUtils.getPrimitiveType(it.first),
cursorGetter = it.second,
stmtSetter = it.third,
- typeAffinity = when(it.first) {
+ typeAffinity = when (it.first) {
INT, SHORT, BYTE, LONG, CHAR -> SQLTypeAffinity.INTEGER
FLOAT, DOUBLE -> REAL
else -> throw IllegalArgumentException("invalid type")
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/StatementValueBinder.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/StatementValueBinder.kt
index c898268..d83c145 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/StatementValueBinder.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/StatementValueBinder.kt
@@ -24,7 +24,7 @@
* see: CursorValueReader
*/
interface StatementValueBinder {
- fun typeMirror() : TypeMirror
+ fun typeMirror(): TypeMirror
fun bindToStmt(stmtName: String, indexVarName: String, valueVarName: String,
scope: CodeGenScope)
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/TypeConverter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/TypeConverter.kt
index 134daf4..67b70dc 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/TypeConverter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/types/TypeConverter.kt
@@ -17,7 +17,6 @@
package android.arch.persistence.room.solver.types
import android.arch.persistence.room.solver.CodeGenScope
-import com.squareup.javapoet.TypeName
import javax.lang.model.type.TypeMirror
/**
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/ColumnInfo.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/ColumnInfo.kt
index e249871..652860b 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/ColumnInfo.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/ColumnInfo.kt
@@ -21,4 +21,4 @@
/**
* Represents a column in a query response
*/
-data class ColumnInfo(val name : String, val type : SQLTypeAffinity)
+data class ColumnInfo(val name: String, val type: SQLTypeAffinity)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/DatabaseVerificaitonErrors.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/DatabaseVerificaitonErrors.kt
index a744894..6b133b4 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/DatabaseVerificaitonErrors.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/DatabaseVerificaitonErrors.kt
@@ -19,19 +19,19 @@
import java.sql.SQLException
object DatabaseVerificaitonErrors {
- private val CANNOT_CREATE_TABLE : String = "Create table statement had an error: %s"
- fun cannotCreateTable(exception: SQLException) : String {
+ private val CANNOT_CREATE_TABLE: String = "Create table statement had an error: %s"
+ fun cannotCreateTable(exception: SQLException): String {
return CANNOT_CREATE_TABLE.format(exception.message)
}
- private val CANNOT_VERIFY_QUERY : String = "There is a problem with the query: %s"
- fun cannotVerifyQuery(exception: SQLException) : String {
+ private val CANNOT_VERIFY_QUERY: String = "There is a problem with the query: %s"
+ fun cannotVerifyQuery(exception: SQLException): String {
return CANNOT_VERIFY_QUERY.format(exception.message)
}
- private val CANNOT_CREATE_SQLITE_CONNECTION : String = "Room cannot create an SQLite" +
+ private val CANNOT_CREATE_SQLITE_CONNECTION: String = "Room cannot create an SQLite" +
" connection to verify the queries. Query verification will be disabled. Error: %s"
- fun cannotCreateConnection(exception: Exception) : String {
+ fun cannotCreateConnection(exception: Exception): String {
return CANNOT_CREATE_SQLITE_CONNECTION.format(exception.message)
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/DatabaseVerifier.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/DatabaseVerifier.kt
index 11acbdf..d384c3c 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/DatabaseVerifier.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/DatabaseVerifier.kt
@@ -33,7 +33,7 @@
* This class is also used to resolve the return types.
*/
class DatabaseVerifier private constructor(
- val connection : Connection, val context : Context, val entities : List<Entity>) {
+ val connection: Connection, val context: Context, val entities: List<Entity>) {
companion object {
private const val CONNECTION_URL = "jdbc:sqlite::memory:"
@@ -54,11 +54,11 @@
/**
* Tries to create a verifier but returns null if it cannot find the driver.
*/
- fun create(context: Context, element: Element, entities: List<Entity>) : DatabaseVerifier? {
+ fun create(context: Context, element: Element, entities: List<Entity>): DatabaseVerifier? {
return try {
val connection = JDBC.createConnection(CONNECTION_URL, java.util.Properties())
DatabaseVerifier(connection, context, entities)
- } catch (ex : Exception) {
+ } catch (ex: Exception) {
context.logger.w(Warning.CANNOT_CREATE_VERIFICATION_DATABASE, element,
DatabaseVerificaitonErrors.cannotCreateConnection(ex))
null
@@ -76,7 +76,7 @@
DriverManager.getDriver(CONNECTION_URL)?.let {
DriverManager.deregisterDriver(it)
}
- } catch (t : Throwable) {
+ } catch (t: Throwable) {
System.err.println("Room: cannot unregister driver ${t.message}")
}
}
@@ -88,11 +88,11 @@
}
}
- fun analyze(sql : String) : QueryResultInfo {
+ fun analyze(sql: String): QueryResultInfo {
return try {
val stmt = connection.prepareStatement(sql)
QueryResultInfo(stmt.columnInfo())
- } catch (ex : SQLException) {
+ } catch (ex: SQLException) {
QueryResultInfo(emptyList(), ex)
}
}
@@ -101,7 +101,7 @@
if (!connection.isClosed) {
try {
connection.close()
- } catch (t : Throwable) {
+ } catch (t: Throwable) {
//ignore.
context.logger.d("failed to close the database connection ${t.message}")
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/QueryResultInfo.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/QueryResultInfo.kt
index 4a99243..41b348f 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/QueryResultInfo.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/QueryResultInfo.kt
@@ -24,4 +24,4 @@
* This information is obtained by preparing the query against an in memory database at compile
* time.
*/
-data class QueryResultInfo(val columns : List<ColumnInfo>, val error : SQLException? = null)
+data class QueryResultInfo(val columns: List<ColumnInfo>, val error: SQLException? = null)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/jdbc_ext.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/jdbc_ext.kt
index 5ae9d6a..47b9442 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/jdbc_ext.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/verifier/jdbc_ext.kt
@@ -33,10 +33,10 @@
return result
}
-private fun <T> PreparedStatement.map(f : (Int, ResultSetMetaData) -> T) : List<T> {
+private fun <T> PreparedStatement.map(f: (Int, ResultSetMetaData) -> T): List<T> {
val columnCount = try {
metaData.columnCount
- } catch (ex : SQLException) {
+ } catch (ex: SQLException) {
// ignore, no-result query
0
}
@@ -48,10 +48,10 @@
return map { index, data -> data.getColumnName(index) }
}
-private fun PreparedStatement.tryGetAffinity(columnIndex : Int) : SQLTypeAffinity {
+private fun PreparedStatement.tryGetAffinity(columnIndex: Int): SQLTypeAffinity {
return try {
SQLTypeAffinity.valueOf(metaData.getColumnTypeName(columnIndex).capitalize())
- } catch (ex : IllegalArgumentException) {
+ } catch (ex: IllegalArgumentException) {
SQLTypeAffinity.NULL
}
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Constructor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Constructor.kt
index fdc2a11..112c9b4 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Constructor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Constructor.kt
@@ -22,9 +22,9 @@
* For each Entity / Pojo we process has a constructor. It might be the empty constructor or a
* constructor with fields.
*/
-data class Constructor(val element : ExecutableElement, val params : List<Param>) {
+data class Constructor(val element: ExecutableElement, val params: List<Param>) {
- fun hasField(field : Field) : Boolean {
+ fun hasField(field: Field): Boolean {
return params.any {
when (it) {
is FieldParam -> it.field === field
@@ -34,18 +34,16 @@
}
}
- class FieldParam(val field : Field) : Param(ParamType.FIELD) {
+ class FieldParam(val field: Field) : Param(ParamType.FIELD) {
override fun log(): String = field.getPath()
-
}
class EmbeddedParam(val embedded: EmbeddedField) : Param(ParamType.EMBEDDED) {
override fun log(): String = embedded.field.getPath()
-
}
- abstract class Param(val type : ParamType) {
- abstract fun log() : String;
+ abstract class Param(val type: ParamType) {
+ abstract fun log(): String
}
enum class ParamType {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/CustomTypeConverter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/CustomTypeConverter.kt
index 5a1f0e6..3bbae96 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/CustomTypeConverter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/CustomTypeConverter.kt
@@ -27,7 +27,7 @@
* Generated when we parse a method annotated with TypeConverter.
*/
data class CustomTypeConverter(val type: TypeMirror,
- val method : ExecutableElement,
+ val method: ExecutableElement,
val from: TypeMirror, val to: TypeMirror) {
val typeName: TypeName by lazy { type.typeName() }
val fromTypeName: TypeName by lazy { from.typeName() }
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Dao.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Dao.kt
index 57d7598..d0ef212 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Dao.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Dao.kt
@@ -21,25 +21,25 @@
import javax.lang.model.element.TypeElement
import javax.lang.model.type.DeclaredType
-data class Dao(val element : TypeElement, val type : DeclaredType,
+data class Dao(val element: TypeElement, val type: DeclaredType,
val queryMethods: List<QueryMethod>,
- val insertionMethods : List<InsertionMethod>,
- val deletionMethods : List<DeletionMethod>,
- val updateMethods : List<UpdateMethod>,
- val transactionMethods : List<TransactionMethod>,
- val constructorParamType : TypeName?) {
+ val insertionMethods: List<InsertionMethod>,
+ val deletionMethods: List<DeletionMethod>,
+ val updateMethods: List<UpdateMethod>,
+ val transactionMethods: List<TransactionMethod>,
+ val constructorParamType: TypeName?) {
// parsed dao might have a suffix if it is used in multiple databases.
- private var suffix : String? = null
- fun setSuffix(newSuffix : String) {
+ private var suffix: String? = null
+ fun setSuffix(newSuffix: String) {
if (this.suffix != null) {
throw IllegalStateException("cannot set suffix twice")
}
this.suffix = if (newSuffix == "") "" else "_$newSuffix"
}
- val typeName : ClassName by lazy { ClassName.get(element) }
+ val typeName: ClassName by lazy { ClassName.get(element) }
- val shortcutMethods : List<ShortcutMethod> by lazy {
+ val shortcutMethods: List<ShortcutMethod> by lazy {
deletionMethods + updateMethods
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/DaoMethod.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/DaoMethod.kt
index bd5e6b8..bf134ad 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/DaoMethod.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/DaoMethod.kt
@@ -21,4 +21,4 @@
/**
* References a method that returns a dao in a Database
*/
-data class DaoMethod(val element : Element, val name : String, val dao : Dao)
+data class DaoMethod(val element: Element, val name: String, val dao: Dao)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Database.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Database.kt
index b118a32..02e83b3 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Database.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Database.kt
@@ -34,7 +34,7 @@
val daoMethods: List<DaoMethod>,
val version: Int,
val exportSchema: Boolean,
- val enableForeignKeys : Boolean) {
+ val enableForeignKeys: Boolean) {
val typeName: ClassName by lazy { ClassName.get(element) }
private val implClassName by lazy {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/DeletionMethod.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/DeletionMethod.kt
index c4adc54..e122c85 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/DeletionMethod.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/DeletionMethod.kt
@@ -17,8 +17,9 @@
import javax.lang.model.element.ExecutableElement
-class DeletionMethod(element: ExecutableElement, name: String,
- entities: Map<String, Entity>, returnCount : Boolean,
- parameters: List<ShortcutQueryParameter>) : ShortcutMethod(
- element, name, entities, returnCount, parameters
-)
+class DeletionMethod(
+ element: ExecutableElement,
+ name: String,
+ entities: Map<String, Entity>, returnCount: Boolean,
+ parameters: List<ShortcutQueryParameter>
+) : ShortcutMethod(element, name, entities, returnCount, parameters)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/EmbeddedField.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/EmbeddedField.kt
index 55e9cc4..55539a2 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/EmbeddedField.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/EmbeddedField.kt
@@ -23,8 +23,8 @@
* Used when a field is embedded inside an Entity or Pojo.
*/
// used in cache matching, must stay as a data class or implement equals
-data class EmbeddedField(val field : Field, val prefix : String = "",
- val parent : EmbeddedField?) {
+data class EmbeddedField(val field: Field, val prefix: String = "",
+ val parent: EmbeddedField?) {
val getter by lazy { field.getter }
val setter by lazy { field.setter }
val nonNull = field.element.hasAnnotation(NonNull::class)
@@ -33,7 +33,7 @@
parent?.mRootParent ?: this
}
- fun isDescendantOf(other : EmbeddedField) : Boolean {
+ fun isDescendantOf(other: EmbeddedField): Boolean {
if (parent == other) {
return true
} else if (parent == null) {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Entity.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Entity.kt
index 06e7484..48592bd 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Entity.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Entity.kt
@@ -33,7 +33,7 @@
createTableQuery(tableName)
}
- fun createTableQuery(tableName : String) : String {
+ fun createTableQuery(tableName: String): String {
val definitions = (fields.map {
val autoIncrement = primaryKey.autoGenerateId && primaryKey.fields.contains(it)
it.databaseDefinition(autoIncrement)
@@ -41,7 +41,7 @@
return "CREATE TABLE IF NOT EXISTS `$tableName` (${definitions.joinToString(", ")})"
}
- private fun createForeignKeyDefinitions() : List<String> {
+ private fun createForeignKeyDefinitions(): List<String> {
return foreignKeys.map { it.databaseDefinition() }
}
@@ -59,12 +59,12 @@
fun toBundle(): EntityBundle = EntityBundle(
tableName,
createTableQuery(BundleUtil.TABLE_NAME_PLACEHOLDER),
- fields.map {it.toBundle()},
+ fields.map { it.toBundle() },
primaryKey.toBundle(),
indices.map { it.toBundle() },
foreignKeys.map { it.toBundle() })
- fun isUnique(columns: List<String>) : Boolean {
+ fun isUnique(columns: List<String>): Boolean {
return if (primaryKey.columnNames.size == columns.size
&& primaryKey.columnNames.containsAll(columns)) {
true
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Field.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Field.kt
index fa0575a..838016e 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Field.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Field.kt
@@ -35,7 +35,7 @@
* embedded child of the main Pojo*/
val parent: EmbeddedField? = null,
// index might be removed when being merged into an Entity
- var indexed : Boolean = false) {
+ var indexed: Boolean = false) {
lateinit var getter: FieldGetter
lateinit var setter: FieldSetter
// binds the field into a statement
@@ -50,7 +50,7 @@
/**
* Used when reporting errors on duplicate names
*/
- fun getPath() : String {
+ fun getPath(): String {
return if (parent == null) {
name
} else {
@@ -58,7 +58,7 @@
}
}
- private val pathWithDotNotation : String by lazy {
+ private val pathWithDotNotation: String by lazy {
if (parent == null) {
name
} else {
@@ -111,7 +111,7 @@
/**
* definition to be used in create query
*/
- fun databaseDefinition(autoIncrementPKey : Boolean) : String {
+ fun databaseDefinition(autoIncrementPKey: Boolean): String {
val columnSpec = StringBuilder("")
if (autoIncrementPKey) {
columnSpec.append(" PRIMARY KEY AUTOINCREMENT")
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/FieldGetter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/FieldGetter.kt
index 6713c2c..70a9bc3 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/FieldGetter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/FieldGetter.kt
@@ -22,7 +22,7 @@
import com.squareup.javapoet.TypeName
import javax.lang.model.type.TypeMirror
-data class FieldGetter(val name : String, val type : TypeMirror, val callType: CallType) {
+data class FieldGetter(val name: String, val type: TypeMirror, val callType: CallType) {
fun writeGet(ownerVar: String, outVar: String, builder: CodeBlock.Builder) {
val stmt = when (callType) {
CallType.FIELD -> "final $T $L = $L.$L"
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/FieldWithIndex.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/FieldWithIndex.kt
index 6ef6979..b30dcc9 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/FieldWithIndex.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/FieldWithIndex.kt
@@ -23,9 +23,9 @@
* If we are sure that the field will be there at compile time, we set it to always Exists so that
* the generated code does not check for -1 column indices.
*/
-data class FieldWithIndex(val field : Field, val indexVar : String, val alwaysExists : Boolean) {
+data class FieldWithIndex(val field: Field, val indexVar: String, val alwaysExists: Boolean) {
companion object {
- fun byOrder(fields : List<Field>) : List<FieldWithIndex> {
+ fun byOrder(fields: List<Field>): List<FieldWithIndex> {
return fields.mapIndexed { index, field ->
FieldWithIndex(field = field,
indexVar = "${index + 1}",
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/ForeignKeyAction.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/ForeignKeyAction.kt
index 1b85910..c6ed9da 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/ForeignKeyAction.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/ForeignKeyAction.kt
@@ -21,7 +21,7 @@
/**
* Compiler representation of ForeignKey#Action.
*/
-enum class ForeignKeyAction(val annotationValue : Int, val sqlName : String) {
+enum class ForeignKeyAction(val annotationValue: Int, val sqlName: String) {
NO_ACTION(ForeignKey.NO_ACTION, "NO ACTION"),
RESTRICT(ForeignKey.RESTRICT, "RESTRICT"),
SET_NULL(ForeignKey.SET_NULL, "SET NULL"),
@@ -31,6 +31,6 @@
private val mapping by lazy {
ForeignKeyAction.values().associateBy { it.annotationValue }
}
- fun fromAnnotationValue(value : Int?) = mapping[value]
+ fun fromAnnotationValue(value: Int?) = mapping[value]
}
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Index.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Index.kt
index 0bee2e0..694c627 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Index.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Index.kt
@@ -22,12 +22,12 @@
/**
* Represents a processed index.
*/
-data class Index(val name : String, val unique : Boolean, val fields : List<Field>) {
+data class Index(val name: String, val unique: Boolean, val fields: List<Field>) {
companion object {
// should match the value in TableInfo.Index.DEFAULT_PREFIX
const val DEFAULT_PREFIX = "index_"
}
- fun createQuery(tableName : String) : String {
+ fun createQuery(tableName: String): String {
val uniqueSQL = if (unique) {
"UNIQUE"
} else {
@@ -39,7 +39,7 @@
""".trimIndent().replace("\n", " ")
}
- val columnNames by lazy { fields.map {it.columnName} }
+ val columnNames by lazy { fields.map { it.columnName } }
fun toBundle(): IndexBundle = IndexBundle(name, unique, fields.map { it.columnName },
createQuery(BundleUtil.TABLE_NAME_PLACEHOLDER))
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/InsertionMethod.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/InsertionMethod.kt
index ad3688d..19573cf 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/InsertionMethod.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/InsertionMethod.kt
@@ -29,7 +29,7 @@
val entities: Map<String, Entity>, val returnType: TypeMirror,
val insertionType: Type?,
val parameters: List<ShortcutQueryParameter>) {
- fun insertMethodTypeFor(param : ShortcutQueryParameter) : Type {
+ fun insertMethodTypeFor(param: ShortcutQueryParameter): Type {
return if (insertionType == Type.INSERT_VOID || insertionType == null) {
Type.INSERT_VOID
} else if (!param.isMultiple) {
@@ -41,7 +41,7 @@
enum class Type(
// methodName matches EntityInsertionAdapter methods
- val methodName : String, val returnTypeName : TypeName) {
+ val methodName: String, val returnTypeName: TypeName) {
INSERT_VOID("insert", TypeName.VOID), // return void
INSERT_SINGLE_ID("insertAndReturnId", TypeName.LONG), // return long
INSERT_ID_ARRAY("insertAndReturnIdsArray",
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Pojo.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Pojo.kt
index acc63af..629c6b8 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Pojo.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Pojo.kt
@@ -18,7 +18,6 @@
import android.arch.persistence.room.ext.typeName
import com.squareup.javapoet.TypeName
-import javax.lang.model.element.ElementKind
import javax.lang.model.element.TypeElement
import javax.lang.model.type.DeclaredType
@@ -26,8 +25,8 @@
* A class is turned into a Pojo if it is used in a query response.
*/
// TODO make data class when move to kotlin 1.1
-open class Pojo(val element : TypeElement, val type: DeclaredType, val fields : List<Field>,
+open class Pojo(val element: TypeElement, val type: DeclaredType, val fields: List<Field>,
val embeddedFields: List<EmbeddedField>, val relations: List<Relation>,
- val constructor : Constructor? = null) {
+ val constructor: Constructor? = null) {
val typeName: TypeName by lazy { type.typeName() }
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/PrimaryKey.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/PrimaryKey.kt
index 9735668..d1a2c21 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/PrimaryKey.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/PrimaryKey.kt
@@ -21,13 +21,13 @@
/**
* Represents a PrimaryKey for an Entity.
*/
-data class PrimaryKey(val declaredIn : Element?, val fields: List<Field>,
+data class PrimaryKey(val declaredIn: Element?, val fields: List<Field>,
val autoGenerateId: Boolean) {
companion object {
val MISSING = PrimaryKey(null, emptyList(), false)
}
- val columnNames by lazy { fields.map {it.columnName} }
+ val columnNames by lazy { fields.map { it.columnName } }
fun toHumanReadableString(): String {
return "PrimaryKey[" +
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/QueryMethod.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/QueryMethod.kt
index a6b8cb7..482a1c4 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/QueryMethod.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/QueryMethod.kt
@@ -29,8 +29,8 @@
*/
data class QueryMethod(val element: ExecutableElement, val query: ParsedQuery, val name: String,
val returnType: TypeMirror, val parameters: List<QueryParameter>,
- val inTransaction : Boolean,
- val queryResultBinder : QueryResultBinder) {
+ val inTransaction: Boolean,
+ val queryResultBinder: QueryResultBinder) {
val sectionToParamMapping by lazy {
query.bindSections.map {
if (it.text.trim() == "?") {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/QueryParameter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/QueryParameter.kt
index 60ab55e..cca25ae 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/QueryParameter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/QueryParameter.kt
@@ -23,4 +23,4 @@
* Holds the parameter for a {@link QueryMethod}.
*/
data class QueryParameter(val name: String, val type: TypeMirror,
- val queryParamAdapter : QueryParameterAdapter?)
+ val queryParamAdapter: QueryParameterAdapter?)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/RelationCollector.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/RelationCollector.kt
index c11091c..bc296fc 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/RelationCollector.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/RelationCollector.kt
@@ -49,13 +49,13 @@
* Internal class that is used to manage fetching 1/N to N relationships.
*/
data class RelationCollector(val relation: Relation,
- val affinity : SQLTypeAffinity,
+ val affinity: SQLTypeAffinity,
val mapTypeName: ParameterizedTypeName,
val keyTypeName: TypeName,
val collectionTypeName: ParameterizedTypeName,
val queryWriter: QueryWriter,
val rowAdapter: RowAdapter,
- val loadAllQuery : ParsedQuery) {
+ val loadAllQuery: ParsedQuery) {
// set when writing the code generator in writeInitCode
lateinit var varName: String
@@ -67,8 +67,8 @@
}
// called after reading each item to extract the key if it exists
- fun writeReadParentKeyCode(cursorVarName: String, itemVar : String,
- fieldsWithIndices : List<FieldWithIndex>, scope: CodeGenScope) {
+ fun writeReadParentKeyCode(cursorVarName: String, itemVar: String,
+ fieldsWithIndices: List<FieldWithIndex>, scope: CodeGenScope) {
val indexVar = fieldsWithIndices.firstOrNull {
it.field === relation.parentField
}?.indexVar
@@ -123,8 +123,10 @@
}
companion object {
- fun createCollectors(baseContext : Context, relations: List<Relation>)
- : List<RelationCollector> {
+ fun createCollectors(
+ baseContext: Context,
+ relations: List<Relation>
+ ): List<RelationCollector> {
return relations.map { relation ->
// decide on the affinity
val context = baseContext.fork(relation.field.element)
@@ -194,7 +196,7 @@
)
// row adapter that matches full response
- fun getDefaultRowAdapter() : RowAdapter? {
+ fun getDefaultRowAdapter(): RowAdapter? {
return context.typeAdapterStore.findRowAdapter(relation.pojo.type, parsedQuery)
}
val rowAdapter = if (relation.projection.size == 1 && resultInfo != null &&
@@ -246,7 +248,7 @@
}
}
- private fun keyTypeFor(context : Context, affinity: SQLTypeAffinity): TypeName {
+ private fun keyTypeFor(context: Context, affinity: SQLTypeAffinity): TypeName {
return when (affinity) {
SQLTypeAffinity.INTEGER -> TypeName.LONG.box()
SQLTypeAffinity.REAL -> TypeName.DOUBLE.box()
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/ShortcutQueryParameter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/ShortcutQueryParameter.kt
index 29fc759..db8a0f5 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/ShortcutQueryParameter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/ShortcutQueryParameter.kt
@@ -26,7 +26,7 @@
/**
* Method name in entity insertion or update adapter.
*/
- fun handleMethodName() : String {
+ fun handleMethodName(): String {
return if (isMultiple) {
"handleMultiple"
} else {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DaoWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DaoWriter.kt
index 0bb9c19..5125444 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DaoWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DaoWriter.kt
@@ -115,8 +115,8 @@
return builder
}
- private fun createPreparedDeleteOrUpdateQueries(preparedDeleteQueries: List<QueryMethod>)
- : List<PreparedStmtQuery> {
+ private fun createPreparedDeleteOrUpdateQueries(
+ preparedDeleteQueries: List<QueryMethod>): List<PreparedStmtQuery> {
return preparedDeleteQueries.map { method ->
val fieldSpec = getOrCreateField(PreparedStatementField(method))
val queryWriter = QueryWriter(method)
@@ -128,9 +128,11 @@
}
}
- private fun createPreparedDeleteQueryMethodBody(method: QueryMethod,
- preparedStmtField: FieldSpec,
- queryWriter: QueryWriter): MethodSpec {
+ private fun createPreparedDeleteQueryMethodBody(
+ method: QueryMethod,
+ preparedStmtField: FieldSpec,
+ queryWriter: QueryWriter
+ ): MethodSpec {
val scope = CodeGenScope(this)
val methodBuilder = overrideWithoutAnnotations(method.element, declaredDao).apply {
val stmtName = scope.getTmpVar("_stmt")
@@ -278,9 +280,10 @@
}.filterNotNull()
}
- private fun createInsertionMethodBody(method: InsertionMethod,
- insertionAdapters: Map<String, Pair<FieldSpec, TypeSpec>>)
- : CodeBlock {
+ private fun createInsertionMethodBody(
+ method: InsertionMethod,
+ insertionAdapters: Map<String, Pair<FieldSpec, TypeSpec>>
+ ): CodeBlock {
val insertionType = method.insertionType
if (insertionAdapters.isEmpty() || insertionType == null) {
return CodeBlock.builder().build()
@@ -346,9 +349,10 @@
})
}
- private fun <T : ShortcutMethod> createShortcutMethods(methods: List<T>, methodPrefix: String,
- implCallback: (T, Entity) -> TypeSpec)
- : List<PreparedStmtQuery> {
+ private fun <T : ShortcutMethod> createShortcutMethods(
+ methods: List<T>, methodPrefix: String,
+ implCallback: (T, Entity) -> TypeSpec
+ ): List<PreparedStmtQuery> {
return methods.map { method ->
val entities = method.entities
@@ -368,9 +372,10 @@
}.filterNotNull()
}
- private fun createDeleteOrUpdateMethodBody(method: ShortcutMethod,
- adapters: Map<String, Pair<FieldSpec, TypeSpec>>)
- : CodeBlock {
+ private fun createDeleteOrUpdateMethodBody(
+ method: ShortcutMethod,
+ adapters: Map<String, Pair<FieldSpec, TypeSpec>>
+ ): CodeBlock {
if (adapters.isEmpty()) {
return CodeBlock.builder().build()
}
@@ -434,7 +439,6 @@
addStatement("$N.endTransaction()", dbField)
}
endControlFlow()
-
}
return scope.builder().build()
}
@@ -454,7 +458,7 @@
}
private fun overrideWithoutAnnotations(elm: ExecutableElement,
- owner : DeclaredType): MethodSpec.Builder {
+ owner: DeclaredType): MethodSpec.Builder {
val baseSpec = MethodSpec.overriding(elm, owner, processingEnv.typeUtils).build()
return MethodSpec.methodBuilder(baseSpec.name).apply {
addAnnotation(Override::class.java)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DatabaseWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DatabaseWriter.kt
index e40bd71..7755a61 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DatabaseWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/DatabaseWriter.kt
@@ -39,7 +39,7 @@
/**
* Writes implementation of classes that were annotated with @Database.
*/
-class DatabaseWriter(val database : Database) : ClassWriter(database.implTypeName) {
+class DatabaseWriter(val database: Database) : ClassWriter(database.implTypeName) {
override fun createTypeSpecBuilder(): TypeSpec.Builder {
val builder = TypeSpec.classBuilder(database.implTypeName)
builder.apply {
@@ -64,7 +64,7 @@
}.build()
}
- private fun addDaoImpls(builder: TypeSpec.Builder) {
+ private fun addDaoImpls(builder: TypeSpec.Builder) {
val scope = CodeGenScope(this)
builder.apply {
database.daoMethods.forEach { method ->
@@ -78,7 +78,7 @@
}
}
- private fun createDaoGetter(field: FieldSpec, method: DaoMethod) : MethodSpec {
+ private fun createDaoGetter(field: FieldSpec, method: DaoMethod): MethodSpec {
return MethodSpec.overriding(MoreElements.asExecutable(method.element)).apply {
beginControlFlow("if ($N != null)", field).apply {
addStatement("return $N", field)
@@ -97,7 +97,7 @@
}.build()
}
- private fun createCreateOpenHelper() : MethodSpec {
+ private fun createCreateOpenHelper(): MethodSpec {
val scope = CodeGenScope(this)
return MethodSpec.methodBuilder("createOpenHelper").apply {
addModifiers(Modifier.PROTECTED)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/EntityCursorConverterWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/EntityCursorConverterWriter.kt
index a83d191..a96e23c 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/EntityCursorConverterWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/EntityCursorConverterWriter.kt
@@ -23,7 +23,6 @@
import android.arch.persistence.room.ext.T
import android.arch.persistence.room.solver.CodeGenScope
import android.arch.persistence.room.vo.Entity
-import android.arch.persistence.room.vo.Field
import android.arch.persistence.room.vo.EmbeddedField
import android.arch.persistence.room.vo.FieldWithIndex
import com.squareup.javapoet.CodeBlock
@@ -58,8 +57,7 @@
}
}
- private fun buildConvertMethodBody(writer: ClassWriter, cursorParam: ParameterSpec)
- : CodeBlock {
+ private fun buildConvertMethodBody(writer: ClassWriter, cursorParam: ParameterSpec): CodeBlock {
val scope = CodeGenScope(writer)
val entityVar = scope.getTmpVar("_entity")
scope.builder().apply {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/EntityInsertionAdapterWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/EntityInsertionAdapterWriter.kt
index cd3e771..26ff47b 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/EntityInsertionAdapterWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/EntityInsertionAdapterWriter.kt
@@ -32,7 +32,7 @@
import javax.lang.model.element.Modifier.PUBLIC
class EntityInsertionAdapterWriter(val entity: Entity, val onConflict: String) {
- fun createAnonymous(classWriter: ClassWriter, dbParam : String): TypeSpec {
+ fun createAnonymous(classWriter: ClassWriter, dbParam: String): TypeSpec {
@Suppress("RemoveSingleExpressionStringTemplate")
return TypeSpec.anonymousClassBuilder("$L", dbParam).apply {
superclass(
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/EntityUpdateAdapterWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/EntityUpdateAdapterWriter.kt
index b5711dc..8dee8e1 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/EntityUpdateAdapterWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/EntityUpdateAdapterWriter.kt
@@ -31,7 +31,7 @@
import com.squareup.javapoet.TypeSpec
import javax.lang.model.element.Modifier.PUBLIC
-class EntityUpdateAdapterWriter(val entity: Entity, val onConflict : String) {
+class EntityUpdateAdapterWriter(val entity: Entity, val onConflict: String) {
fun createAnonymous(classWriter: ClassWriter, dbParam: String): TypeSpec {
@Suppress("RemoveSingleExpressionStringTemplate")
return TypeSpec.anonymousClassBuilder("$L", dbParam).apply {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/FieldReadWriteWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/FieldReadWriteWriter.kt
index 8df3feb..4aa795a 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/FieldReadWriteWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/FieldReadWriteWriter.kt
@@ -64,9 +64,10 @@
* them. This work is done here instead of parsing because the result may include arbitrary
* fields.
*/
- private fun createNodeTree(rootVar: String,
- fieldsWithIndices: List<FieldWithIndex>,
- scope: CodeGenScope): Node {
+ private fun createNodeTree(
+ rootVar: String,
+ fieldsWithIndices: List<FieldWithIndex>,
+ scope: CodeGenScope): Node {
val allParents = getAllParents(fieldsWithIndices.map { it.field })
val rootNode = Node(rootVar, null)
rootNode.directFields = fieldsWithIndices.filter { it.field.parent == null }
@@ -88,9 +89,12 @@
return rootNode
}
- fun bindToStatement(ownerVar: String, stmtParamVar: String,
- fieldsWithIndices: List<FieldWithIndex>,
- scope: CodeGenScope) {
+ fun bindToStatement(
+ ownerVar: String,
+ stmtParamVar: String,
+ fieldsWithIndices: List<FieldWithIndex>,
+ scope: CodeGenScope
+ ) {
fun visitNode(node: Node) {
fun bindWithDescendants() {
node.directFields.forEach {
@@ -133,9 +137,13 @@
* reading statement since we may never read if the cursor does not have necessary
* columns.
*/
- private fun construct(outVar : String, constructor : Constructor?, typeName : TypeName,
- localVariableNames : Map<String, FieldWithIndex>,
- localEmbeddeds: List<Node>, scope: CodeGenScope) {
+ private fun construct(
+ outVar: String,
+ constructor: Constructor?,
+ typeName: TypeName,
+ localVariableNames: Map<String, FieldWithIndex>,
+ localEmbeddeds: List<Node>, scope: CodeGenScope
+ ) {
if (constructor == null) {
// best hope code generation
scope.builder().apply {
@@ -144,7 +152,7 @@
return
}
val variableNames = constructor.params.map { param ->
- when(param) {
+ when (param) {
is Constructor.FieldParam -> localVariableNames.entries.firstOrNull {
it.value.field === param.field
}?.key
@@ -154,7 +162,7 @@
else -> null
}
}
- val args = variableNames.joinToString(",") { it ?: "null"}
+ val args = variableNames.joinToString(",") { it ?: "null" }
scope.builder().apply {
addStatement("$L = new $T($L)", outVar, typeName, args)
}
@@ -163,12 +171,14 @@
/**
* Reads the row into the given variable. It does not declare it but constructs it.
*/
- fun readFromCursor(outVar: String,
- outPojo : Pojo,
- cursorVar: String,
- fieldsWithIndices: List<FieldWithIndex>,
- scope: CodeGenScope,
- relationCollectors : List<RelationCollector>) {
+ fun readFromCursor(
+ outVar: String,
+ outPojo: Pojo,
+ cursorVar: String,
+ fieldsWithIndices: List<FieldWithIndex>,
+ scope: CodeGenScope,
+ relationCollectors: List<RelationCollector>
+ ) {
fun visitNode(node: Node) {
val fieldParent = node.fieldParent
fun readNode() {
@@ -248,7 +258,6 @@
} else {
"( ${it.indexVar} == -1 || $cursorVar.isNull(${it.indexVar}))"
}
-
}
scope.builder().apply {
beginControlFlow("if (! ($L))", allNullCheck).apply {
@@ -326,7 +335,7 @@
/**
* Reads the value into a temporary local variable.
*/
- fun readIntoTmpVar(cursorVar: String, scope: CodeGenScope) : String {
+ fun readIntoTmpVar(cursorVar: String, scope: CodeGenScope): String {
val tmpField = scope.getTmpVar("_tmp${field.name.capitalize()}")
val typeName = field.getter.type.typeName()
scope.builder().apply {
@@ -353,7 +362,8 @@
// root for me
val varName: String,
// set if I'm a FieldParent
- val fieldParent: EmbeddedField?) {
+ val fieldParent: EmbeddedField?
+ ) {
// whom do i belong
var parentNode: Node? = null
// these fields are my direct fields
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/PreparedStatementWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/PreparedStatementWriter.kt
index 9c3e612..7982ace 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/PreparedStatementWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/PreparedStatementWriter.kt
@@ -29,7 +29,7 @@
* Creates anonymous classes for RoomTypeNames#SHARED_SQLITE_STMT.
*/
class PreparedStatementWriter(val queryWriter: QueryWriter) {
- fun createAnonymous(classWriter: ClassWriter, dbParam : FieldSpec): TypeSpec {
+ fun createAnonymous(classWriter: ClassWriter, dbParam: FieldSpec): TypeSpec {
val scope = CodeGenScope(classWriter)
@Suppress("RemoveSingleExpressionStringTemplate")
return TypeSpec.anonymousClassBuilder("$N", dbParam).apply {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/QueryWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/QueryWriter.kt
index a2c7e62..d99e989 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/QueryWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/QueryWriter.kt
@@ -36,9 +36,9 @@
/**
* Writes the SQL query and arguments for a QueryMethod.
*/
-class QueryWriter constructor(val parameters : List<QueryParameter>,
- val sectionToParamMapping : List<Pair<Section, QueryParameter?>>,
- val query : ParsedQuery) {
+class QueryWriter constructor(val parameters: List<QueryParameter>,
+ val sectionToParamMapping: List<Pair<Section, QueryParameter?>>,
+ val query: ParsedQuery) {
constructor(queryMethod: QueryMethod) : this(queryMethod.parameters,
queryMethod.sectionToParamMapping, queryMethod.query) {
@@ -50,13 +50,16 @@
bindArgs(outRoomSQLiteQueryVar, listSizeVars, scope)
}
- fun prepareQuery(outSqlQueryName: String, scope: CodeGenScope)
- : List<Pair<QueryParameter, String>> {
+ fun prepareQuery(
+ outSqlQueryName: String, scope: CodeGenScope): List<Pair<QueryParameter, String>> {
return createSqlQueryAndArgs(outSqlQueryName, null, scope)
}
- private fun createSqlQueryAndArgs(outSqlQueryName: String, outArgsName: String?,
- scope: CodeGenScope): List<Pair<QueryParameter, String>> {
+ private fun createSqlQueryAndArgs(
+ outSqlQueryName: String,
+ outArgsName: String?,
+ scope: CodeGenScope
+ ): List<Pair<QueryParameter, String>> {
val listSizeVars = arrayListOf<Pair<QueryParameter, String>>()
val varargParams = parameters
.filter { it.queryParamAdapter?.isMultiple ?: false }
@@ -118,8 +121,11 @@
return listSizeVars
}
- fun bindArgs(outArgsName: String, listSizeVars : List<Pair<QueryParameter, String>>,
- scope: CodeGenScope) {
+ fun bindArgs(
+ outArgsName: String,
+ listSizeVars: List<Pair<QueryParameter, String>>,
+ scope: CodeGenScope
+ ) {
if (parameters.isEmpty()) {
return
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/SQLiteOpenHelperWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/SQLiteOpenHelperWriter.kt
index bdc601f..16fcd9c 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/SQLiteOpenHelperWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/SQLiteOpenHelperWriter.kt
@@ -35,8 +35,8 @@
/**
* Create an open helper using SupportSQLiteOpenHelperFactory
*/
-class SQLiteOpenHelperWriter(val database : Database) {
- fun write(outVar : String, configuration : ParameterSpec, scope: CodeGenScope) {
+class SQLiteOpenHelperWriter(val database: Database) {
+ fun write(outVar: String, configuration: ParameterSpec, scope: CodeGenScope) {
scope.builder().apply {
val sqliteConfigVar = scope.getTmpVar("_sqliteConfig")
val callbackVar = scope.getTmpVar("_openCallback")
@@ -61,7 +61,7 @@
}
}
- private fun createOpenCallback(scope: CodeGenScope) : TypeSpec {
+ private fun createOpenCallback(scope: CodeGenScope): TypeSpec {
return TypeSpec.anonymousClassBuilder(L, database.version).apply {
superclass(RoomTypeNames.OPEN_HELPER_DELEGATE)
addMethod(createCreateAllTables())
@@ -106,7 +106,7 @@
}.build()
}
- private fun createCreateAllTables() : MethodSpec {
+ private fun createCreateAllTables(): MethodSpec {
return MethodSpec.methodBuilder("createAllTables").apply {
addModifiers(PUBLIC)
addParameter(SupportDbTypeNames.DB, "_db")
@@ -116,7 +116,7 @@
}.build()
}
- private fun createDropAllTables() : MethodSpec {
+ private fun createDropAllTables(): MethodSpec {
return MethodSpec.methodBuilder("dropAllTables").apply {
addModifiers(PUBLIC)
addParameter(SupportDbTypeNames.DB, "_db")
@@ -140,12 +140,12 @@
}
@VisibleForTesting
- fun createQuery(entity : Entity) : String {
+ fun createQuery(entity: Entity): String {
return entity.createTableQuery
}
@VisibleForTesting
- fun createDropTableQuery(entity: Entity) : String {
+ fun createDropTableQuery(entity: Entity): String {
return "DROP TABLE IF EXISTS `${entity.tableName}`"
}
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/TableInfoValidationWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/TableInfoValidationWriter.kt
index e54f986..3c67475 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/TableInfoValidationWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/TableInfoValidationWriter.kt
@@ -33,8 +33,8 @@
import java.util.HashMap
import java.util.HashSet
-class TableInfoValidationWriter(val entity : Entity) {
- fun write(dbParam : ParameterSpec, scope : CodeGenScope) {
+class TableInfoValidationWriter(val entity: Entity) {
+ fun write(dbParam: ParameterSpec, scope: CodeGenScope) {
val suffix = entity.tableName.stripNonJava().capitalize()
val expectedInfoVar = scope.getTmpVar("_info$suffix")
scope.builder().apply {
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/parser/SqlParserTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/parser/SqlParserTest.kt
index 6d3e194..1d31354 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/parser/SqlParserTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/parser/SqlParserTest.kt
@@ -110,7 +110,7 @@
}
@Test
- fun indexedVariablesError() {
+ fun indexedVariablesError() {
assertErrors("select * from users where name like ?",
ParserErrors.ANONYMOUS_BIND_ARGUMENT)
assertErrors("select * from users where name like ? or last_name like ?",
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/BaseDaoTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/BaseDaoTest.kt
index ae648f7..19430af 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/BaseDaoTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/BaseDaoTest.kt
@@ -140,7 +140,7 @@
}
}
- fun baseDao(code : String, handler : (Dao) -> Unit) {
+ fun baseDao(code: String, handler: (Dao) -> Unit) {
val baseClass = """
package foo.bar;
import android.arch.persistence.room.*;
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/BaseEntityParserTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/BaseEntityParserTest.kt
index 7893200..bd09a11 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/BaseEntityParserTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/BaseEntityParserTest.kt
@@ -25,7 +25,6 @@
import com.google.common.truth.Truth
import com.google.testing.compile.CompileTester
import com.google.testing.compile.JavaFileObjects
-import com.google.testing.compile.JavaSourceSubjectFactory
import com.google.testing.compile.JavaSourcesSubjectFactory
import javax.tools.JavaFileObject
@@ -42,10 +41,10 @@
}
fun singleEntity(input: String, attributes: Map<String, String> = mapOf(),
- baseClass : String = "",
- jfos : List<JavaFileObject> = emptyList(),
+ baseClass: String = "",
+ jfos: List<JavaFileObject> = emptyList(),
handler: (Entity, TestInvocation) -> Unit): CompileTester {
- val attributesReplacement : String
+ val attributesReplacement: String
if (attributes.isEmpty()) {
attributesReplacement = ""
} else {
@@ -53,7 +52,7 @@
attributes.entries.map { "${it.key} = ${it.value}" }.joinToString(",") +
")".trimIndent()
}
- val baseClassReplacement : String
+ val baseClassReplacement: String
if (baseClass == "") {
baseClassReplacement = ""
} else {
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/CustomConverterProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/CustomConverterProcessorTest.kt
index 6b8dbaf..067773a 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/CustomConverterProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/CustomConverterProcessorTest.kt
@@ -60,8 +60,7 @@
@Test
fun validCase() {
- singleClass(createConverter(TypeName.SHORT.box(), TypeName.CHAR.box()))
- { converter, _ ->
+ singleClass(createConverter(TypeName.SHORT.box(), TypeName.CHAR.box())) { converter, _ ->
assertThat(converter?.fromTypeName, `is`(TypeName.SHORT.box()))
assertThat(converter?.toTypeName, `is`(TypeName.CHAR.box()))
}.compilesWithoutError()
@@ -222,21 +221,24 @@
@Test
fun checkDuplicates() {
- singleClass(createConverter(TypeName.SHORT.box(), TypeName.CHAR.box(), duplicate = true))
- { converter, _ ->
+ singleClass(
+ createConverter(TypeName.SHORT.box(), TypeName.CHAR.box(), duplicate = true)
+ ) { converter, _ ->
assertThat(converter?.fromTypeName, `is`(TypeName.SHORT.box()))
assertThat(converter?.toTypeName, `is`(TypeName.CHAR.box()))
}.failsToCompile().withErrorContaining("Multiple methods define the same conversion")
}
- private fun createConverter(from: TypeName, to: TypeName,
- typeVariables: List<TypeVariableName> = emptyList(),
- duplicate : Boolean = false)
- : JavaFileObject {
+ private fun createConverter(
+ from: TypeName,
+ to: TypeName,
+ typeVariables: List<TypeVariableName> = emptyList(),
+ duplicate: Boolean = false
+ ): JavaFileObject {
val code = TypeSpec.classBuilder(CONVERTER).apply {
addTypeVariables(typeVariables)
addModifiers(Modifier.PUBLIC)
- fun buildMethod(name : String) = MethodSpec.methodBuilder(name).apply {
+ fun buildMethod(name: String) = MethodSpec.methodBuilder(name).apply {
addAnnotation(TypeConverter::class.java)
addModifiers(Modifier.PUBLIC)
returns(to)
@@ -256,9 +258,10 @@
"package ${CONVERTER.packageName()};\n$code")
}
- private fun singleClass(vararg jfo: JavaFileObject,
- handler: (CustomTypeConverter?, TestInvocation) -> Unit)
- : CompileTester {
+ private fun singleClass(
+ vararg jfo: JavaFileObject,
+ handler: (CustomTypeConverter?, TestInvocation) -> Unit
+ ): CompileTester {
return simpleRun(*((jfo.toList() + CONTAINER).toTypedArray())) { invocation ->
val processed = CustomConverterProcessor.findConverters(invocation.context,
invocation.processingEnv.elementUtils.getTypeElement("foo.bar.Container"))
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/DaoProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/DaoProcessorTest.kt
index 55f335d..9207cf3 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/DaoProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/DaoProcessorTest.kt
@@ -36,7 +36,7 @@
import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
-class DaoProcessorTest(val enableVerification : Boolean) {
+class DaoProcessorTest(val enableVerification: Boolean) {
companion object {
const val DAO_PREFIX = """
package foo.bar;
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/DatabaseProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/DatabaseProcessorTest.kt
index 40e9a96..d192c8f 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/DatabaseProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/DatabaseProcessorTest.kt
@@ -201,8 +201,7 @@
@Query("SELECT * FROM nonExistentTable")
public java.util.List<Book> loadAllBooks();
}
- """)){ _, _ ->
-
+ """)) { _, _ ->
}.failsToCompile().withErrorContaining("no such table: nonExistentTable")
}
@@ -247,8 +246,7 @@
@Query("SELECT nonExistingField FROM Book")
public java.util.List<Book> loadAllBooks();
}
- """)){ _, _ ->
-
+ """)) { _, _ ->
}.compilesWithoutError()
}
@@ -294,7 +292,7 @@
abstract UserDao userDao();
abstract UserDao userDao2();
}
- """, USER, USER_DAO){ _, _ -> }
+ """, USER, USER_DAO) { _, _ -> }
.failsToCompile()
.withErrorContaining(ProcessorErrors.DAO_METHOD_CONFLICTS_WITH_OTHERS)
.and()
@@ -312,7 +310,7 @@
public abstract class MyDb extends RoomDatabase {
abstract UserDao userDao();
}
- """, USER, USER_DAO) {db, invocation ->
+ """, USER, USER_DAO) { db, invocation ->
assertThat(DatabaseProcessor(invocation.context, db.element)
.context.logger.suppressedWarnings, `is`(setOf(Warning.CURSOR_MISMATCH)))
}.compilesWithoutError()
@@ -347,8 +345,7 @@
@Database(entities = {Entity1.class, Entity2.class}, version = 42)
public abstract class MyDb extends RoomDatabase {
}
- """, entity1, entity2){ _, _ ->
-
+ """, entity1, entity2) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.duplicateIndexInDatabase("index_name",
listOf("foo.bar.Entity1 > index_name", "foo.bar.Entity2 > index_name"))
@@ -374,8 +371,7 @@
@Database(entities = {Entity1.class}, version = 42)
public abstract class MyDb extends RoomDatabase {
}
- """, entity1, COMMON.USER){ _, _ ->
-
+ """, entity1, COMMON.USER) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.foreignKeyMissingParentEntityInDatabase("User", "foo.bar.Entity1")
)
@@ -400,8 +396,7 @@
@Database(entities = {Entity1.class, User.class}, version = 42)
public abstract class MyDb extends RoomDatabase {
}
- """, entity1, COMMON.USER){ _, _ ->
-
+ """, entity1, COMMON.USER) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.foreignKeyMissingIndexInParent(
parentEntity = COMMON.USER_TYPE_NAME.toString(),
@@ -444,8 +439,7 @@
@Database(entities = {Entity1.class, Entity2.class}, version = 42)
public abstract class MyDb extends RoomDatabase {
}
- """, entity1, entity2){ _, _ ->
-
+ """, entity1, entity2) { _, _ ->
}.compilesWithoutError()
}
@@ -481,7 +475,7 @@
@Database(entities = {Entity1.class, Entity2.class}, version = 42)
public abstract class MyDb extends RoomDatabase {
}
- """, entity1, entity2){ _, _ ->
+ """, entity1, entity2) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.foreignKeyParentColumnDoesNotExist("foo.bar.Entity2",
"anotherName2", listOf("uid", "anotherName"))
@@ -521,7 +515,7 @@
@Database(entities = {Entity1.class, Entity2.class}, version = 42)
public abstract class MyDb extends RoomDatabase {
}
- """, entity1, entity2){ _, _ ->
+ """, entity1, entity2) { _, _ ->
}.compilesWithoutError()
}
@@ -532,7 +526,7 @@
public abstract class MyDb extends RoomDatabase {
abstract BookDao bookDao();
}
- """, USER, USER_DAO, BOOK, BOOK_DAO){ _, _ ->
+ """, USER, USER_DAO, BOOK, BOOK_DAO) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.shortcutEntityIsNotInDatabase(
database = "foo.bar.MyDb",
@@ -566,7 +560,7 @@
public static java.util.Date foo(Long input) {return null;}
}
}
- """, USER, USER_DAO){ db, _ ->
+ """, USER, USER_DAO) { db, _ ->
val userDao = db.daoMethods.first().dao
val insertionMethod = userDao.insertionMethods.find { it.name == "insert" }
assertThat(insertionMethod, notNullValue())
@@ -597,7 +591,7 @@
public abstract class MyDb extends RoomDatabase {
public abstract UserDao userDao();
}
- """, USER, USER_DAO){ db, _ ->
+ """, USER, USER_DAO) { db, _ ->
val userDao = db.daoMethods.first().dao
val loadOne = userDao.queryMethods.find { it.name == "loadOnePojo" }
assertThat(loadOne, notNullValue())
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/DeletionMethodProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/DeletionMethodProcessorTest.kt
index 864ea9b..40546e8 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/DeletionMethodProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/DeletionMethodProcessorTest.kt
@@ -36,5 +36,4 @@
executableElement: ExecutableElement): DeletionMethod {
return DeletionMethodProcessor(baseContext, containing, executableElement).process()
}
-
}
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityNameMatchingVariationsTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityNameMatchingVariationsTest.kt
index e6a2ff3..00dde74 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityNameMatchingVariationsTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityNameMatchingVariationsTest.kt
@@ -38,7 +38,7 @@
companion object {
@JvmStatic
@Parameterized.Parameters(name = "{0}")
- fun params() : List<Triple<String, String, String>> {
+ fun params(): List<Triple<String, String, String>> {
val result = arrayListOf<Triple<String, String, String>>()
arrayListOf("x", "_x", "mX").forEach { field ->
arrayListOf("getX", "x").forEach { getter ->
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityProcessorTest.kt
index 631f511..95c70ca 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityProcessorTest.kt
@@ -277,7 +277,6 @@
@PrimaryKey
public java.util.Date myDate;
""") { _, _ ->
-
}.failsToCompile().withErrorContaining(ProcessorErrors.CANNOT_FIND_COLUMN_TYPE_ADAPTER)
}
@@ -338,7 +337,7 @@
}.compilesWithoutError()
}
- private fun fieldsByName(entity : Pojo, vararg fieldNames : String) : List<Field> {
+ private fun fieldsByName(entity: Pojo, vararg fieldNames: String): List<Field> {
return fieldNames
.map { name -> entity.fields.find { it.name == name } }
.filterNotNull()
@@ -438,9 +437,10 @@
"""
, annotation) { entity, _ ->
assertThat(entity.indices, `is`(
- listOf(Index(name = "index_MyEntity_foo_id",
+ listOf(Index(
+ name = "index_MyEntity_foo_id",
unique = true,
- fields = fieldsByName(entity, "foo", "id")))
+ fields = fieldsByName(entity, "foo", "id")))
))
}.compilesWithoutError()
}
@@ -663,7 +663,6 @@
unique = false,
fields = fieldsByName(entity, "name"))))
}.compilesWithoutError().withWarningCount(0)
-
}
@Test
@@ -880,7 +879,6 @@
baseClass = "foo.bar.Base",
jfos = listOf(parent)) { entity, _ ->
assertThat(entity.primaryKey.fields.firstOrNull()?.name, `is`("baseId"))
-
}.compilesWithoutError().withWarningCount(0)
}
@@ -1033,7 +1031,7 @@
}
@Test
- fun primaryKey_embedded(){
+ fun primaryKey_embedded() {
singleEntity(
"""
public int id;
@@ -1054,7 +1052,7 @@
}
@Test
- fun primaryKey_embeddedInherited(){
+ fun primaryKey_embeddedInherited() {
val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
"""
package foo.bar;
@@ -1231,7 +1229,7 @@
}
@Test
- fun primaryKey_nullableEmbedded(){
+ fun primaryKey_nullableEmbedded() {
singleEntity(
"""
public int id;
@@ -1249,7 +1247,7 @@
}
@Test
- fun primaryKey_nullableEmbeddedObject(){
+ fun primaryKey_nullableEmbeddedObject() {
singleEntity(
"""
public int id;
@@ -1270,7 +1268,7 @@
}
@Test
- fun primaryKey_nullableEmbeddedObject_multipleParents(){
+ fun primaryKey_nullableEmbeddedObject_multipleParents() {
singleEntity(
"""
public int id;
@@ -1297,7 +1295,7 @@
}
@Test
- fun primaryKey_nullableEmbeddedInherited(){
+ fun primaryKey_nullableEmbeddedInherited() {
val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
"""
package foo.bar;
@@ -1495,7 +1493,7 @@
String name;
""",
attributes = annotation, jfos = listOf(COMMON.USER)
- ){ _, _ ->
+ ) { _, _ ->
}.failsToCompile().withErrorContaining(ProcessorErrors.INVALID_FOREIGN_KEY_ACTION)
}
@@ -1515,7 +1513,7 @@
String name;
""",
attributes = annotation, jfos = listOf(COMMON.USER)
- ){ _, _ ->
+ ) { _, _ ->
}.failsToCompile().withErrorContaining("cannot find symbol")
}
@@ -1535,7 +1533,7 @@
String name;
""",
attributes = annotation, jfos = listOf(COMMON.NOT_AN_ENTITY)
- ){ _, _ ->
+ ) { _, _ ->
}.failsToCompile().withErrorContaining(ProcessorErrors.foreignKeyNotAnEntity(
COMMON.NOT_AN_ENTITY_TYPE_NAME.toString()))
}
@@ -1556,7 +1554,7 @@
String name;
""",
attributes = annotation, jfos = listOf(COMMON.USER)
- ){ _, _ ->
+ ) { _, _ ->
}.failsToCompile().withErrorContaining(ProcessorErrors.foreignKeyChildColumnDoesNotExist(
"namex", listOf("id", "name")))
}
@@ -1577,7 +1575,7 @@
String name;
""",
attributes = annotation, jfos = listOf(COMMON.USER)
- ){ _, _ ->
+ ) { _, _ ->
}.failsToCompile().withErrorContaining(ProcessorErrors.foreignKeyColumnNumberMismatch(
listOf("name", "id"), listOf("lastName")))
}
@@ -1598,7 +1596,7 @@
String name;
""",
attributes = annotation, jfos = listOf(COMMON.USER)
- ){ _, _ ->
+ ) { _, _ ->
}.failsToCompile().withErrorContaining(ProcessorErrors.FOREIGN_KEY_EMPTY_CHILD_COLUMN_LIST)
}
@@ -1618,7 +1616,7 @@
String name;
""",
attributes = annotation, jfos = listOf(COMMON.USER)
- ){ _, _ ->
+ ) { _, _ ->
}.failsToCompile().withErrorContaining(ProcessorErrors.FOREIGN_KEY_EMPTY_PARENT_COLUMN_LIST)
}
@@ -1641,7 +1639,7 @@
String name;
""",
attributes = annotation, jfos = listOf(COMMON.USER)
- ){ entity, _ ->
+ ) { entity, _ ->
assertThat(entity.foreignKeys.size, `is`(1))
val fKey = entity.foreignKeys.first()
assertThat(fKey.parentTable, `is`("User"))
@@ -1748,7 +1746,7 @@
String name;
""",
attributes = annotation, jfos = listOf(COMMON.USER)
- ){ entity, _ ->
+ ) { entity, _ ->
assertThat(entity.indices, `is`(emptyList()))
}.compilesWithoutError().withWarningContaining(
ProcessorErrors.foreignKeyMissingIndexInChildColumn("name"))
@@ -1771,7 +1769,7 @@
String lName;
""",
attributes = annotation, jfos = listOf(COMMON.USER)
- ){ entity, _ ->
+ ) { entity, _ ->
assertThat(entity.indices, `is`(emptyList()))
}.compilesWithoutError().withWarningContaining(
ProcessorErrors.foreignKeyMissingIndexInChildColumns(listOf("lName", "name")))
@@ -1796,7 +1794,7 @@
String name;
""",
attributes = annotation, jfos = listOf(COMMON.USER)
- ){ entity, _ ->
+ ) { entity, _ ->
assertThat(entity.indices, `is`(emptyList()))
}.compilesWithoutWarnings()
}
@@ -1807,7 +1805,7 @@
"""
@Embedded
MyEntity myEntity;
- """){ _, _ ->
+ """) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.RECURSIVE_REFERENCE_DETECTED.format(
"foo.bar.MyEntity -> foo.bar.MyEntity"))
@@ -1826,7 +1824,7 @@
@Relation(parentColumn = "pojoId", entityColumn = "entityId")
MyEntity myEntity;
}
- """){ _, _ ->
+ """) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.RECURSIVE_REFERENCE_DETECTED.format(
"foo.bar.MyEntity -> foo.bar.MyEntity.A -> foo.bar.MyEntity"))
@@ -1843,7 +1841,7 @@
@Embedded
MyEntity myEntity;
}
- """){ _, _ ->
+ """) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.RECURSIVE_REFERENCE_DETECTED.format(
"foo.bar.MyEntity -> foo.bar.MyEntity.A -> foo.bar.MyEntity"))
@@ -1875,7 +1873,7 @@
String name;
""",
attributes = annotation, jfos = listOf(COMMON.USER)
- ){ _, _ ->
+ ) { _, _ ->
}.compilesWithoutError()
}
@@ -1889,7 +1887,7 @@
String name;
""",
attributes = annotation, jfos = listOf(COMMON.USER)
- ){ _, _ ->
+ ) { _, _ ->
}.failsToCompile().withErrorContaining(ProcessorErrors.INVALID_TABLE_NAME)
}
@@ -1903,7 +1901,7 @@
String name;
""",
jfos = listOf(COMMON.USER)
- ){ _, _ ->
+ ) { _, _ ->
}.failsToCompile().withErrorContaining(ProcessorErrors.INVALID_COLUMN_NAME)
}
}
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/InsertionMethodProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/InsertionMethodProcessorTest.kt
index ffb07ed..51f81db 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/InsertionMethodProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/InsertionMethodProcessorTest.kt
@@ -55,8 +55,8 @@
abstract class MyClass {
"""
const val DAO_SUFFIX = "}"
- val USER_TYPE_NAME : TypeName = COMMON.USER_TYPE_NAME
- val BOOK_TYPE_NAME : TypeName = ClassName.get("foo.bar", "Book")
+ val USER_TYPE_NAME: TypeName = COMMON.USER_TYPE_NAME
+ val BOOK_TYPE_NAME: TypeName = ClassName.get("foo.bar", "Book")
}
@Test
@@ -387,9 +387,10 @@
}
}
- fun singleInsertMethod(vararg input: String,
- handler: (InsertionMethod, TestInvocation) -> Unit):
- CompileTester {
+ fun singleInsertMethod(
+ vararg input: String,
+ handler: (InsertionMethod, TestInvocation) -> Unit
+ ): CompileTester {
return assertAbout(JavaSourcesSubjectFactory.javaSources())
.that(listOf(JavaFileObjects.forSourceString("foo.bar.MyClass",
DAO_PREFIX + input.joinToString("\n") + DAO_SUFFIX
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt
index 6fdb300..bf34b4c 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt
@@ -523,7 +523,7 @@
affinity = SQLTypeAffinity.TEXT,
columnName = "foo",
parent = null,
- indexed = false
+ indexed = false
)
val fakeEmbedded = EmbeddedField(fakeField, "", null)
@@ -562,7 +562,7 @@
singleRun(pojoCode) { pojo ->
val param = pojo.constructor?.params?.first()
assertThat(param, instanceOf(Constructor.FieldParam::class.java))
- assertThat((param as Constructor.FieldParam).field.name, `is`("mName"))
+ assertThat((param as Constructor.FieldParam).field.name, `is`("mName"))
assertThat(pojo.fields.find { it.name == "mName" }?.setter?.callType,
`is`(CallType.CONSTRUCTOR))
}.compilesWithoutError()
@@ -579,7 +579,7 @@
singleRun(pojoCode) { pojo ->
val param = pojo.constructor?.params?.first()
assertThat(param, instanceOf(Constructor.FieldParam::class.java))
- assertThat((param as Constructor.FieldParam).field.name, `is`("mName"))
+ assertThat((param as Constructor.FieldParam).field.name, `is`("mName"))
assertThat(pojo.fields.find { it.name == "mName" }?.setter?.callType,
`is`(CallType.CONSTRUCTOR))
}.compilesWithoutError()
@@ -714,7 +714,7 @@
"""
@Embedded
MyPojo myPojo;
- """){ _, _ ->
+ """) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.RECURSIVE_REFERENCE_DETECTED.format(
"foo.bar.MyPojo -> foo.bar.MyPojo"))
@@ -736,7 +736,7 @@
@Embedded
MyPojo myPojo;
}
- """){ _, _ ->
+ """) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.RECURSIVE_REFERENCE_DETECTED.format(
"foo.bar.MyPojo -> foo.bar.MyPojo.MyEntity -> foo.bar.MyPojo"))
@@ -754,7 +754,7 @@
@Embedded
MyPojo myPojo;
}
- """){ _, _ ->
+ """) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.RECURSIVE_REFERENCE_DETECTED.format(
"foo.bar.MyPojo -> foo.bar.MyPojo.A -> foo.bar.MyPojo"))
@@ -770,7 +770,7 @@
@Embedded
MyPojo myPojo;
}
- """){ _, _ ->
+ """) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.RECURSIVE_REFERENCE_DETECTED.format(
"foo.bar.MyPojo -> foo.bar.MyPojo.A -> foo.bar.MyPojo"))
@@ -790,7 +790,7 @@
@Embedded
MyPojo myPojo;
}
- """){ _, _ ->
+ """) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.RECURSIVE_REFERENCE_DETECTED.format(
"foo.bar.MyPojo -> foo.bar.MyPojo.A -> foo.bar.MyPojo.B -> foo.bar.MyPojo"))
@@ -810,7 +810,7 @@
@Embedded
A a;
}
- """){ _, _ ->
+ """) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.RECURSIVE_REFERENCE_DETECTED.format(
"foo.bar.MyPojo.A -> foo.bar.MyPojo.B -> foo.bar.MyPojo.A"))
@@ -836,7 +836,7 @@
@Embedded
MyPojo myPojo;
}
- """){ _, _ ->
+ """) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.RECURSIVE_REFERENCE_DETECTED.format(
"foo.bar.MyPojo -> foo.bar.MyPojo.C -> foo.bar.MyPojo"))
@@ -862,20 +862,20 @@
}
static class C {
}
- """){ _, _ ->
+ """) { _, _ ->
}.failsToCompile().withErrorContaining(
ProcessorErrors.RECURSIVE_REFERENCE_DETECTED.format(
"foo.bar.MyPojo -> foo.bar.MyPojo.A -> foo.bar.MyPojo"))
}
- fun singleRun(code: String, vararg jfos:JavaFileObject, handler: (Pojo) -> Unit)
- : CompileTester {
+ fun singleRun(
+ code: String, vararg jfos: JavaFileObject, handler: (Pojo) -> Unit): CompileTester {
return singleRun(code, *jfos) { pojo, _ ->
handler(pojo)
}
}
- fun singleRun(code: String, vararg jfos:JavaFileObject,
+ fun singleRun(code: String, vararg jfos: JavaFileObject,
handler: (Pojo, TestInvocation) -> Unit): CompileTester {
val pojoJFO = """
$HEADER
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/ShortcutMethodProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/ShortcutMethodProcessorTest.kt
index c4ef416..7a332ea 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/ShortcutMethodProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/ShortcutMethodProcessorTest.kt
@@ -55,7 +55,7 @@
"""
const val DAO_SUFFIX = "}"
val USER_TYPE_NAME: TypeName = COMMON.USER_TYPE_NAME
- val BOOK_TYPE_NAME : TypeName = ClassName.get("foo.bar", "Book")
+ val BOOK_TYPE_NAME: TypeName = ClassName.get("foo.bar", "Book")
}
@Test
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/CustomTypeConverterResolutionTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/CustomTypeConverterResolutionTest.kt
index 545556e..d9b4997 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/CustomTypeConverterResolutionTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/CustomTypeConverterResolutionTest.kt
@@ -49,7 +49,7 @@
@RunWith(JUnit4::class)
class CustomTypeConverterResolutionTest {
- fun TypeSpec.toJFO() : JavaFileObject {
+ fun TypeSpec.toJFO(): JavaFileObject {
return JavaFileObjects.forSourceString("foo.bar.${this.name}",
"package foo.bar;\n" + toString())
}
@@ -168,15 +168,15 @@
run(entity.toJFO(), dao.toJFO(), database.toJFO()).compilesWithoutError()
}
- fun run(vararg jfos : JavaFileObject): CompileTester {
+ fun run(vararg jfos: JavaFileObject): CompileTester {
return Truth.assertAbout(JavaSourcesSubjectFactory.javaSources())
.that(jfos.toList() + CUSTOM_TYPE_JFO + CUSTOM_TYPE_CONVERTER_JFO)
.processedWith(RoomProcessor())
}
- private fun createEntity(hasCustomField : Boolean = false,
- hasConverters : Boolean = false,
- hasConverterOnField : Boolean = false) : TypeSpec {
+ private fun createEntity(hasCustomField: Boolean = false,
+ hasConverters: Boolean = false,
+ hasConverterOnField: Boolean = false): TypeSpec {
if (hasConverterOnField && hasConverters) {
throw IllegalArgumentException("cannot have both converters")
}
@@ -199,8 +199,8 @@
}.build()
}
- private fun createDatabase(hasConverters : Boolean = false,
- hasDao : Boolean = false) : TypeSpec {
+ private fun createDatabase(hasConverters: Boolean = false,
+ hasDao: Boolean = false): TypeSpec {
return TypeSpec.classBuilder(DB).apply {
addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
superclass(RoomTypeNames.ROOM_DB)
@@ -225,11 +225,11 @@
}.build()
}
- private fun createDao(hasConverters : Boolean = false,
- hasQueryReturningEntity : Boolean = false,
- hasQueryWithCustomParam : Boolean = false,
- hasMethodConverters : Boolean = false,
- hasParameterConverters : Boolean = false) : TypeSpec {
+ private fun createDao(hasConverters: Boolean = false,
+ hasQueryReturningEntity: Boolean = false,
+ hasQueryWithCustomParam: Boolean = false,
+ hasMethodConverters: Boolean = false,
+ hasParameterConverters: Boolean = false): TypeSpec {
val annotationCount = listOf(hasMethodConverters, hasConverters, hasParameterConverters)
.map { if (it) 1 else 0 }.sum()
if (annotationCount > 1) {
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/TypeAdapterStoreTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/TypeAdapterStoreTest.kt
index 78284b4..0148d2a 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/TypeAdapterStoreTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/solver/TypeAdapterStoreTest.kt
@@ -182,7 +182,6 @@
invocation.context.COMMON_TYPES.STRING)
assertThat(converter, notNullValue())
assertThat(store.reverse(converter!!), `is`(binders[1]))
-
}.compilesWithoutError()
}
@@ -368,7 +367,6 @@
addStatement("$L = $T.toBoolean($L)", outputVarName, from, inputVarName)
}
}
-
},
object : TypeConverter(tBoolean, tPoint) {
override fun convert(inputVarName: String, outputVarName: String,
@@ -393,7 +391,6 @@
addStatement("// convert Date to Long")
}
}
-
},
object : TypeConverter(tLong, tDate) {
override fun convert(inputVarName: String, outputVarName: String,
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/TestInvocation.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/TestInvocation.kt
index b97628e..86b6e01 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/TestInvocation.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/TestInvocation.kt
@@ -26,7 +26,7 @@
val roundEnv: RoundEnvironment) {
val context = Context(processingEnv)
- fun typeElement(qName: String) : TypeElement {
+ fun typeElement(qName: String): TypeElement {
return processingEnv.elementUtils.getTypeElement(qName)
}
}
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/TestProcessor.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/TestProcessor.kt
index 16c0048..6dfa2e4 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/TestProcessor.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/TestProcessor.kt
@@ -27,8 +27,8 @@
class TestProcessor(val handlers: List<(TestInvocation) -> Boolean>,
val annotations: MutableSet<String>) : AbstractProcessor() {
var count = 0
- override fun process(annotations: MutableSet<out TypeElement>, roundEnv: RoundEnvironment)
- : Boolean {
+ override fun process(
+ annotations: MutableSet<out TypeElement>, roundEnv: RoundEnvironment): Boolean {
return handlers.getOrNull(count++)?.invoke(
TestInvocation(processingEnv, annotations, roundEnv)) ?: true
}
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/test_util.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/test_util.kt
index 2616627..4d100b3 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/test_util.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/testing/test_util.kt
@@ -95,7 +95,7 @@
return CodeGenScope(Mockito.mock(ClassWriter::class.java))
}
-fun simpleRun(vararg jfos : JavaFileObject, f: (TestInvocation) -> Unit): CompileTester {
+fun simpleRun(vararg jfos: JavaFileObject, f: (TestInvocation) -> Unit): CompileTester {
return Truth.assertAbout(JavaSourcesSubjectFactory.javaSources())
.that(jfos.toList() + JavaFileObjects.forSourceString("foo.bar.MyClass",
"""
@@ -115,12 +115,12 @@
.build())
}
-fun loadJavaCode(fileName : String, qName : String) : JavaFileObject {
+fun loadJavaCode(fileName: String, qName: String): JavaFileObject {
val contents = File("src/test/data/$fileName").readText(Charsets.UTF_8)
return JavaFileObjects.forSourceString(qName, contents)
}
-fun createVerifierFromEntities(invocation: TestInvocation) : DatabaseVerifier {
+fun createVerifierFromEntities(invocation: TestInvocation): DatabaseVerifier {
val entities = invocation.roundEnv.getElementsAnnotatedWith(Entity::class.java).map {
EntityProcessor(invocation.context, MoreElements.asType(it)).process()
}
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/verifier/DatabaseVerifierTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/verifier/DatabaseVerifierTest.kt
index ef5c4ef..e144e2b 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/verifier/DatabaseVerifierTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/verifier/DatabaseVerifierTest.kt
@@ -235,6 +235,5 @@
.filter { it.second > 0 }
.sortedBy { it.second }
.map { it.first }
-
}
}
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/vo/IndexTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/vo/IndexTest.kt
index c1ac029..04e43f8 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/vo/IndexTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/vo/IndexTest.kt
@@ -42,7 +42,7 @@
))
}
- private fun mockField(columnName : String): Field {
+ private fun mockField(columnName: String): Field {
val (element, type) = mockElementAndType()
return Field(
element = element,
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/DaoWriterTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/DaoWriterTest.kt
index 6d2bda3..96d1e3a 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/DaoWriterTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/DaoWriterTest.kt
@@ -72,7 +72,7 @@
)
}
- fun singleDao(vararg jfo : JavaFileObject): CompileTester {
+ fun singleDao(vararg jfo: JavaFileObject): CompileTester {
return Truth.assertAbout(JavaSourcesSubjectFactory.javaSources())
.that(jfo.toList() + COMMON.USER + COMMON.MULTI_PKEY_ENTITY + COMMON.BOOK +
COMMON.LIVE_DATA + COMMON.COMPUTABLE_LIVE_DATA)
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/DatabaseWriterTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/DatabaseWriterTest.kt
index 9a3252f..824d2d0 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/DatabaseWriterTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/DatabaseWriterTest.kt
@@ -42,9 +42,9 @@
)
}
- private fun singleDb(vararg jfo : JavaFileObject): CompileTester {
+ private fun singleDb(vararg jfo: JavaFileObject): CompileTester {
return Truth.assertAbout(JavaSourcesSubjectFactory.javaSources())
- .that(jfo.toList() + COMMON.USER + COMMON.LIVE_DATA + COMMON.COMPUTABLE_LIVE_DATA)
+ .that(jfo.toList() + COMMON.USER + COMMON.LIVE_DATA + COMMON.COMPUTABLE_LIVE_DATA)
.processedWith(RoomProcessor())
}
}
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/EntityCursorConverterWriterTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/EntityCursorConverterWriterTest.kt
index 31a3f18..a01033e 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/EntityCursorConverterWriterTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/EntityCursorConverterWriterTest.kt
@@ -78,20 +78,20 @@
""".trimIndent())
}
- fun generateAndMatch(input: String, output : String,
+ fun generateAndMatch(input: String, output: String,
attributes: Map<String, String> = mapOf()) {
generate(input, attributes)
.compilesWithoutError()
.and()
.generatesSources(JavaFileObjects.forSourceString(
"foo.bar.MyEntity_CursorConverter",
- listOf(OUT_PREFIX,output,OUT_SUFFIX).joinToString("\n")))
+ listOf(OUT_PREFIX, output, OUT_SUFFIX).joinToString("\n")))
}
- fun generate(input: String, attributes: Map<String, String> = mapOf()) : CompileTester {
+ fun generate(input: String, attributes: Map<String, String> = mapOf()): CompileTester {
return singleEntity(input, attributes) { entity, invocation ->
- val className = ClassName.get("foo.bar","MyContainerClass")
- val writer = object : ClassWriter(className){
+ val className = ClassName.get("foo.bar", "MyContainerClass")
+ val writer = object : ClassWriter(className) {
override fun createTypeSpecBuilder(): TypeSpec.Builder {
getOrCreateMethod(EntityCursorConverterWriter(entity))
return TypeSpec.classBuilder(className).apply {
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/SQLiteOpenHelperWriterTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/SQLiteOpenHelperWriterTest.kt
index 2e86a00..4d68231 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/SQLiteOpenHelperWriterTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/writer/SQLiteOpenHelperWriterTest.kt
@@ -132,7 +132,7 @@
fun singleEntity(input: String, attributes: Map<String, String> = mapOf(),
handler: (Database, TestInvocation) -> Unit): CompileTester {
- val attributesReplacement : String
+ val attributesReplacement: String
if (attributes.isEmpty()) {
attributesReplacement = ""
} else {
diff --git a/room/integration-tests/kotlintestapp/build.gradle b/room/integration-tests/kotlintestapp/build.gradle
index f1f5139..f444018 100644
--- a/room/integration-tests/kotlintestapp/build.gradle
+++ b/room/integration-tests/kotlintestapp/build.gradle
@@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+import static android.support.dependencies.DependenciesKt.*
+
apply plugin: 'com.android.application'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android'
-project.ext.noDocs = true
-
android {
compileSdkVersion tools.current_sdk
buildToolsVersion tools.build_tools_version
@@ -57,21 +58,21 @@
}
dependencies {
- implementation project(":room:common")
- implementation project(":persistence:db")
- implementation project(":persistence:db-framework")
- implementation project(':room:runtime')
- implementation project(':arch:runtime')
+ implementation(project(":room:common"))
+ implementation(project(":persistence:db"))
+ implementation(project(":persistence:db-framework"))
+ implementation(project(":room:runtime"))
+ implementation(project(":arch:runtime"))
implementation libs.support.app_compat, libs.support_exclude_config
kapt project(":room:compiler")
kaptAndroidTest project(":room:compiler")
- androidTestImplementation(libs.test_runner) {
+ androidTestImplementation(TEST_RUNNER) {
exclude module: 'support-annotations'
exclude module: 'hamcrest-core'
}
- androidTestImplementation(libs.espresso_core, {
+ androidTestImplementation(ESPRESSO_CORE, {
exclude group: 'com.android.support', module: 'support-annotations'
exclude module: "hamcrest-core"
})
@@ -82,12 +83,10 @@
androidTestImplementation project(':room:testing')
androidTestImplementation project(':room:rxjava2')
androidTestImplementation project(':arch:core-testing')
- androidTestImplementation libs.rx_java
- testImplementation libs.mockito_core
+ androidTestImplementation(RX_JAVA)
+ testImplementation(MOCKITO_CORE)
}
-createAndroidCheckstyle(project)
-createKotlinCheckstyle(project)
tasks['check'].dependsOn(tasks['connectedCheck'])
uploadArchives.enabled = false
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/DerivedDao.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/DerivedDao.kt
index 01e8167..5245a01 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/DerivedDao.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/dao/DerivedDao.kt
@@ -20,7 +20,6 @@
import android.arch.persistence.room.Query
import android.arch.persistence.room.integration.kotlintestapp.vo.Author
-
@Dao
interface DerivedDao : BaseDao<Author> {
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt
index 4265e19..b684923 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt
@@ -33,7 +33,6 @@
import java.io.FileNotFoundException
import java.io.IOException
-
class MigrationKotlinTest {
@get:Rule
@@ -58,7 +57,6 @@
} catch (exception: FileNotFoundException) {
assertThat<String>(exception.message, containsString("Cannot find"))
}
-
}
@Test
@@ -244,7 +242,6 @@
assertThat<String>(throwable!!.message, containsString("Migration failed"))
}
-
internal val MIGRATION_1_2: Migration = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE IF NOT EXISTS `Entity2` (`id` INTEGER NOT NULL,"
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/BookAuthor.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/BookAuthor.kt
index 4fc661c..5a21f40 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/BookAuthor.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/BookAuthor.kt
@@ -19,7 +19,6 @@
import android.arch.persistence.room.Entity
import android.arch.persistence.room.ForeignKey
-
@Entity(foreignKeys = arrayOf(
ForeignKey(entity = Book::class,
parentColumns = arrayOf("bookId"),
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/BookWithPublisher.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/BookWithPublisher.kt
index 6516c23..418a0e2 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/BookWithPublisher.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/BookWithPublisher.kt
@@ -18,6 +18,5 @@
import android.arch.persistence.room.Embedded
-
data class BookWithPublisher(val bookId: String, val title: String,
@Embedded val publisher: Publisher)
diff --git a/room/integration-tests/testapp/build.gradle b/room/integration-tests/testapp/build.gradle
index b063595..d1da195 100644
--- a/room/integration-tests/testapp/build.gradle
+++ b/room/integration-tests/testapp/build.gradle
@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-apply plugin: 'com.android.application'
-project.ext.noDocs = true
+import static android.support.dependencies.DependenciesKt.*
+
+apply plugin: 'com.android.application'
android {
compileSdkVersion tools.current_sdk
@@ -55,18 +56,18 @@
}
dependencies {
- implementation project(":room:common")
- implementation project(":persistence:db")
- implementation project(":persistence:db-framework")
- implementation project(':room:runtime')
- implementation project(':arch:runtime')
- implementation project(':arch:common')
- implementation project(':paging:common')
- implementation project(':lifecycle:extensions')
- implementation project(':lifecycle:runtime')
- implementation project(':lifecycle:common')
- implementation project(':room:rxjava2')
- implementation project(':paging:runtime')
+ implementation(project(":room:common"))
+ implementation(project(":persistence:db"))
+ implementation(project(":persistence:db-framework"))
+ implementation(project(":room:runtime"))
+ implementation(project(":arch:runtime"))
+ implementation(project(":arch:common"))
+ implementation(project(":paging:common"))
+ implementation(project(":lifecycle:extensions"))
+ implementation(project(":lifecycle:runtime"))
+ implementation(project(":lifecycle:common"))
+ implementation(project(":room:rxjava2"))
+ implementation(project(":paging:runtime"))
implementation libs.support.recyclerview, libs.support_exclude_config
implementation libs.support.app_compat, libs.support_exclude_config
@@ -74,26 +75,21 @@
androidTestAnnotationProcessor project(":room:compiler")
// IJ's gradle integration just cannot figure this out ...
- androidTestImplementation project(':lifecycle:extensions')
- androidTestImplementation project(':lifecycle:common')
- androidTestImplementation project(':lifecycle:runtime')
- androidTestImplementation project(':room:testing')
- androidTestImplementation project(':room:rxjava2')
- androidTestImplementation project(':arch:core-testing')
- androidTestImplementation libs.rx_java
- androidTestImplementation(libs.test_runner) {
- exclude module: 'support-annotations'
- }
- androidTestImplementation(libs.espresso_core, {
- exclude group: 'com.android.support', module: 'support-annotations'
- })
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it's own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it's own MockMaker
+ androidTestImplementation(project(":lifecycle:extensions"))
+ androidTestImplementation(project(":lifecycle:common"))
+ androidTestImplementation(project(":lifecycle:runtime"))
+ androidTestImplementation(project(":room:testing"))
+ androidTestImplementation(project(":room:rxjava2"))
+ androidTestImplementation(project(":arch:core-testing"))
+ androidTestImplementation(RX_JAVA)
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it's own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it's own MockMaker
- testImplementation libs.junit
+ testImplementation(JUNIT)
}
-createAndroidCheckstyle(project)
tasks['check'].dependsOn(tasks['connectedCheck'])
uploadArchives.enabled = false
diff --git a/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/database/LastNameAscCustomerDataSource.java b/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/database/LastNameAscCustomerDataSource.java
index 2db543b..6278bc2 100644
--- a/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/database/LastNameAscCustomerDataSource.java
+++ b/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/database/LastNameAscCustomerDataSource.java
@@ -16,10 +16,9 @@
package android.arch.persistence.room.integration.testapp.database;
import android.arch.paging.DataSource;
-import android.arch.paging.KeyedDataSource;
+import android.arch.paging.ItemKeyedDataSource;
import android.arch.persistence.room.InvalidationTracker;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import java.util.Collections;
import java.util.List;
@@ -28,7 +27,7 @@
/**
* Sample Room keyed data source.
*/
-public class LastNameAscCustomerDataSource extends KeyedDataSource<String, Customer> {
+public class LastNameAscCustomerDataSource extends ItemKeyedDataSource<String, Customer> {
private final CustomerDao mCustomerDao;
@SuppressWarnings("FieldCanBeLocal")
private final InvalidationTracker.Observer mObserver;
@@ -76,13 +75,14 @@
}
@Override
- public void loadInitial(@Nullable String customerName, int initialLoadSize,
- boolean enablePlaceholders, @NonNull InitialLoadCallback<Customer> callback) {
+ public void loadInitial(@NonNull LoadInitialParams<String> params,
+ @NonNull LoadInitialCallback<Customer> callback) {
+ String customerName = params.requestedInitialKey;
List<Customer> list;
if (customerName != null) {
// initial keyed load - load before 'customerName',
// and load after last item in before list
- int pageSize = initialLoadSize / 2;
+ int pageSize = params.requestedLoadSize / 2;
String key = customerName;
list = mCustomerDao.customerNameLoadBefore(key, pageSize);
Collections.reverse(list);
@@ -91,10 +91,10 @@
}
list.addAll(mCustomerDao.customerNameLoadAfter(key, pageSize));
} else {
- list = mCustomerDao.customerNameInitial(initialLoadSize);
+ list = mCustomerDao.customerNameInitial(params.requestedLoadSize);
}
- if (enablePlaceholders && !list.isEmpty()) {
+ if (params.placeholdersEnabled && !list.isEmpty()) {
String firstKey = getKey(list.get(0));
String lastKey = getKey(list.get(list.size() - 1));
@@ -108,16 +108,18 @@
}
@Override
- public void loadAfter(@NonNull String currentEndKey, int pageSize,
+ public void loadAfter(@NonNull LoadParams<String> params,
@NonNull LoadCallback<Customer> callback) {
- callback.onResult(mCustomerDao.customerNameLoadAfter(currentEndKey, pageSize));
+ callback.onResult(mCustomerDao.customerNameLoadAfter(params.key, params.requestedLoadSize));
}
@Override
- public void loadBefore(@NonNull String currentBeginKey, int pageSize,
+ public void loadBefore(@NonNull LoadParams<String> params,
@NonNull LoadCallback<Customer> callback) {
- List<Customer> list = mCustomerDao.customerNameLoadBefore(currentBeginKey, pageSize);
+ List<Customer> list = mCustomerDao.customerNameLoadBefore(
+ params.key, params.requestedLoadSize);
Collections.reverse(list);
callback.onResult(list);
}
}
+
diff --git a/room/migration/build.gradle b/room/migration/build.gradle
index 086aac7..acadb71 100644
--- a/room/migration/build.gradle
+++ b/room/migration/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
import android.support.SupportLibraryExtension;
@@ -26,12 +27,12 @@
test.java.srcDirs += 'src/tests/kotlin'
}
dependencies {
- compile project(":room:common")
- compile libs.kotlin.stdlib
- compile libs.gson
- testCompile libs.junit
- testCompile libs.ij_annotations
- testCompile libs.mockito_core
+ compile(project(":room:common"))
+ compile(KOTLIN_STDLIB)
+ compile(GSON)
+ testCompile(JUNIT)
+ testCompile(INTELLIJ_ANNOTATIONS)
+ testCompile(MOCKITO_CORE)
}
supportLibrary {
diff --git a/room/runtime/build.gradle b/room/runtime/build.gradle
index 0570fe8..8a91ac7 100644
--- a/room/runtime/build.gradle
+++ b/room/runtime/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
import android.support.SupportLibraryExtension
@@ -33,27 +34,24 @@
}
dependencies {
- api project(":room:common")
- api project(":persistence:db-framework")
- api project(":persistence:db")
- api project(":arch:runtime")
+ api(project(":room:common"))
+ api(project(":persistence:db-framework"))
+ api(project(":persistence:db"))
+ api(project(":arch:runtime"))
compileOnly project(":paging:common")
compileOnly project(":lifecycle:runtime")
compileOnly project(":lifecycle:extensions")
api libs.support.core_utils, libs.support_exclude_config
- testImplementation project(":arch:core-testing")
- testImplementation libs.junit
- testImplementation libs.mockito_core
- testImplementation libs.support.annotations
+ testImplementation(project(":arch:core-testing"))
+ testImplementation(JUNIT)
+ testImplementation(MOCKITO_CORE)
- androidTestImplementation libs.junit
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
+ androidTestImplementation(JUNIT)
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
}
-createAndroidCheckstyle(project)
-
// Used by testCompile in room-compiler
android.libraryVariants.all { variant ->
def name = variant.buildType.name
diff --git a/room/runtime/lint-baseline.xml b/room/runtime/lint-baseline.xml
deleted file mode 100644
index 2cadde1..0000000
--- a/room/runtime/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0">
-
-</issues>
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/RoomDatabase.java b/room/runtime/src/main/java/android/arch/persistence/room/RoomDatabase.java
index 8c94024..2a108f9 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/RoomDatabase.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/RoomDatabase.java
@@ -90,7 +90,7 @@
* @param configuration The database configuration.
*/
@CallSuper
- public void init(DatabaseConfiguration configuration) {
+ public void init(@NonNull DatabaseConfiguration configuration) {
mOpenHelper = createOpenHelper(configuration);
mCallbacks = configuration.callbacks;
mAllowMainThreadQueries = configuration.allowMainThreadQueries;
@@ -101,6 +101,7 @@
*
* @return The SQLite open helper used by this database.
*/
+ @NonNull
public SupportSQLiteOpenHelper getOpenHelper() {
return mOpenHelper;
}
@@ -113,6 +114,7 @@
* @param config The configuration of the Room database.
* @return A new SupportSQLiteOpenHelper to be used while connecting to the database.
*/
+ @NonNull
protected abstract SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration config);
/**
@@ -122,6 +124,7 @@
*
* @return Creates a new InvalidationTracker.
*/
+ @NonNull
protected abstract InvalidationTracker createInvalidationTracker();
/**
@@ -199,7 +202,7 @@
* @param sql The query to compile.
* @return The compiled query.
*/
- public SupportSQLiteStatement compileStatement(String sql) {
+ public SupportSQLiteStatement compileStatement(@NonNull String sql) {
assertNotMainThread();
return mOpenHelper.getWritableDatabase().compileStatement(sql);
}
@@ -238,7 +241,7 @@
*
* @param body The piece of code to execute.
*/
- public void runInTransaction(Runnable body) {
+ public void runInTransaction(@NonNull Runnable body) {
beginTransaction();
try {
body.run();
@@ -256,7 +259,7 @@
* @param <V> The type of the return value.
* @return The value returned from the {@link Callable}.
*/
- public <V> V runInTransaction(Callable<V> body) {
+ public <V> V runInTransaction(@NonNull Callable<V> body) {
beginTransaction();
try {
V result = body.call();
@@ -278,7 +281,7 @@
*
* @param db The database instance.
*/
- protected void internalInitInvalidationTracker(SupportSQLiteDatabase db) {
+ protected void internalInitInvalidationTracker(@NonNull SupportSQLiteDatabase db) {
mInvalidationTracker.internalInit(db);
}
@@ -290,6 +293,7 @@
*
* @return The invalidation tracker for the database.
*/
+ @NonNull
public InvalidationTracker getInvalidationTracker() {
return mInvalidationTracker;
}
@@ -365,7 +369,7 @@
* @return this
*/
@NonNull
- public Builder<T> addMigrations(Migration... migrations) {
+ public Builder<T> addMigrations(@NonNull Migration... migrations) {
mMigrationContainer.addMigrations(migrations);
return this;
}
@@ -471,7 +475,7 @@
*
* @param migrations List of available migrations.
*/
- public void addMigrations(Migration... migrations) {
+ public void addMigrations(@NonNull Migration... migrations) {
for (Migration migration : migrations) {
addMigration(migration);
}
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/RoomSQLiteQuery.java b/room/runtime/src/main/java/android/arch/persistence/room/RoomSQLiteQuery.java
index a8defd4..a10cc52 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/RoomSQLiteQuery.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/RoomSQLiteQuery.java
@@ -209,7 +209,7 @@
}
@Override
- public void close() throws Exception {
+ public void close() {
// no-op. not calling release because it is internal API.
}
diff --git a/room/rxjava2/build.gradle b/room/rxjava2/build.gradle
index efdfc48..1b012dd 100644
--- a/room/rxjava2/build.gradle
+++ b/room/rxjava2/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
import android.support.SupportLibraryExtension
@@ -29,18 +30,16 @@
}
dependencies {
- api project(":room:common")
- api project(":room:runtime")
- api project(":arch:runtime")
+ api(project(":room:common"))
+ api(project(":room:runtime"))
+ api(project(":arch:runtime"))
api libs.support.core_utils, libs.support_exclude_config
- api libs.rx_java
- testImplementation libs.junit
- testImplementation libs.mockito_core
- testImplementation project(":arch:core-testing")
+ api(RX_JAVA)
+ testImplementation(JUNIT)
+ testImplementation(MOCKITO_CORE)
+ testImplementation(project(":arch:core-testing"))
}
-createAndroidCheckstyle(project)
-
supportLibrary {
name = "Android Room RXJava2"
publish = true
diff --git a/room/rxjava2/lint-baseline.xml b/room/rxjava2/lint-baseline.xml
deleted file mode 100644
index 2cadde1..0000000
--- a/room/rxjava2/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0">
-
-</issues>
diff --git a/room/testing/build.gradle b/room/testing/build.gradle
index 876300a..b71c8bc 100644
--- a/room/testing/build.gradle
+++ b/room/testing/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
import android.support.SupportLibraryExtension
@@ -29,18 +30,16 @@
}
dependencies {
- api project(":room:common")
- api project(":room:runtime")
- api project(":persistence:db")
- api project(":persistence:db-framework")
- api project(":room:migration")
- api project(":arch:runtime")
+ api(project(":room:common"))
+ api(project(":room:runtime"))
+ api(project(":persistence:db"))
+ api(project(":persistence:db-framework"))
+ api(project(":room:migration"))
+ api(project(":arch:runtime"))
api libs.support.core_utils, libs.support_exclude_config
- api libs.junit
+ api(JUNIT)
}
-createAndroidCheckstyle(project)
-
supportLibrary {
name = "Android Room Testing"
publish = true
diff --git a/samples/Support13Demos/build.gradle b/samples/Support13Demos/build.gradle
index 99175b3..ba2c2e4 100644
--- a/samples/Support13Demos/build.gradle
+++ b/samples/Support13Demos/build.gradle
@@ -1,7 +1,7 @@
apply plugin: 'com.android.application'
dependencies {
- implementation project(':support-v13')
+ implementation(project(":support-v13"))
}
android {
diff --git a/samples/Support4Demos/build.gradle b/samples/Support4Demos/build.gradle
index 8e76229..3257e6a 100644
--- a/samples/Support4Demos/build.gradle
+++ b/samples/Support4Demos/build.gradle
@@ -1,7 +1,7 @@
apply plugin: 'com.android.application'
dependencies {
- implementation project(':support-v4')
+ implementation(project(":support-v4"))
}
android {
diff --git a/samples/Support7Demos/build.gradle b/samples/Support7Demos/build.gradle
index 14d128a..6b2468b 100644
--- a/samples/Support7Demos/build.gradle
+++ b/samples/Support7Demos/build.gradle
@@ -1,12 +1,12 @@
apply plugin: 'com.android.application'
dependencies {
- implementation project(':appcompat-v7')
- implementation project(':cardview-v7')
- implementation project(':gridlayout-v7')
- implementation project(':mediarouter-v7')
- implementation project(':palette-v7')
- implementation project(':recyclerview-v7')
+ implementation(project(":appcompat-v7"))
+ implementation(project(":cardview-v7"))
+ implementation(project(":gridlayout-v7"))
+ implementation(project(":mediarouter-v7"))
+ implementation(project(":palette-v7"))
+ implementation(project(":recyclerview-v7"))
implementation project(':recyclerview-selection')
}
diff --git a/samples/SupportAnimationDemos/build.gradle b/samples/SupportAnimationDemos/build.gradle
index 23e5030..bb86bd5 100644
--- a/samples/SupportAnimationDemos/build.gradle
+++ b/samples/SupportAnimationDemos/build.gradle
@@ -1,7 +1,7 @@
apply plugin: 'com.android.application'
dependencies {
- implementation project(':support-dynamic-animation')
+ implementation(project(":support-dynamic-animation"))
}
android {
diff --git a/samples/SupportAppNavigation/build.gradle b/samples/SupportAppNavigation/build.gradle
index 35a9d73..b242576 100644
--- a/samples/SupportAppNavigation/build.gradle
+++ b/samples/SupportAppNavigation/build.gradle
@@ -17,7 +17,7 @@
apply plugin: 'com.android.application'
dependencies {
- implementation project(':support-v4')
+ implementation(project(":support-v4"))
}
android {
diff --git a/samples/SupportCarDemos/OWNERS b/samples/SupportCarDemos/OWNERS
new file mode 100644
index 0000000..42ef8d4
--- /dev/null
+++ b/samples/SupportCarDemos/OWNERS
@@ -0,0 +1,2 @@
+ajchen@google.com
+yaoyx@google.com
\ No newline at end of file
diff --git a/samples/SupportCarDemos/build.gradle b/samples/SupportCarDemos/build.gradle
new file mode 100644
index 0000000..efd8550
--- /dev/null
+++ b/samples/SupportCarDemos/build.gradle
@@ -0,0 +1,32 @@
+apply plugin: 'com.android.application'
+
+dependencies {
+ implementation project(':car')
+}
+
+android {
+ compileSdkVersion project.ext.currentSdk
+
+ defaultConfig {
+ minSdkVersion 24
+ targetSdkVersion project.ext.currentSdk
+ }
+
+ signingConfigs {
+ debug {
+ // Use a local debug keystore to avoid build server issues.
+ storeFile project.rootProject.init.debugKeystore
+ }
+ }
+
+ lintOptions {
+ abortOnError true
+ check 'NewApi'
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
diff --git a/samples/SupportCarDemos/src/main/AndroidManifest.xml b/samples/SupportCarDemos/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..c32fcf4
--- /dev/null
+++ b/samples/SupportCarDemos/src/main/AndroidManifest.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.androidx.car">
+
+ <application android:label="@string/activity_sample_code"
+ android:supportsRtl="true"
+ android:icon="@drawable/app_sample_code"
+ android:theme="@style/CarTheme">
+
+ <activity android:name=".SupportCarDemoActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".PagedListViewActivity"
+ android:label="PagedListView"
+ android:parentActivityName=".SupportCarDemoActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ <meta-data android:name="android.support.PARENT_ACTIVITY"
+ android:value=".SupportCarDemoActivity" />
+ </activity>
+
+ <activity android:name=".ListItemActivity"
+ android:label="ListItem"
+ android:parentActivityName=".SupportCarDemoActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ <meta-data android:name="android.support.PARENT_ACTIVITY"
+ android:value=".SupportCarDemoActivity" />
+ </activity>
+ </application>
+</manifest>
+
diff --git a/samples/SupportCarDemos/src/main/java/com/example/androidx/car/ListItemActivity.java b/samples/SupportCarDemos/src/main/java/com/example/androidx/car/ListItemActivity.java
new file mode 100644
index 0000000..6aa5ba6
--- /dev/null
+++ b/samples/SupportCarDemos/src/main/java/com/example/androidx/car/ListItemActivity.java
@@ -0,0 +1,223 @@
+/*
+ * 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.androidx.car;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Point;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import androidx.car.widget.ListItem;
+import androidx.car.widget.ListItemAdapter;
+import androidx.car.widget.ListItemProvider;
+import androidx.car.widget.PagedListView;
+
+/**
+ * Demo activity for {@link ListItem}.
+ */
+public class ListItemActivity extends Activity {
+
+ private static int pixelToDip(Context context, int pixels) {
+ return (int) (pixels / context.getResources().getDisplayMetrics().density);
+ }
+
+ PagedListView mPagedListView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_paged_list_view);
+
+ mPagedListView = findViewById(R.id.paged_list_view);
+
+ ListItemAdapter adapter = new ListItemAdapter(this,
+ new SampleProvider(this));
+ mPagedListView.setAdapter(adapter);
+ mPagedListView.setMaxPages(PagedListView.UNLIMITED_PAGES);
+ }
+
+ private static class SampleProvider extends ListItemProvider {
+ private Context mContext;
+ private List<ListItem> mItems;
+
+ private View.OnClickListener mGetParentHeight = (v) -> {
+ int parentHeight = ((FrameLayout) v.getParent().getParent().getParent()).getHeight();
+ Toast.makeText(v.getContext(),
+ "card height is " + pixelToDip(mContext, parentHeight) + " dp",
+ Toast.LENGTH_SHORT).show();
+ };
+
+ private ListItemProvider.ListProvider mListProvider;
+
+ SampleProvider(Context context) {
+ mContext = context;
+ mItems = new ArrayList<>();
+
+ mItems.add(new ListItem.Builder(mContext)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, true)
+ .withTitle("single line with full icon and one action")
+ .withAction("card height", true, mGetParentHeight)
+ .build());
+
+ mItems.add(new ListItem.Builder(mContext)
+ .withTitle("primary action set by drawable")
+ .withPrimaryActionIcon(mContext.getDrawable(R.drawable.pressed_icon), true)
+ .withViewBinder(vh -> vh.getPrimaryIcon().setClickable(true))
+ .build());
+
+ mItems.add(new ListItem.Builder(mContext)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false)
+ .withTitle("single line with small icon and clickable end icon")
+ .withSupplementalIcon(android.R.drawable.sym_def_app_icon, true,
+ mGetParentHeight)
+ .build());
+
+ mItems.add(new ListItem.Builder(mContext)
+ .withPrimaryActionEmptyIcon()
+ .withTitle("single line with empty icon and end icon no divider")
+ .withSupplementalIcon(android.R.drawable.sym_def_app_icon, false)
+ .build());
+
+ mItems.add(new ListItem.Builder(mContext)
+ .withTitle("title is single line and ellipsizes. "
+ + mContext.getString(R.string.long_text))
+ .withSupplementalIcon(android.R.drawable.sym_def_app_icon, true)
+ .build());
+
+ mItems.add(new ListItem.Builder(mContext)
+ .withPrimaryActionNoIcon()
+ .withTitle("single line with two actions and no divider")
+ .withActions("action 1", false,
+ (v) -> Toast.makeText(
+ v.getContext(), "action 1", Toast.LENGTH_SHORT).show(),
+ "action 2", false,
+ (v) -> Toast.makeText(
+ v.getContext(), "action 2", Toast.LENGTH_SHORT).show())
+ .build());
+
+ mItems.add(new ListItem.Builder(mContext)
+ .withPrimaryActionNoIcon()
+ .withTitle("single line with two actions and action 2 divider")
+ .withActions("action 1", false,
+ (v) -> Toast.makeText(
+ v.getContext(), "action 1", Toast.LENGTH_SHORT).show(),
+ "action 2", true,
+ (v) -> Toast.makeText(
+ v.getContext(), "action 2", Toast.LENGTH_SHORT).show())
+ .build());
+
+ mItems.add(new ListItem.Builder(mContext)
+ .withPrimaryActionNoIcon()
+ .withTitle("single line with divider between actions. "
+ + mContext.getString(R.string.long_text))
+ .withActions("action 1", true,
+ (v) -> Toast.makeText(
+ v.getContext(), "action 1", Toast.LENGTH_SHORT).show(),
+ "action 2", false,
+ (v) -> Toast.makeText(
+ v.getContext(), "action 2", Toast.LENGTH_SHORT).show())
+ .build());
+
+ mItems.add(new ListItem.Builder(mContext)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, true)
+ .withTitle("double line with full icon and no end icon divider")
+ .withBody("one line text")
+ .withSupplementalIcon(android.R.drawable.sym_def_app_icon, false,
+ mGetParentHeight)
+ .build());
+
+ mItems.add(new ListItem.Builder(mContext)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false)
+ .withTitle("double line with small icon and one action")
+ .withBody("one line text")
+ .withAction("card height", true, mGetParentHeight)
+ .build());
+
+ String tenChars = "Ten Chars.";
+ mItems.add(new ListItem.Builder(mContext)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false)
+ .withTitle("Card with small icon and text longer than limit")
+ .withBody("some chars")
+ .withBody(TextUtils.join("", Collections.nCopies(20, tenChars)))
+ .withSupplementalIcon(android.R.drawable.sym_def_app_icon, true,
+ mGetParentHeight)
+ .build());
+
+ mItems.add(new ListItem.Builder(mContext)
+ .withPrimaryActionEmptyIcon()
+ .withTitle("double line with empty primary icon."
+ + mContext.getString(R.string.long_text))
+ .withBody("one line text as primary", true)
+ .withActions("screen size", false, (v) -> {
+ Context c = v.getContext();
+ Point size = new Point();
+ c.getSystemService(WindowManager.class).getDefaultDisplay().getSize(size);
+
+ Toast.makeText(v.getContext(),
+ String.format("%s x %s dp", pixelToDip(c, size.x),
+ pixelToDip(c, size.y)), Toast.LENGTH_SHORT).show();
+ }, "card height", true, mGetParentHeight)
+ .build());
+
+ mItems.add(new ListItem.Builder(mContext)
+ .withTitle("double line with no primary action and one divider")
+ .withBody("one line text as primary", true)
+ .withActions("screen size", false, (v) -> {
+ Context c = v.getContext();
+ Point size = new Point();
+ c.getSystemService(WindowManager.class).getDefaultDisplay().getSize(size);
+
+ Toast.makeText(v.getContext(),
+ String.format("%s x %s dp", pixelToDip(c, size.x),
+ pixelToDip(c, size.y)), Toast.LENGTH_SHORT).show();
+ }, "card height", true, mGetParentHeight)
+ .build());
+
+ mItems.add(new ListItem.Builder(mContext)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, true)
+ .withBody("Only body - no title is set")
+ .withAction("card height", true, mGetParentHeight)
+ .build());
+
+ mItems.add(new ListItem.Builder(mContext)
+ .withPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false)
+ .withBody("Only body - no title. " + mContext.getString(R.string.long_text))
+ .build());
+
+ mListProvider = new ListItemProvider.ListProvider(mItems);
+ }
+
+ @Override
+ public ListItem get(int position) {
+ return mListProvider.get(position);
+ }
+
+ @Override
+ public int size() {
+ return mListProvider.size();
+ }
+ }
+}
diff --git a/samples/SupportCarDemos/src/main/java/com/example/androidx/car/PagedListViewActivity.java b/samples/SupportCarDemos/src/main/java/com/example/androidx/car/PagedListViewActivity.java
new file mode 100644
index 0000000..2aa4e0c
--- /dev/null
+++ b/samples/SupportCarDemos/src/main/java/com/example/androidx/car/PagedListViewActivity.java
@@ -0,0 +1,101 @@
+/*
+ * 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.androidx.car;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.car.widget.PagedListView;
+
+/**
+ * Demo activity for PagedListView.
+ */
+public class PagedListViewActivity extends Activity {
+
+ private static final int ITEM_COUNT = 80;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_paged_list_view);
+
+ PagedListView pagedListView = findViewById(R.id.paged_list_view);
+ pagedListView.setAdapter(new DemoAdapter(ITEM_COUNT));
+
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+ }
+
+ /**
+ * Adapter that populates a number of items for demo purposes.
+ */
+ public static class DemoAdapter extends RecyclerView.Adapter<DemoAdapter.ViewHolder> {
+
+ private final List<String> mItems = new ArrayList<>();
+
+ /**
+ * Generates a string for item text.
+ */
+ public static String getItemText(int index) {
+ return "Item " + index;
+ }
+
+
+ public DemoAdapter(int itemCount) {
+ for (int i = 0; i < itemCount; i++) {
+ mItems.add(getItemText(i));
+ }
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+ View view = inflater.inflate(R.layout.paged_list_item, parent, false);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ holder.mTextView.setText(mItems.get(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ return mItems.size();
+ }
+
+ /**
+ * ViewHolder for DemoAdapter.
+ */
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+ private TextView mTextView;
+
+ public ViewHolder(View itemView) {
+ super(itemView);
+ mTextView = itemView.findViewById(R.id.text);
+ }
+ }
+ }
+}
+
diff --git a/samples/SupportCarDemos/src/main/java/com/example/androidx/car/SupportCarDemoActivity.java b/samples/SupportCarDemos/src/main/java/com/example/androidx/car/SupportCarDemoActivity.java
new file mode 100644
index 0000000..049c5c6
--- /dev/null
+++ b/samples/SupportCarDemos/src/main/java/com/example/androidx/car/SupportCarDemoActivity.java
@@ -0,0 +1,124 @@
+/*
+ * 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.androidx.car;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Home activity for car support library samples.
+ */
+public class SupportCarDemoActivity extends ListActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setListAdapter(new SampleAdapter(querySampleActivities()));
+ }
+
+ @Override
+ protected void onListItemClick(ListView lv, View v, int pos, long id) {
+ SampleInfo info = (SampleInfo) getListAdapter().getItem(pos);
+ startActivity(info.mIntent);
+ }
+
+ protected List<SampleInfo> querySampleActivities() {
+ Intent intent = new Intent(Intent.ACTION_MAIN, null);
+ intent.setPackage(getPackageName());
+ intent.addCategory(Intent.CATEGORY_SAMPLE_CODE);
+
+ PackageManager pm = getPackageManager();
+ List<ResolveInfo> infos = pm.queryIntentActivities(intent, 0);
+
+ ArrayList<SampleInfo> samples = new ArrayList<>();
+
+ final int count = infos.size();
+ for (int i = 0; i < count; i++) {
+ final ResolveInfo info = infos.get(i);
+ final CharSequence labelSeq = info.loadLabel(pm);
+ String label = TextUtils.isEmpty(labelSeq)
+ ? info.activityInfo.name
+ : labelSeq.toString();
+
+ Intent target = new Intent();
+ target.setClassName(info.activityInfo.applicationInfo.packageName,
+ info.activityInfo.name);
+ SampleInfo sample = new SampleInfo(label, target);
+ samples.add(sample);
+ }
+
+ return samples;
+ }
+
+ static class SampleInfo {
+ String mName;
+ Intent mIntent;
+
+ SampleInfo(String name, Intent intent) {
+ this.mName = name;
+ this.mIntent = intent;
+ }
+ }
+
+ class SampleAdapter extends BaseAdapter {
+ private List<SampleInfo> mItems;
+
+ SampleAdapter(List<SampleInfo> items) {
+ mItems = items;
+ }
+
+ @Override
+ public int getCount() {
+ return mItems.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mItems.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(android.R.layout.simple_list_item_1,
+ parent, false);
+ convertView.setTag(convertView.findViewById(android.R.id.text1));
+ }
+ TextView tv = (TextView) convertView.getTag();
+ tv.setText(mItems.get(position).mName);
+ return convertView;
+ }
+
+ }
+}
diff --git a/samples/SupportCarDemos/src/main/res/drawable/app_sample_code.png b/samples/SupportCarDemos/src/main/res/drawable/app_sample_code.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/samples/SupportCarDemos/src/main/res/drawable/app_sample_code.png
Binary files differ
diff --git a/samples/SupportCarDemos/src/main/res/drawable/pressed_icon.xml b/samples/SupportCarDemos/src/main/res/drawable/pressed_icon.xml
new file mode 100644
index 0000000..32a497f
--- /dev/null
+++ b/samples/SupportCarDemos/src/main/res/drawable/pressed_icon.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@android:drawable/btn_star_big_on"/>
+ <item android:drawable="@android:drawable/btn_star_big_off"/>
+</selector>
diff --git a/samples/SupportCarDemos/src/main/res/layout/activity_paged_list_view.xml b/samples/SupportCarDemos/src/main/res/layout/activity_paged_list_view.xml
new file mode 100644
index 0000000..5b9a1a5
--- /dev/null
+++ b/samples/SupportCarDemos/src/main/res/layout/activity_paged_list_view.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 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.
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <androidx.car.widget.PagedListView
+ android:id="@+id/paged_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:showPagedListViewDivider="true"
+ app:offsetScrollBar="true"/>
+</FrameLayout>
+
diff --git a/samples/SupportCarDemos/src/main/res/layout/paged_list_item.xml b/samples/SupportCarDemos/src/main/res/layout/paged_list_item.xml
new file mode 100644
index 0000000..26f9c5a
--- /dev/null
+++ b/samples/SupportCarDemos/src/main/res/layout/paged_list_item.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 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.
+ -->
+<androidx.car.widget.ColumnCardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:cardBackgroundColor="@color/car_card">
+ <TextView
+ android:id="@+id/text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textAppearance="@style/CarBody1"/>
+</androidx.car.widget.ColumnCardView>
\ No newline at end of file
diff --git a/samples/SupportCarDemos/src/main/res/values/strings.xml b/samples/SupportCarDemos/src/main/res/values/strings.xml
new file mode 100644
index 0000000..adffe89
--- /dev/null
+++ b/samples/SupportCarDemos/src/main/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 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.
+-->
+<resources>
+ <string name="activity_sample_code">Support Car Demos</string>
+ <string name="long_text">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</string>
+</resources>
+
diff --git a/samples/SupportCarDemos/src/main/res/values/themes.xml b/samples/SupportCarDemos/src/main/res/values/themes.xml
new file mode 100644
index 0000000..4b82ecd
--- /dev/null
+++ b/samples/SupportCarDemos/src/main/res/values/themes.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- The main theme for all activities within the Car Demo. -->
+ <style name="CarTheme" parent="android:Theme.Material.Light">
+ <item name="android:windowBackground">@color/car_grey_50</item>
+ <item name="android:colorAccent">@color/car_yellow_500</item>
+ <item name="android:colorPrimary">@color/car_highlight</item>
+ <item name="android:colorPrimaryDark">@color/car_grey_300</item>
+ <item name="android:buttonStyle">@style/CarButton</item>
+ <item name="android:borderlessButtonStyle">@style/CarButton.Borderless</item>
+ <item name="android:progressBarStyleHorizontal">
+ @style/CarProgressBar.Horizontal
+ </item>
+ <item name="android:windowLightStatusBar">true</item>
+ </style>
+</resources>
diff --git a/samples/SupportContentDemos/build.gradle b/samples/SupportContentDemos/build.gradle
index 1ed1134..898774c 100644
--- a/samples/SupportContentDemos/build.gradle
+++ b/samples/SupportContentDemos/build.gradle
@@ -17,9 +17,9 @@
apply plugin: 'com.android.application'
dependencies {
- implementation project(':design')
- implementation project(':appcompat-v7')
- implementation project(':support-content')
+ implementation(project(":design"))
+ implementation(project(":appcompat-v7"))
+ implementation(project(":support-content"))
}
android {
diff --git a/samples/SupportDesignDemos/build.gradle b/samples/SupportDesignDemos/build.gradle
index 7abaa0e..ed111f3 100644
--- a/samples/SupportDesignDemos/build.gradle
+++ b/samples/SupportDesignDemos/build.gradle
@@ -1,7 +1,7 @@
apply plugin: 'com.android.application'
dependencies {
- implementation project(':design')
+ implementation(project(":design"))
}
android {
diff --git a/samples/SupportDesignDemos/src/main/res/layout/design_fab.xml b/samples/SupportDesignDemos/src/main/res/layout/design_fab.xml
index ad26d5b..f00dd96 100644
--- a/samples/SupportDesignDemos/src/main/res/layout/design_fab.xml
+++ b/samples/SupportDesignDemos/src/main/res/layout/design_fab.xml
@@ -66,6 +66,21 @@
android:clickable="true"
app:fabSize="mini" />
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dp"
+ android:textAppearance="@style/TextAppearance.AppCompat.Title"
+ android:text="@string/fab_size_custom" />
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/custom_fab"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_margin="16dp"
+ android:src="@drawable/ic_add"
+ android:clickable="true"
+ app:fabCustomSize="@dimen/custom_fab_size" />
</LinearLayout>
</FrameLayout>
\ No newline at end of file
diff --git a/samples/SupportDesignDemos/src/main/res/values/dimens.xml b/samples/SupportDesignDemos/src/main/res/values/dimens.xml
index c8a5ea9..68e4775 100644
--- a/samples/SupportDesignDemos/src/main/res/values/dimens.xml
+++ b/samples/SupportDesignDemos/src/main/res/values/dimens.xml
@@ -20,4 +20,6 @@
<dimen name="bottom_sheet_peek_height">128dp</dimen>
<dimen name="custom_snackbar_max_width">-1px</dimen>
+
+ <dimen name="custom_fab_size">45dp</dimen>
</resources>
diff --git a/samples/SupportDesignDemos/src/main/res/values/strings.xml b/samples/SupportDesignDemos/src/main/res/values/strings.xml
index 6ebe24c..e1818af 100644
--- a/samples/SupportDesignDemos/src/main/res/values/strings.xml
+++ b/samples/SupportDesignDemos/src/main/res/values/strings.xml
@@ -37,6 +37,7 @@
<string name="fab_size_normal">Normal size</string>
<string name="fab_size_mini">Mini size</string>
+ <string name="fab_size_custom">Custom size</string>
<string name="navigation_open">Open</string>
<string name="navigation_close">Close</string>
diff --git a/samples/SupportEmojiDemos/build.gradle b/samples/SupportEmojiDemos/build.gradle
index abc8328..dea5bf4 100644
--- a/samples/SupportEmojiDemos/build.gradle
+++ b/samples/SupportEmojiDemos/build.gradle
@@ -21,9 +21,9 @@
}
dependencies {
- implementation project(':support-emoji')
- implementation project(':support-emoji-bundled')
- implementation project(':support-emoji-appcompat')
+ implementation(project(":support-emoji"))
+ implementation(project(":support-emoji-bundled"))
+ implementation(project(":support-emoji-appcompat"))
}
android {
diff --git a/samples/SupportLeanbackDemos/build.gradle b/samples/SupportLeanbackDemos/build.gradle
index 61d0209..a00d435 100644
--- a/samples/SupportLeanbackDemos/build.gradle
+++ b/samples/SupportLeanbackDemos/build.gradle
@@ -1,8 +1,8 @@
apply plugin: 'com.android.application'
dependencies {
- implementation project(':leanback-v17')
- implementation project(':preference-leanback-v17')
+ implementation(project(":leanback-v17"))
+ implementation(project(":preference-leanback-v17"))
implementation 'com.google.code.gson:gson:2.6.2'
}
diff --git a/samples/SupportLeanbackJank/build.gradle b/samples/SupportLeanbackJank/build.gradle
index eef9986..3ba2d64 100644
--- a/samples/SupportLeanbackJank/build.gradle
+++ b/samples/SupportLeanbackJank/build.gradle
@@ -2,8 +2,8 @@
dependencies {
implementation 'com.github.bumptech.glide:glide:3.6.1'
- implementation project(':leanback-v17')
- implementation project(':preference-leanback-v17')
+ implementation(project(":leanback-v17"))
+ implementation(project(":preference-leanback-v17"))
}
android {
diff --git a/samples/SupportPercentDemos/build.gradle b/samples/SupportPercentDemos/build.gradle
index cec4b03..353e034 100644
--- a/samples/SupportPercentDemos/build.gradle
+++ b/samples/SupportPercentDemos/build.gradle
@@ -1,7 +1,7 @@
apply plugin: 'com.android.application'
dependencies {
- implementation project(':percent')
+ implementation(project(":percent"))
}
android {
diff --git a/samples/SupportPreferenceDemos/build.gradle b/samples/SupportPreferenceDemos/build.gradle
index f720b92..742ceb7 100644
--- a/samples/SupportPreferenceDemos/build.gradle
+++ b/samples/SupportPreferenceDemos/build.gradle
@@ -1,12 +1,12 @@
apply plugin: 'com.android.application'
dependencies {
- implementation project(':appcompat-v7')
- implementation project(':recyclerview-v7')
- implementation project(':preference-v7')
- implementation project(':preference-v14')
- implementation project(':leanback-v17')
- implementation project(':preference-leanback-v17')
+ implementation(project(":appcompat-v7"))
+ implementation(project(":recyclerview-v7"))
+ implementation(project(":preference-v7"))
+ implementation(project(":preference-v14"))
+ implementation(project(":leanback-v17"))
+ implementation(project(":preference-leanback-v17"))
}
android {
diff --git a/samples/SupportTransitionDemos/build.gradle b/samples/SupportTransitionDemos/build.gradle
index 8719221..47c84ad 100644
--- a/samples/SupportTransitionDemos/build.gradle
+++ b/samples/SupportTransitionDemos/build.gradle
@@ -1,8 +1,8 @@
apply plugin: 'com.android.application'
dependencies {
- implementation project(':transition')
- implementation project(':appcompat-v7')
+ implementation(project(":transition"))
+ implementation(project(":appcompat-v7"))
}
android {
diff --git a/samples/SupportVectorDrawableDemos/build.gradle b/samples/SupportVectorDrawableDemos/build.gradle
index e9c9d2c..09bb2d5 100644
--- a/samples/SupportVectorDrawableDemos/build.gradle
+++ b/samples/SupportVectorDrawableDemos/build.gradle
@@ -17,9 +17,9 @@
apply plugin: 'com.android.application'
dependencies {
- implementation project(':support-vector-drawable')
- implementation project(':animated-vector-drawable')
- implementation project(':appcompat-v7')
+ implementation(project(":support-vector-drawable"))
+ implementation(project(":animated-vector-drawable"))
+ implementation(project(":appcompat-v7"))
}
android {
diff --git a/samples/SupportWearDemos/build.gradle b/samples/SupportWearDemos/build.gradle
index ae0f195..96da969 100644
--- a/samples/SupportWearDemos/build.gradle
+++ b/samples/SupportWearDemos/build.gradle
@@ -17,7 +17,7 @@
apply plugin: 'com.android.application'
dependencies {
- implementation project(':wear')
+ implementation(project(":wear"))
implementation project(path: ':appcompat-v7')
}
diff --git a/samples/SupportWearDemos/src/main/java/com/example/android/support/wear/app/AlertDialogDemo.java b/samples/SupportWearDemos/src/main/java/com/example/android/support/wear/app/AlertDialogDemo.java
index 4ea448a..35a32ce 100644
--- a/samples/SupportWearDemos/src/main/java/com/example/android/support/wear/app/AlertDialogDemo.java
+++ b/samples/SupportWearDemos/src/main/java/com/example/android/support/wear/app/AlertDialogDemo.java
@@ -17,6 +17,7 @@
package com.example.android.support.wear.app;
import android.app.Activity;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
@@ -55,10 +56,12 @@
}
private AlertDialog createV7Dialog() {
+ Drawable drawable = getDrawable(R.drawable.app_sample_code);
return new AlertDialog.Builder(this)
.setTitle("AppCompatDialog")
.setMessage("Lorem ipsum dolor...")
.setPositiveButton("Ok", null)
+ .setPositiveButtonIcon(drawable)
.setNegativeButton("Cancel", null)
.create();
}
diff --git a/samples/SupportWearDemos/src/main/res/layout/alert_dialog_demo.xml b/samples/SupportWearDemos/src/main/res/layout/alert_dialog_demo.xml
index 833d489..5df4f4c 100644
--- a/samples/SupportWearDemos/src/main/res/layout/alert_dialog_demo.xml
+++ b/samples/SupportWearDemos/src/main/res/layout/alert_dialog_demo.xml
@@ -41,4 +41,4 @@
android:text="Show Framework dialog"/>
</LinearLayout>
-</android.support.wear.widget.BoxInsetLayout>
\ No newline at end of file
+</android.support.wear.widget.BoxInsetLayout>
diff --git a/settings.gradle b/settings.gradle
index 0544c91..1eccbcf 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -165,6 +165,8 @@
include ':support-emoji-demos'
project(':support-emoji-demos').projectDir = new File(samplesRoot, 'SupportEmojiDemos')
+include ':support-car-demos'
+project(':support-car-demos').projectDir = new File(samplesRoot, 'SupportCarDemos')
/////////////////////////////
//
// Testing libraries
diff --git a/testutils/build.gradle b/testutils/build.gradle
index 6ecc012..074ab34 100644
--- a/testutils/build.gradle
+++ b/testutils/build.gradle
@@ -14,19 +14,21 @@
* limitations under the License.
*/
+import static android.support.dependencies.DependenciesKt.*
+
plugins {
id("SupportAndroidLibraryPlugin")
}
dependencies {
- api project(':support-fragment')
- api project(':appcompat-v7')
+ api(project(":support-fragment"))
+ api(project(":appcompat-v7"))
- compile libs.test_runner, { exclude module: 'support-annotations' }
- compile libs.espresso_core, { exclude module: 'support-annotations' }
- compile libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has its own MockMaker
- compile libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has its own MockMaker
- compile libs.junit
+ implementation(TEST_RUNNER)
+ implementation(ESPRESSO_CORE)
+ implementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ implementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ implementation(JUNIT)
}
android {
diff --git a/testutils/lint-baseline.xml b/testutils/lint-baseline.xml
deleted file mode 100644
index f50cc2a..0000000
--- a/testutils/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-beta2">
-
-</issues>
diff --git a/transition/api/current.txt b/transition/api/current.txt
index 805fcfc..b939299 100644
--- a/transition/api/current.txt
+++ b/transition/api/current.txt
@@ -118,7 +118,7 @@
method public void setSlideEdge(int);
}
- public abstract class Transition {
+ public abstract class Transition implements java.lang.Cloneable {
ctor public Transition();
ctor public Transition(android.content.Context, android.util.AttributeSet);
method public android.support.transition.Transition addListener(android.support.transition.Transition.TransitionListener);
diff --git a/transition/build.gradle b/transition/build.gradle
index cd2c237..dcf3a76 100644
--- a/transition/build.gradle
+++ b/transition/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,16 +7,16 @@
}
dependencies {
- api project(':support-annotations')
- api project(':support-compat')
+ api(project(":support-annotations"))
+ api(project(":support-compat"))
compileOnly project(':support-fragment')
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation project(':support-v4')
- androidTestImplementation project(':appcompat-v7')
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(project(":support-v4"))
+ androidTestImplementation(project(":appcompat-v7"))
}
android {
diff --git a/transition/lint-baseline.xml b/transition/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/transition/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/transition/src/main/java/android/support/transition/package.html b/transition/src/main/java/android/support/transition/package.html
index b09005f..d8394a5 100644
--- a/transition/src/main/java/android/support/transition/package.html
+++ b/transition/src/main/java/android/support/transition/package.html
@@ -1,6 +1,6 @@
<body>
-Support android.transition classes to provide transition API back to android API level 14.
+Support android.transition classes to provide transition API back to Android API level 14.
This library contains {@link android.support.transition.Transition},
{@link android.support.transition.TransitionManager}, and other related classes
back-ported from their platform versions introduced Android API level 19.
diff --git a/tv-provider/api/27.0.0.ignore b/tv-provider/api/27.0.0.ignore
new file mode 100644
index 0000000..3bd938a
--- /dev/null
+++ b/tv-provider/api/27.0.0.ignore
@@ -0,0 +1,7 @@
+122b8cc
+7a7f371
+906efec
+355dc8b
+1490eba
+e3d27cc
+cd7673a
diff --git a/tv-provider/api/current.txt b/tv-provider/api/current.txt
index 80421e9..ef10221 100644
--- a/tv-provider/api/current.txt
+++ b/tv-provider/api/current.txt
@@ -74,12 +74,10 @@
}
public final class PreviewProgram {
- method public boolean equals(java.lang.Object);
method public static android.support.media.tv.PreviewProgram fromCursor(android.database.Cursor);
method public long getChannelId();
method public int getWeight();
method public android.content.ContentValues toContentValues();
- method public java.lang.String toString();
}
public static final class PreviewProgram.Builder {
@@ -92,16 +90,13 @@
public final class Program implements java.lang.Comparable {
method public int compareTo(android.support.media.tv.Program);
- method public boolean equals(java.lang.Object);
method public static android.support.media.tv.Program fromCursor(android.database.Cursor);
method public java.lang.String[] getBroadcastGenres();
method public long getChannelId();
method public long getEndTimeUtcMillis();
method public long getStartTimeUtcMillis();
- method public int hashCode();
method public boolean isRecordingProhibited();
method public android.content.ContentValues toContentValues();
- method public java.lang.String toString();
}
public static class Program.Builder {
@@ -149,7 +144,7 @@
field public static final java.lang.String EXTRA_WATCH_NEXT_PROGRAM_ID = "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
}
- public static abstract interface TvContractCompat.BaseTvColumns {
+ public static abstract interface TvContractCompat.BaseTvColumns implements android.provider.BaseColumns {
field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
}
@@ -525,12 +520,10 @@
}
public final class WatchNextProgram {
- method public boolean equals(java.lang.Object);
method public static android.support.media.tv.WatchNextProgram fromCursor(android.database.Cursor);
method public long getLastEngagementTimeUtcMillis();
method public int getWatchNextType();
method public android.content.ContentValues toContentValues();
- method public java.lang.String toString();
field public static final int WATCH_NEXT_TYPE_UNKNOWN = -1; // 0xffffffff
}
diff --git a/tv-provider/build.gradle b/tv-provider/build.gradle
index 60c2b2e..7090108 100644
--- a/tv-provider/build.gradle
+++ b/tv-provider/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,10 +7,10 @@
}
dependencies {
- api project(':support-annotations')
- api project(':support-compat')
+ api(project(":support-annotations"))
+ api(project(":support-compat"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
+ androidTestImplementation(TEST_RUNNER)
}
android {
diff --git a/v13/api/current.txt b/v13/api/current.txt
index 73871f6..1d9fdbf 100644
--- a/v13/api/current.txt
+++ b/v13/api/current.txt
@@ -5,44 +5,63 @@
method public static android.support.v13.view.DragAndDropPermissionsCompat requestDragAndDropPermissions(android.app.Activity, android.view.DragEvent);
}
- public class FragmentCompat {
- ctor public FragmentCompat();
- method public static void requestPermissions(android.app.Fragment, java.lang.String[], int);
+ public deprecated class FragmentCompat {
+ ctor public deprecated FragmentCompat();
+ method public static deprecated void requestPermissions(android.app.Fragment, java.lang.String[], int);
method public static deprecated void setMenuVisibility(android.app.Fragment, boolean);
- method public static void setPermissionCompatDelegate(android.support.v13.app.FragmentCompat.PermissionCompatDelegate);
- method public static void setUserVisibleHint(android.app.Fragment, boolean);
- method public static boolean shouldShowRequestPermissionRationale(android.app.Fragment, java.lang.String);
+ method public static deprecated void setPermissionCompatDelegate(android.support.v13.app.FragmentCompat.PermissionCompatDelegate);
+ method public static deprecated void setUserVisibleHint(android.app.Fragment, boolean);
+ method public static deprecated boolean shouldShowRequestPermissionRationale(android.app.Fragment, java.lang.String);
}
- public static abstract interface FragmentCompat.OnRequestPermissionsResultCallback {
- method public abstract void onRequestPermissionsResult(int, java.lang.String[], int[]);
+ public static abstract deprecated interface FragmentCompat.OnRequestPermissionsResultCallback {
+ method public abstract deprecated void onRequestPermissionsResult(int, java.lang.String[], int[]);
}
- public static abstract interface FragmentCompat.PermissionCompatDelegate {
- method public abstract boolean requestPermissions(android.app.Fragment, java.lang.String[], int);
+ public static abstract deprecated interface FragmentCompat.PermissionCompatDelegate {
+ method public abstract deprecated boolean requestPermissions(android.app.Fragment, java.lang.String[], int);
}
- public abstract class FragmentPagerAdapter extends android.support.v4.view.PagerAdapter {
- ctor public FragmentPagerAdapter(android.app.FragmentManager);
- method public abstract android.app.Fragment getItem(int);
- method public long getItemId(int);
- method public boolean isViewFromObject(android.view.View, java.lang.Object);
+ public abstract deprecated class FragmentPagerAdapter extends android.support.v4.view.PagerAdapter {
+ ctor public deprecated FragmentPagerAdapter(android.app.FragmentManager);
+ method public deprecated void destroyItem(android.view.ViewGroup, int, java.lang.Object);
+ method public deprecated void finishUpdate(android.view.ViewGroup);
+ method public abstract deprecated android.app.Fragment getItem(int);
+ method public deprecated long getItemId(int);
+ method public deprecated java.lang.Object instantiateItem(android.view.ViewGroup, int);
+ method public deprecated boolean isViewFromObject(android.view.View, java.lang.Object);
+ method public deprecated void restoreState(android.os.Parcelable, java.lang.ClassLoader);
+ method public deprecated android.os.Parcelable saveState();
+ method public deprecated void setPrimaryItem(android.view.ViewGroup, int, java.lang.Object);
+ method public deprecated void startUpdate(android.view.ViewGroup);
}
- public abstract class FragmentStatePagerAdapter extends android.support.v4.view.PagerAdapter {
- ctor public FragmentStatePagerAdapter(android.app.FragmentManager);
- method public abstract android.app.Fragment getItem(int);
- method public boolean isViewFromObject(android.view.View, java.lang.Object);
+ public abstract deprecated class FragmentStatePagerAdapter extends android.support.v4.view.PagerAdapter {
+ ctor public deprecated FragmentStatePagerAdapter(android.app.FragmentManager);
+ method public deprecated void destroyItem(android.view.ViewGroup, int, java.lang.Object);
+ method public deprecated void finishUpdate(android.view.ViewGroup);
+ method public abstract deprecated android.app.Fragment getItem(int);
+ method public deprecated java.lang.Object instantiateItem(android.view.ViewGroup, int);
+ method public deprecated boolean isViewFromObject(android.view.View, java.lang.Object);
+ method public deprecated void restoreState(android.os.Parcelable, java.lang.ClassLoader);
+ method public deprecated android.os.Parcelable saveState();
+ method public deprecated void setPrimaryItem(android.view.ViewGroup, int, java.lang.Object);
+ method public deprecated void startUpdate(android.view.ViewGroup);
}
- public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
- ctor public FragmentTabHost(android.content.Context);
- ctor public FragmentTabHost(android.content.Context, android.util.AttributeSet);
- method public void addTab(android.widget.TabHost.TabSpec, java.lang.Class<?>, android.os.Bundle);
- method public void onTabChanged(java.lang.String);
+ public deprecated class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+ ctor public deprecated FragmentTabHost(android.content.Context);
+ ctor public deprecated FragmentTabHost(android.content.Context, android.util.AttributeSet);
+ method public deprecated void addTab(android.widget.TabHost.TabSpec, java.lang.Class<?>, android.os.Bundle);
+ method protected deprecated void onAttachedToWindow();
+ method protected deprecated void onDetachedFromWindow();
+ method protected deprecated void onRestoreInstanceState(android.os.Parcelable);
+ method protected deprecated android.os.Parcelable onSaveInstanceState();
+ method public deprecated void onTabChanged(java.lang.String);
+ method public deprecated void setOnTabChangedListener(android.widget.TabHost.OnTabChangeListener);
method public deprecated void setup();
- method public void setup(android.content.Context, android.app.FragmentManager);
- method public void setup(android.content.Context, android.app.FragmentManager, int);
+ method public deprecated void setup(android.content.Context, android.app.FragmentManager);
+ method public deprecated void setup(android.content.Context, android.app.FragmentManager, int);
}
}
diff --git a/v13/build.gradle b/v13/build.gradle
index bd01c55..425a31f 100644
--- a/v13/build.gradle
+++ b/v13/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,13 +7,13 @@
}
dependencies {
- api project(':support-annotations')
- api project(':support-v4')
+ api(project(":support-annotations"))
+ api(project(":support-v4"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
}
android {
diff --git a/v13/java/android/support/v13/app/FragmentCompat.java b/v13/java/android/support/v13/app/FragmentCompat.java
index 31c2343..e8915fb 100644
--- a/v13/java/android/support/v13/app/FragmentCompat.java
+++ b/v13/java/android/support/v13/app/FragmentCompat.java
@@ -30,8 +30,19 @@
/**
* Helper for accessing features in {@link Fragment} in a backwards compatible fashion.
+ *
+ * @deprecated Use {@link android.support.v4.app.Fragment} instead of the framework fragment.
*/
+@Deprecated
public class FragmentCompat {
+
+ /**
+ * @deprecated Use {@link android.support.v4.app.Fragment} instead of the framework fragment.
+ */
+ @Deprecated
+ public FragmentCompat() {
+ }
+
interface FragmentCompatImpl {
void setUserVisibleHint(Fragment f, boolean deferStart);
void requestPermissions(Fragment fragment, String[] permissions, int requestCode);
@@ -48,7 +59,11 @@
* to the compatibility methods in this class will first check whether the delegate can
* handle the method call, and invoke the corresponding method if it can.
* </p>
+ *
+ * @deprecated Use {@link android.support.v4.app.Fragment} instead of the framework
+ * {@link Fragment}.
*/
+ @Deprecated
public interface PermissionCompatDelegate {
/**
@@ -66,7 +81,11 @@
*
* @return Whether the delegate has handled the permission request.
* @see FragmentCompat#requestPermissions(Fragment, String[], int)
+ *
+ * @deprecated Use {@link android.support.v4.app.Fragment} instead of the framework
+ * {@link Fragment}.
*/
+ @Deprecated
boolean requestPermissions(Fragment fragment, String[] permissions, int requestCode);
}
@@ -157,22 +176,34 @@
* delegate.
*
* @param delegate The delegate to be set. {@code null} to clear the set delegate.
+ *
+ * @deprecated Use {@link android.support.v4.app.Fragment} instead of the framework
+ * {@link Fragment}.
*/
+ @Deprecated
public static void setPermissionCompatDelegate(PermissionCompatDelegate delegate) {
sDelegate = delegate;
}
/**
* @hide
+ *
+ * @deprecated Use {@link android.support.v4.app.Fragment} instead of the framework
+ * {@link Fragment}.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @Deprecated
public static PermissionCompatDelegate getPermissionCompatDelegate() {
return sDelegate;
}
/**
* This interface is the contract for receiving the results for permission requests.
+ *
+ * @deprecated Use {@link android.support.v4.app.Fragment} instead of the framework
+ * {@link Fragment}.
*/
+ @Deprecated
public interface OnRequestPermissionsResultCallback {
/**
@@ -188,7 +219,11 @@
* or {@link android.content.pm.PackageManager#PERMISSION_DENIED}. Never null.
*
* @see #requestPermissions(android.app.Fragment, String[], int)
+ *
+ * @deprecated Use {@link android.support.v4.app.Fragment} instead of the framework
+ * {@link Fragment}.
*/
+ @Deprecated
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults);
}
@@ -197,7 +232,8 @@
* Call {@link Fragment#setMenuVisibility(boolean) Fragment.setMenuVisibility(boolean)}
* if running on an appropriate version of the platform.
*
- * @deprecated Use {@link Fragment#setMenuVisibility(boolean)} directly.
+ * @deprecated Use {@link android.support.v4.app.Fragment} instead of the framework
+ * {@link Fragment}.
*/
@Deprecated
public static void setMenuVisibility(Fragment f, boolean visible) {
@@ -207,7 +243,11 @@
/**
* Call {@link Fragment#setUserVisibleHint(boolean) setUserVisibleHint(boolean)}
* if running on an appropriate version of the platform.
+ *
+ * @deprecated Use {@link android.support.v4.app.Fragment} instead of the framework
+ * {@link Fragment}.
*/
+ @Deprecated
public static void setUserVisibleHint(Fragment f, boolean deferStart) {
IMPL.setUserVisibleHint(f, deferStart);
}
@@ -262,7 +302,11 @@
* @see android.support.v4.content.ContextCompat#checkSelfPermission(
* android.content.Context, String)
* @see #shouldShowRequestPermissionRationale(android.app.Fragment, String)
+ *
+ * @deprecated Use {@link android.support.v4.app.Fragment} instead of the framework
+ * {@link Fragment}.
*/
+ @Deprecated
public static void requestPermissions(@NonNull Fragment fragment,
@NonNull String[] permissions, int requestCode) {
if (sDelegate != null && sDelegate.requestPermissions(fragment, permissions, requestCode)) {
@@ -293,7 +337,11 @@
* @see android.support.v4.content.ContextCompat#checkSelfPermission(
* android.content.Context, String)
* @see #requestPermissions(android.app.Fragment, String[], int)
+ *
+ * @deprecated Use {@link android.support.v4.app.Fragment} instead of the framework
+ * {@link Fragment}.
*/
+ @Deprecated
public static boolean shouldShowRequestPermissionRationale(@NonNull Fragment fragment,
@NonNull String permission) {
return IMPL.shouldShowRequestPermissionRationale(fragment, permission);
diff --git a/v13/java/android/support/v13/app/FragmentPagerAdapter.java b/v13/java/android/support/v13/app/FragmentPagerAdapter.java
index e0b788a..112ed02 100644
--- a/v13/java/android/support/v13/app/FragmentPagerAdapter.java
+++ b/v13/java/android/support/v13/app/FragmentPagerAdapter.java
@@ -61,7 +61,10 @@
*
* {@sample frameworks/support/samples/Support13Demos/src/main/res/layout/fragment_pager_list.xml
* complete}
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentPagerAdapter} instead.
*/
+@Deprecated
public abstract class FragmentPagerAdapter extends PagerAdapter {
private static final String TAG = "FragmentPagerAdapter";
private static final boolean DEBUG = false;
@@ -70,15 +73,26 @@
private FragmentTransaction mCurTransaction = null;
private Fragment mCurrentPrimaryItem = null;
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentPagerAdapter} instead.
+ */
+ @Deprecated
public FragmentPagerAdapter(FragmentManager fm) {
mFragmentManager = fm;
}
/**
* Return the Fragment associated with a specified position.
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentPagerAdapter} instead.
*/
+ @Deprecated
public abstract Fragment getItem(int position);
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentPagerAdapter} instead.
+ */
+ @Deprecated
@Override
public void startUpdate(ViewGroup container) {
if (container.getId() == View.NO_ID) {
@@ -87,6 +101,10 @@
}
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentPagerAdapter} instead.
+ */
+ @Deprecated
@SuppressWarnings("ReferenceEquality")
@Override
public Object instantiateItem(ViewGroup container, int position) {
@@ -116,6 +134,10 @@
return fragment;
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentPagerAdapter} instead.
+ */
+ @Deprecated
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (mCurTransaction == null) {
@@ -126,6 +148,10 @@
mCurTransaction.detach((Fragment)object);
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentPagerAdapter} instead.
+ */
+ @Deprecated
@SuppressWarnings("ReferenceEquality")
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
@@ -143,6 +169,10 @@
}
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentPagerAdapter} instead.
+ */
+ @Deprecated
@Override
public void finishUpdate(ViewGroup container) {
if (mCurTransaction != null) {
@@ -152,16 +182,28 @@
}
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentPagerAdapter} instead.
+ */
+ @Deprecated
@Override
public boolean isViewFromObject(View view, Object object) {
return ((Fragment)object).getView() == view;
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentPagerAdapter} instead.
+ */
+ @Deprecated
@Override
public Parcelable saveState() {
return null;
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentPagerAdapter} instead.
+ */
+ @Deprecated
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
}
@@ -174,7 +216,10 @@
*
* @param position Position within this adapter
* @return Unique identifier for the item at position
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentPagerAdapter} instead.
*/
+ @Deprecated
public long getItemId(int position) {
return position;
}
diff --git a/v13/java/android/support/v13/app/FragmentStatePagerAdapter.java b/v13/java/android/support/v13/app/FragmentStatePagerAdapter.java
index 45a6bf5..76a3224 100644
--- a/v13/java/android/support/v13/app/FragmentStatePagerAdapter.java
+++ b/v13/java/android/support/v13/app/FragmentStatePagerAdapter.java
@@ -64,7 +64,10 @@
*
* {@sample frameworks/support/samples/Support4Demos/src/main/res/layout/fragment_pager_list.xml
* complete}
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentStatePagerAdapter} instead.
*/
+@Deprecated
public abstract class FragmentStatePagerAdapter extends PagerAdapter {
private static final String TAG = "FragStatePagerAdapter";
private static final boolean DEBUG = false;
@@ -76,15 +79,26 @@
private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
private Fragment mCurrentPrimaryItem = null;
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentStatePagerAdapter} instead.
+ */
+ @Deprecated
public FragmentStatePagerAdapter(FragmentManager fm) {
mFragmentManager = fm;
}
/**
* Return the Fragment associated with a specified position.
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentStatePagerAdapter} instead.
*/
+ @Deprecated
public abstract Fragment getItem(int position);
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentStatePagerAdapter} instead.
+ */
+ @Deprecated
@Override
public void startUpdate(ViewGroup container) {
if (container.getId() == View.NO_ID) {
@@ -93,6 +107,10 @@
}
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentStatePagerAdapter} instead.
+ */
+ @Deprecated
@Override
public Object instantiateItem(ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
@@ -129,6 +147,10 @@
return fragment;
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentStatePagerAdapter} instead.
+ */
+ @Deprecated
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment) object;
@@ -148,6 +170,10 @@
mCurTransaction.remove(fragment);
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentStatePagerAdapter} instead.
+ */
+ @Deprecated
@SuppressWarnings("ReferenceEquality")
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
@@ -165,6 +191,10 @@
}
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentStatePagerAdapter} instead.
+ */
+ @Deprecated
@Override
public void finishUpdate(ViewGroup container) {
if (mCurTransaction != null) {
@@ -174,11 +204,19 @@
}
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentStatePagerAdapter} instead.
+ */
+ @Deprecated
@Override
public boolean isViewFromObject(View view, Object object) {
return ((Fragment)object).getView() == view;
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentStatePagerAdapter} instead.
+ */
+ @Deprecated
@Override
public Parcelable saveState() {
Bundle state = null;
@@ -201,6 +239,10 @@
return state;
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentStatePagerAdapter} instead.
+ */
+ @Deprecated
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
if (state != null) {
diff --git a/v13/java/android/support/v13/app/FragmentTabHost.java b/v13/java/android/support/v13/app/FragmentTabHost.java
index 2326ccb..5c34ab5 100644
--- a/v13/java/android/support/v13/app/FragmentTabHost.java
+++ b/v13/java/android/support/v13/app/FragmentTabHost.java
@@ -38,7 +38,10 @@
* Version of {@link android.support.v4.app.FragmentTabHost} that can be
* used with the platform {@link android.app.Fragment} APIs. You will not
* normally use this, instead using action bar tabs.
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentTabHost} instead.
*/
+@Deprecated
public class FragmentTabHost extends TabHost implements TabHost.OnTabChangeListener {
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
private FrameLayout mRealTabContent;
@@ -117,6 +120,10 @@
};
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentTabHost} instead.
+ */
+ @Deprecated
public FragmentTabHost(Context context) {
// Note that we call through to the version that takes an AttributeSet,
// because the simple Context construct can result in a broken object!
@@ -124,6 +131,10 @@
initFragmentTabHost(context, null);
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentTabHost} instead.
+ */
+ @Deprecated
public FragmentTabHost(Context context, AttributeSet attrs) {
super(context, attrs);
initFragmentTabHost(context, attrs);
@@ -167,9 +178,7 @@
}
/**
- * @deprecated Don't call the original TabHost setup, you must instead
- * call {@link #setup(Context, FragmentManager)} or
- * {@link #setup(Context, FragmentManager, int)}.
+ * @deprecated Use {@link android.support.v4.app.FragmentTabHost} instead.
*/
@Override
@Deprecated
@@ -178,6 +187,10 @@
"Must call setup() that takes a Context and FragmentManager");
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentTabHost} instead.
+ */
+ @Deprecated
public void setup(Context context, FragmentManager manager) {
ensureHierarchy(context); // Ensure views required by super.setup()
super.setup();
@@ -186,6 +199,10 @@
ensureContent();
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentTabHost} instead.
+ */
+ @Deprecated
public void setup(Context context, FragmentManager manager, int containerId) {
ensureHierarchy(context); // Ensure views required by super.setup()
super.setup();
@@ -212,11 +229,19 @@
}
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentTabHost} instead.
+ */
+ @Deprecated
@Override
public void setOnTabChangedListener(OnTabChangeListener l) {
mOnTabChangeListener = l;
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentTabHost} instead.
+ */
+ @Deprecated
public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
tabSpec.setContent(new DummyTabFactory(mContext));
String tag = tabSpec.getTag();
@@ -239,6 +264,10 @@
addTab(tabSpec);
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentTabHost} instead.
+ */
+ @Deprecated
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
@@ -278,12 +307,20 @@
}
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentTabHost} instead.
+ */
+ @Deprecated
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mAttached = false;
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentTabHost} instead.
+ */
+ @Deprecated
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
@@ -292,6 +329,10 @@
return ss;
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentTabHost} instead.
+ */
+ @Deprecated
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
@@ -303,6 +344,10 @@
setCurrentTabByTag(ss.curTab);
}
+ /**
+ * @deprecated Use {@link android.support.v4.app.FragmentTabHost} instead.
+ */
+ @Deprecated
@Override
public void onTabChanged(String tabId) {
if (mAttached) {
diff --git a/v13/java/android/support/v13/app/package.html b/v13/java/android/support/v13/app/package.html
deleted file mode 100755
index 3557ecb..0000000
--- a/v13/java/android/support/v13/app/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<body>
-
-Support classes to access some of the android.app package features introduced after API level 13 in a backwards compatible fashion.
-
-</body>
diff --git a/v13/lint-baseline.xml b/v13/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/v13/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/v14/preference/api/current.txt b/v14/preference/api/current.txt
index b92ccf9..af3db09 100644
--- a/v14/preference/api/current.txt
+++ b/v14/preference/api/current.txt
@@ -46,7 +46,7 @@
field protected static final java.lang.String ARG_KEY = "key";
}
- public abstract class PreferenceFragment extends android.app.Fragment implements android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
+ public abstract class PreferenceFragment extends android.app.Fragment implements android.support.v7.preference.DialogPreference.TargetFragment android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
ctor public PreferenceFragment();
method public void addPreferencesFromResource(int);
method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
diff --git a/v14/preference/build.gradle b/v14/preference/build.gradle
index f68379a..c129cba 100644
--- a/v14/preference/build.gradle
+++ b/v14/preference/build.gradle
@@ -22,10 +22,10 @@
}
dependencies {
- api project(':support-v4')
- api project(':appcompat-v7')
- api project(':recyclerview-v7')
- api project(':preference-v7')
+ api(project(":support-v4"))
+ api(project(":appcompat-v7"))
+ api(project(":recyclerview-v7"))
+ api(project(":preference-v7"))
}
android {
diff --git a/v14/preference/res/layout-v17/preference_category_material.xml b/v14/preference/res/layout-v17/preference_category_material.xml
index 804da6a..db3abfe 100644
--- a/v14/preference/res/layout-v17/preference_category_material.xml
+++ b/v14/preference/res/layout-v17/preference_category_material.xml
@@ -15,49 +15,13 @@
~ limitations under the License
-->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"
- android:layout_marginTop="8dp"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart">
-
- <LinearLayout
- android:id="@+id/icon_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="start|center_vertical"
- android:orientation="horizontal">
- <android.support.v7.internal.widget.PreferenceImageView
- android:id="@android:id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:maxHeight="18dp"
- app:maxWidth="18dp"/>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingStart="56dp">
- <TextView
- android:id="@android:id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:textAlignment="viewStart"
- android:textColor="@color/preference_fallback_accent_color"/>
- <TextView
- android:id="@android:id/summary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="end"
- android:singleLine="true"
- android:textColor="?android:attr/textColorSecondary"/>
- </LinearLayout>
-
-</FrameLayout>
+ android:layout_marginBottom="16dip"
+ android:textAppearance="@style/Preference_TextAppearanceMaterialBody2"
+ android:textColor="@color/preference_fallback_accent_color"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingTop="16dip" />
diff --git a/v14/preference/res/layout-v21/preference_category_material.xml b/v14/preference/res/layout-v21/preference_category_material.xml
index 1331268..dad9a5c 100644
--- a/v14/preference/res/layout-v21/preference_category_material.xml
+++ b/v14/preference/res/layout-v21/preference_category_material.xml
@@ -15,52 +15,13 @@
~ limitations under the License
-->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"
- android:layout_marginTop="8dp"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart">
-
- <LinearLayout
- android:id="@+id/icon_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="start|center_vertical"
- android:orientation="horizontal">
- <android.support.v7.internal.widget.PreferenceImageView
- android:id="@android:id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:maxHeight="18dp"
- app:maxWidth="18dp"
- android:tint="?android:attr/textColorPrimary"/>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingStart="56dp">
- <TextView
- android:id="@android:id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:textAlignment="viewStart"
- android:textAppearance="@android:style/TextAppearance.Material.Body2"
- android:textColor="?android:attr/colorAccent"/>
- <TextView
- android:id="@android:id/summary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="end"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceListItemSecondary"
- android:textColor="?android:attr/textColorSecondary"/>
- </LinearLayout>
-
-</FrameLayout>
+ android:layout_marginBottom="16dip"
+ android:textAppearance="@android:style/TextAppearance.Material.Body2"
+ android:textColor="?android:attr/colorAccent"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingTop="16dip" />
diff --git a/v14/preference/res/layout-v21/preference_dropdown_material.xml b/v14/preference/res/layout-v21/preference_dropdown_material.xml
index f886d88..a92095e 100644
--- a/v14/preference/res/layout-v21/preference_dropdown_material.xml
+++ b/v14/preference/res/layout-v21/preference_dropdown_material.xml
@@ -15,18 +15,74 @@
~ limitations under the License
-->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:gravity="center_vertical"
+ android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+ android:paddingRight="?android:attr/listPreferredItemPaddingRight"
+ android:background="?android:attr/selectableItemBackground"
+ android:clipToPadding="false"
+ android:focusable="true" >
<Spinner
android:id="@+id/spinner"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/preference_no_icon_padding_start"
android:visibility="invisible" />
- <include layout="@layout/preference_material"/>
+ <LinearLayout
+ android:id="@+id/icon_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="-4dp"
+ android:minWidth="60dp"
+ android:gravity="start|center_vertical"
+ android:orientation="horizontal"
+ android:paddingRight="12dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp">
+ <android.support.v7.internal.widget.PreferenceImageView
+ android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:maxWidth="48dp"
+ app:maxHeight="48dp" />
+ </LinearLayout>
-</FrameLayout>
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp">
+
+ <TextView android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="@style/Preference_TextAppearanceMaterialSubhead"
+ android:ellipsize="marquee" />
+
+ <TextView android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_alignStart="@android:id/title"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="10" />
+
+ </RelativeLayout>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="end|center_vertical"
+ android:paddingLeft="16dp"
+ android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/v14/preference/res/layout-v21/preference_material.xml b/v14/preference/res/layout-v21/preference_material.xml
index da6b69f..c3000f9 100644
--- a/v14/preference/res/layout-v21/preference_material.xml
+++ b/v14/preference/res/layout-v21/preference_material.xml
@@ -31,11 +31,10 @@
android:id="@+id/icon_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="-4dp"
- android:minWidth="60dp"
+ android:minWidth="56dp"
android:gravity="start|center_vertical"
android:orientation="horizontal"
- android:paddingEnd="12dp"
+ android:paddingEnd="8dp"
android:paddingTop="4dp"
android:paddingBottom="4dp">
<android.support.v7.internal.widget.PreferenceImageView
@@ -66,6 +65,7 @@
android:layout_below="@android:id/title"
android:layout_alignStart="@android:id/title"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+ android:textAlignment="viewStart"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="10" />
diff --git a/v14/preference/res/layout/preference_category_material.xml b/v14/preference/res/layout/preference_category_material.xml
index 8eb2137..e366e7a 100644
--- a/v14/preference/res/layout/preference_category_material.xml
+++ b/v14/preference/res/layout/preference_category_material.xml
@@ -15,49 +15,13 @@
~ limitations under the License
-->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"
- android:layout_marginTop="8dp"
- android:paddingLeft="?android:attr/listPreferredItemPaddingLeft">
-
- <LinearLayout
- android:id="@+id/icon_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="start|center_vertical"
- android:orientation="horizontal">
- <android.support.v7.internal.widget.PreferenceImageView
- android:id="@android:id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:maxHeight="18dp"
- app:maxWidth="18dp"/>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingLeft="56dp">
- <TextView
- android:id="@android:id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- android:paddingRight="?android:attr/listPreferredItemPaddingRight"
- android:textAlignment="viewStart"
- android:textColor="@color/preference_fallback_accent_color"/>
- <TextView
- android:id="@android:id/summary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="end"
- android:singleLine="true"
- android:textColor="?android:attr/textColorSecondary"/>
- </LinearLayout>
-
-</FrameLayout>
+ android:layout_marginBottom="16dip"
+ android:textAppearance="@style/Preference_TextAppearanceMaterialBody2"
+ android:textColor="@color/preference_fallback_accent_color"
+ android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+ android:paddingRight="?android:attr/listPreferredItemPaddingRight"
+ android:paddingTop="16dip" />
diff --git a/v14/preference/res/values/styles.xml b/v14/preference/res/values/styles.xml
index edd5285..26b1544 100644
--- a/v14/preference/res/values/styles.xml
+++ b/v14/preference/res/values/styles.xml
@@ -24,10 +24,6 @@
<style name="Preference.Material">
<item name="android:layout">@layout/preference_material</item>
- <item name="allowDividerAbove">false</item>
- <item name="allowDividerBelow">true</item>
- <item name="singleLineTitle">false</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference.Information.Material">
@@ -38,16 +34,10 @@
<style name="Preference.Category.Material">
<item name="android:layout">@layout/preference_category_material</item>
- <item name="allowDividerAbove">true</item>
- <item name="allowDividerBelow">true</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference.CheckBoxPreference.Material">
<item name="android:layout">@layout/preference_material</item>
- <item name="allowDividerAbove">false</item>
- <item name="allowDividerBelow">true</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference.SwitchPreferenceCompat.Material">
@@ -56,10 +46,6 @@
<style name="Preference.SwitchPreference.Material">
<item name="android:layout">@layout/preference_material</item>
- <item name="allowDividerAbove">false</item>
- <item name="allowDividerBelow">true</item>
- <item name="singleLineTitle">false</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference.SeekBarPreference.Material">
@@ -70,31 +56,18 @@
<style name="Preference.PreferenceScreen.Material">
<item name="android:layout">@layout/preference_material</item>
- <item name="allowDividerAbove">false</item>
- <item name="allowDividerBelow">true</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference.DialogPreference.Material">
<item name="android:layout">@layout/preference_material</item>
- <item name="allowDividerAbove">false</item>
- <item name="allowDividerBelow">true</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference.DialogPreference.EditTextPreference.Material">
<item name="android:layout">@layout/preference_material</item>
- <item name="allowDividerAbove">false</item>
- <item name="allowDividerBelow">true</item>
- <item name="singleLineTitle">false</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference.DropDown.Material">
<item name="android:layout">@layout/preference_dropdown_material</item>
- <item name="allowDividerAbove">false</item>
- <item name="allowDividerBelow">true</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference_TextAppearanceMaterialBody2">
@@ -113,7 +86,6 @@
<style name="PreferenceFragment.Material">
<item name="android:divider">@drawable/preference_list_divider_material</item>
- <item name="allowDividerAfterLastItem">false</item>
</style>
<style name="PreferenceFragmentList.Material">
diff --git a/v14/preference/res/values/themes.xml b/v14/preference/res/values/themes.xml
index 919873e..a69126f 100644
--- a/v14/preference/res/values/themes.xml
+++ b/v14/preference/res/values/themes.xml
@@ -36,6 +36,5 @@
<item name="editTextPreferenceStyle">@style/Preference.DialogPreference.EditTextPreference.Material</item>
<item name="dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
<item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Material</item>
- <item name="android:scrollbars">vertical</item>
</style>
</resources>
diff --git a/v4/build.gradle b/v4/build.gradle
index 0a17101..ac5a9f5 100644
--- a/v4/build.gradle
+++ b/v4/build.gradle
@@ -6,11 +6,11 @@
}
dependencies {
- api project(':support-compat')
- api project(':support-media-compat')
- api project(':support-core-utils')
- api project(':support-core-ui')
- api project(':support-fragment')
+ api(project(":support-compat"))
+ api(project(":support-media-compat"))
+ api(project(":support-core-utils"))
+ api(project(":support-core-ui"))
+ api(project(":support-fragment"))
}
android {
diff --git a/v4/lint-baseline.xml b/v4/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/v4/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/v7/appcompat/api/27.0.0.ignore b/v7/appcompat/api/27.0.0.ignore
new file mode 100644
index 0000000..97cc753
--- /dev/null
+++ b/v7/appcompat/api/27.0.0.ignore
@@ -0,0 +1,2 @@
+b0b1638
+dfaf9f5
diff --git a/v7/appcompat/api/current.txt b/v7/appcompat/api/current.txt
index d39b109..5d4fa6e 100644
--- a/v7/appcompat/api/current.txt
+++ b/v7/appcompat/api/current.txt
@@ -161,6 +161,7 @@
method public android.widget.ListView getListView();
method public void setButton(int, java.lang.CharSequence, android.os.Message);
method public void setButton(int, java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+ method public void setButton(int, java.lang.CharSequence, android.graphics.drawable.Drawable, android.content.DialogInterface.OnClickListener);
method public void setCustomTitle(android.view.View);
method public void setIcon(int);
method public void setIcon(android.graphics.drawable.Drawable);
@@ -192,14 +193,17 @@
method public android.support.v7.app.AlertDialog.Builder setMultiChoiceItems(android.database.Cursor, java.lang.String, java.lang.String, android.content.DialogInterface.OnMultiChoiceClickListener);
method public android.support.v7.app.AlertDialog.Builder setNegativeButton(int, android.content.DialogInterface.OnClickListener);
method public android.support.v7.app.AlertDialog.Builder setNegativeButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setNegativeButtonIcon(android.graphics.drawable.Drawable);
method public android.support.v7.app.AlertDialog.Builder setNeutralButton(int, android.content.DialogInterface.OnClickListener);
method public android.support.v7.app.AlertDialog.Builder setNeutralButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setNeutralButtonIcon(android.graphics.drawable.Drawable);
method public android.support.v7.app.AlertDialog.Builder setOnCancelListener(android.content.DialogInterface.OnCancelListener);
method public android.support.v7.app.AlertDialog.Builder setOnDismissListener(android.content.DialogInterface.OnDismissListener);
method public android.support.v7.app.AlertDialog.Builder setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
method public android.support.v7.app.AlertDialog.Builder setOnKeyListener(android.content.DialogInterface.OnKeyListener);
method public android.support.v7.app.AlertDialog.Builder setPositiveButton(int, android.content.DialogInterface.OnClickListener);
method public android.support.v7.app.AlertDialog.Builder setPositiveButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setPositiveButtonIcon(android.graphics.drawable.Drawable);
method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(int, int, android.content.DialogInterface.OnClickListener);
method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(android.database.Cursor, int, java.lang.String, android.content.DialogInterface.OnClickListener);
method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(java.lang.CharSequence[], int, android.content.DialogInterface.OnClickListener);
@@ -211,7 +215,7 @@
method public android.support.v7.app.AlertDialog show();
}
- public class AppCompatActivity extends android.support.v4.app.FragmentActivity implements android.support.v7.app.ActionBarDrawerToggle.DelegateProvider android.support.v7.app.AppCompatCallback {
+ public class AppCompatActivity extends android.support.v4.app.FragmentActivity implements android.support.v7.app.ActionBarDrawerToggle.DelegateProvider android.support.v7.app.AppCompatCallback android.support.v4.app.TaskStackBuilder.SupportParentable {
ctor public AppCompatActivity();
method public android.support.v7.app.AppCompatDelegate getDelegate();
method public android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
@@ -403,6 +407,15 @@
method public abstract void onActionViewExpanded();
}
+ public class ContextThemeWrapper extends android.content.ContextWrapper {
+ ctor public ContextThemeWrapper();
+ ctor public ContextThemeWrapper(android.content.Context, int);
+ ctor public ContextThemeWrapper(android.content.Context, android.content.res.Resources.Theme);
+ method public void applyOverrideConfiguration(android.content.res.Configuration);
+ method public int getThemeResId();
+ method protected void onApplyThemeResource(android.content.res.Resources.Theme, int, boolean);
+ }
+
}
package android.support.v7.widget {
@@ -443,27 +456,41 @@
method public abstract boolean onMenuItemClick(android.view.MenuItem);
}
- public class AppCompatAutoCompleteTextView extends android.widget.AutoCompleteTextView {
+ public class AppCompatAutoCompleteTextView extends android.widget.AutoCompleteTextView implements android.support.v4.view.TintableBackgroundView {
ctor public AppCompatAutoCompleteTextView(android.content.Context);
ctor public AppCompatAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
ctor public AppCompatAutoCompleteTextView(android.content.Context, android.util.AttributeSet, int);
+ method public android.content.res.ColorStateList getSupportBackgroundTintList();
+ method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
+ method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
method public void setTextAppearance(android.content.Context, int);
}
- public class AppCompatButton extends android.widget.Button {
+ public class AppCompatButton extends android.widget.Button implements android.support.v4.widget.AutoSizeableTextView android.support.v4.view.TintableBackgroundView {
ctor public AppCompatButton(android.content.Context);
ctor public AppCompatButton(android.content.Context, android.util.AttributeSet);
ctor public AppCompatButton(android.content.Context, android.util.AttributeSet, int);
+ method public android.content.res.ColorStateList getSupportBackgroundTintList();
+ method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
+ method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int) throws java.lang.IllegalArgumentException;
+ method public void setAutoSizeTextTypeUniformWithPresetSizes(int[], int) throws java.lang.IllegalArgumentException;
method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
method public void setSupportAllCaps(boolean);
+ method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
+ method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
method public void setTextAppearance(android.content.Context, int);
}
- public class AppCompatCheckBox extends android.widget.CheckBox {
+ public class AppCompatCheckBox extends android.widget.CheckBox implements android.support.v4.widget.TintableCompoundButton {
ctor public AppCompatCheckBox(android.content.Context);
ctor public AppCompatCheckBox(android.content.Context, android.util.AttributeSet);
ctor public AppCompatCheckBox(android.content.Context, android.util.AttributeSet, int);
+ method public android.content.res.ColorStateList getSupportButtonTintList();
+ method public android.graphics.PorterDuff.Mode getSupportButtonTintMode();
+ method public void setSupportButtonTintList(android.content.res.ColorStateList);
+ method public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode);
}
public class AppCompatCheckedTextView extends android.widget.CheckedTextView {
@@ -473,40 +500,68 @@
method public void setTextAppearance(android.content.Context, int);
}
- public class AppCompatEditText extends android.widget.EditText {
+ public class AppCompatEditText extends android.widget.EditText implements android.support.v4.view.TintableBackgroundView {
ctor public AppCompatEditText(android.content.Context);
ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet);
ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet, int);
+ method public android.content.res.ColorStateList getSupportBackgroundTintList();
+ method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
+ method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
method public void setTextAppearance(android.content.Context, int);
}
- public class AppCompatImageButton extends android.widget.ImageButton {
+ public class AppCompatImageButton extends android.widget.ImageButton implements android.support.v4.view.TintableBackgroundView android.support.v4.widget.TintableImageSourceView {
ctor public AppCompatImageButton(android.content.Context);
ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet);
ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet, int);
+ method public android.content.res.ColorStateList getSupportBackgroundTintList();
+ method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
+ method public android.content.res.ColorStateList getSupportImageTintList();
+ method public android.graphics.PorterDuff.Mode getSupportImageTintMode();
method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
+ method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
+ method public void setSupportImageTintList(android.content.res.ColorStateList);
+ method public void setSupportImageTintMode(android.graphics.PorterDuff.Mode);
}
- public class AppCompatImageView extends android.widget.ImageView {
+ public class AppCompatImageView extends android.widget.ImageView implements android.support.v4.view.TintableBackgroundView android.support.v4.widget.TintableImageSourceView {
ctor public AppCompatImageView(android.content.Context);
ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet);
ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet, int);
+ method public android.content.res.ColorStateList getSupportBackgroundTintList();
+ method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
+ method public android.content.res.ColorStateList getSupportImageTintList();
+ method public android.graphics.PorterDuff.Mode getSupportImageTintMode();
method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
+ method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
+ method public void setSupportImageTintList(android.content.res.ColorStateList);
+ method public void setSupportImageTintMode(android.graphics.PorterDuff.Mode);
}
- public class AppCompatMultiAutoCompleteTextView extends android.widget.MultiAutoCompleteTextView {
+ public class AppCompatMultiAutoCompleteTextView extends android.widget.MultiAutoCompleteTextView implements android.support.v4.view.TintableBackgroundView {
ctor public AppCompatMultiAutoCompleteTextView(android.content.Context);
ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet, int);
+ method public android.content.res.ColorStateList getSupportBackgroundTintList();
+ method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
+ method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
method public void setTextAppearance(android.content.Context, int);
}
- public class AppCompatRadioButton extends android.widget.RadioButton {
+ public class AppCompatRadioButton extends android.widget.RadioButton implements android.support.v4.widget.TintableCompoundButton {
ctor public AppCompatRadioButton(android.content.Context);
ctor public AppCompatRadioButton(android.content.Context, android.util.AttributeSet);
ctor public AppCompatRadioButton(android.content.Context, android.util.AttributeSet, int);
+ method public android.content.res.ColorStateList getSupportButtonTintList();
+ method public android.graphics.PorterDuff.Mode getSupportButtonTintMode();
+ method public void setSupportButtonTintList(android.content.res.ColorStateList);
+ method public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode);
}
public class AppCompatRatingBar extends android.widget.RatingBar {
@@ -521,21 +576,31 @@
ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet, int);
}
- public class AppCompatSpinner extends android.widget.Spinner {
+ public class AppCompatSpinner extends android.widget.Spinner implements android.support.v4.view.TintableBackgroundView {
ctor public AppCompatSpinner(android.content.Context);
ctor public AppCompatSpinner(android.content.Context, int);
ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet);
ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int);
ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int, int);
ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int, int, android.content.res.Resources.Theme);
+ method public android.content.res.ColorStateList getSupportBackgroundTintList();
+ method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
+ method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
}
- public class AppCompatTextView extends android.widget.TextView {
+ public class AppCompatTextView extends android.widget.TextView implements android.support.v4.widget.AutoSizeableTextView android.support.v4.view.TintableBackgroundView {
ctor public AppCompatTextView(android.content.Context);
ctor public AppCompatTextView(android.content.Context, android.util.AttributeSet);
ctor public AppCompatTextView(android.content.Context, android.util.AttributeSet, int);
+ method public android.content.res.ColorStateList getSupportBackgroundTintList();
+ method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
+ method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int) throws java.lang.IllegalArgumentException;
+ method public void setAutoSizeTextTypeUniformWithPresetSizes(int[], int) throws java.lang.IllegalArgumentException;
method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
+ method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
method public void setTextAppearance(android.content.Context, int);
}
@@ -555,7 +620,6 @@
method public float getWeightSum();
method public boolean isBaselineAligned();
method public boolean isMeasureWithLargestChildEnabled();
- method protected void onLayout(boolean, int, int, int, int);
method public void setBaselineAligned(boolean);
method public void setBaselineAlignedChildIndex(int);
method public void setDividerDrawable(android.graphics.drawable.Drawable);
@@ -819,7 +883,6 @@
method public boolean hideOverflowMenu();
method public void inflateMenu(int);
method public boolean isOverflowMenuShowing();
- method protected void onLayout(boolean, int, int, int, int);
method public void setContentInsetEndWithActions(int);
method public void setContentInsetStartWithNavigation(int);
method public void setContentInsetsAbsolute(int, int);
diff --git a/v7/appcompat/build.gradle b/v7/appcompat/build.gradle
index 8e242cc..a3b80a8 100644
--- a/v7/appcompat/build.gradle
+++ b/v7/appcompat/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,16 +7,16 @@
}
dependencies {
- api project(':support-annotations')
- api project(':support-core-utils')
- api project(':support-fragment')
- api project(':support-vector-drawable')
- api project(':animated-vector-drawable')
+ api(project(":support-annotations"))
+ api(project(":support-core-utils"))
+ api(project(":support-fragment"))
+ api(project(":support-vector-drawable"))
+ api(project(":animated-vector-drawable"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation project(':support-testutils'), {
exclude group: 'com.android.support', module: 'appcompat-v7'
}
@@ -23,7 +24,7 @@
android {
defaultConfig {
- minSdkVersion 14
+ minSdkVersion(14)
// This disables the builds tools automatic vector -> PNG generation
generatedDensities = []
}
diff --git a/v7/appcompat/lint-baseline.xml b/v7/appcompat/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/v7/appcompat/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/v7/appcompat/res/values/attrs.xml b/v7/appcompat/res/values/attrs.xml
index 2012a3a..c48b7ba 100644
--- a/v7/appcompat/res/values/attrs.xml
+++ b/v7/appcompat/res/values/attrs.xml
@@ -1140,6 +1140,7 @@
<attr name="singleChoiceItemLayout" format="reference" />
<attr name="listItemLayout" format="reference" />
<attr name="showTitle" format="boolean" />
+ <attr name="buttonIconDimen" format="dimension" />
</declare-styleable>
<!-- @hide -->
diff --git a/v7/appcompat/res/values/dimens.xml b/v7/appcompat/res/values/dimens.xml
index a02b7c0..5bcd4b4 100644
--- a/v7/appcompat/res/values/dimens.xml
+++ b/v7/appcompat/res/values/dimens.xml
@@ -95,6 +95,9 @@
<!-- Minimum "smallest width" of the display for cascading menus to be enabled. -->
<dimen name="abc_cascading_menus_min_smallest_width">720dp</dimen>
+ <!-- Dimension of the AlertDialog button icon -->
+ <dimen name="abc_alert_dialog_button_dimen">48dp</dimen>
+
<!-- Tooltip dimensions. -->
<!-- Vertical offset from the edge of the anchor view for a touch-triggered tooltip. -->
<dimen name="tooltip_y_offset_touch">16dp</dimen>
diff --git a/v7/appcompat/res/values/styles_base.xml b/v7/appcompat/res/values/styles_base.xml
index adaaae0..c1aa3a7 100644
--- a/v7/appcompat/res/values/styles_base.xml
+++ b/v7/appcompat/res/values/styles_base.xml
@@ -520,6 +520,7 @@
<item name="listItemLayout">@layout/select_dialog_item_material</item>
<item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_material</item>
<item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_material</item>
+ <item name="buttonIconDimen">@dimen/abc_alert_dialog_button_dimen</item>
</style>
<style name="Base.AlertDialog.AppCompat.Light" parent="Base.AlertDialog.AppCompat" />
diff --git a/v7/appcompat/src/main/java/android/support/v7/app/AlertController.java b/v7/appcompat/src/main/java/android/support/v7/app/AlertController.java
index 5ff4537..01bc449 100644
--- a/v7/appcompat/src/main/java/android/support/v7/app/AlertController.java
+++ b/v7/appcompat/src/main/java/android/support/v7/app/AlertController.java
@@ -65,6 +65,7 @@
private final Context mContext;
final AppCompatDialog mDialog;
private final Window mWindow;
+ private final int mButtonIconDimen;
private CharSequence mTitle;
private CharSequence mMessage;
@@ -82,14 +83,17 @@
Button mButtonPositive;
private CharSequence mButtonPositiveText;
Message mButtonPositiveMessage;
+ private Drawable mButtonPositiveIcon;
Button mButtonNegative;
private CharSequence mButtonNegativeText;
Message mButtonNegativeMessage;
+ private Drawable mButtonNegativeIcon;
Button mButtonNeutral;
private CharSequence mButtonNeutralText;
Message mButtonNeutralMessage;
+ private Drawable mButtonNeutralIcon;
NestedScrollView mScrollView;
@@ -192,6 +196,7 @@
.getResourceId(R.styleable.AlertDialog_singleChoiceItemLayout, 0);
mListItemLayout = a.getResourceId(R.styleable.AlertDialog_listItemLayout, 0);
mShowTitle = a.getBoolean(R.styleable.AlertDialog_showTitle, true);
+ mButtonIconDimen = a.getDimensionPixelSize(R.styleable.AlertDialog_buttonIconDimen, 0);
a.recycle();
@@ -298,8 +303,8 @@
}
/**
- * Sets a click listener or a message to be sent when the button is clicked.
- * You only need to pass one of {@code listener} or {@code msg}.
+ * Sets an icon, a click listener or a message to be sent when the button is clicked.
+ * You only need to pass one of {@code icon}, {@code listener} or {@code msg}.
*
* @param whichButton Which button, can be one of
* {@link DialogInterface#BUTTON_POSITIVE},
@@ -308,9 +313,11 @@
* @param text The text to display in positive button.
* @param listener The {@link DialogInterface.OnClickListener} to use.
* @param msg The {@link Message} to be sent when clicked.
+ * @param icon The (@link Drawable) to be used as an icon for the button.
+ *
*/
public void setButton(int whichButton, CharSequence text,
- DialogInterface.OnClickListener listener, Message msg) {
+ DialogInterface.OnClickListener listener, Message msg, Drawable icon) {
if (msg == null && listener != null) {
msg = mHandler.obtainMessage(whichButton, listener);
@@ -321,16 +328,19 @@
case DialogInterface.BUTTON_POSITIVE:
mButtonPositiveText = text;
mButtonPositiveMessage = msg;
+ mButtonPositiveIcon = icon;
break;
case DialogInterface.BUTTON_NEGATIVE:
mButtonNegativeText = text;
mButtonNegativeMessage = msg;
+ mButtonNegativeIcon = icon;
break;
case DialogInterface.BUTTON_NEUTRAL:
mButtonNeutralText = text;
mButtonNeutralMessage = msg;
+ mButtonNeutralIcon = icon;
break;
default:
@@ -752,35 +762,45 @@
mButtonPositive = (Button) buttonPanel.findViewById(android.R.id.button1);
mButtonPositive.setOnClickListener(mButtonHandler);
- if (TextUtils.isEmpty(mButtonPositiveText)) {
+ if (TextUtils.isEmpty(mButtonPositiveText) && mButtonPositiveIcon == null) {
mButtonPositive.setVisibility(View.GONE);
} else {
mButtonPositive.setText(mButtonPositiveText);
+ if (mButtonPositiveIcon != null) {
+ mButtonPositiveIcon.setBounds(0, 0, mButtonIconDimen, mButtonIconDimen);
+ mButtonPositive.setCompoundDrawables(mButtonPositiveIcon, null, null, null);
+ }
mButtonPositive.setVisibility(View.VISIBLE);
whichButtons = whichButtons | BIT_BUTTON_POSITIVE;
}
- mButtonNegative = (Button) buttonPanel.findViewById(android.R.id.button2);
+ mButtonNegative = buttonPanel.findViewById(android.R.id.button2);
mButtonNegative.setOnClickListener(mButtonHandler);
- if (TextUtils.isEmpty(mButtonNegativeText)) {
+ if (TextUtils.isEmpty(mButtonNegativeText) && mButtonNegativeIcon == null) {
mButtonNegative.setVisibility(View.GONE);
} else {
mButtonNegative.setText(mButtonNegativeText);
+ if (mButtonNegativeIcon != null) {
+ mButtonNegativeIcon.setBounds(0, 0, mButtonIconDimen, mButtonIconDimen);
+ mButtonNegative.setCompoundDrawables(mButtonNegativeIcon, null, null, null);
+ }
mButtonNegative.setVisibility(View.VISIBLE);
-
whichButtons = whichButtons | BIT_BUTTON_NEGATIVE;
}
mButtonNeutral = (Button) buttonPanel.findViewById(android.R.id.button3);
mButtonNeutral.setOnClickListener(mButtonHandler);
- if (TextUtils.isEmpty(mButtonNeutralText)) {
+ if (TextUtils.isEmpty(mButtonNeutralText) && mButtonNeutralIcon == null) {
mButtonNeutral.setVisibility(View.GONE);
} else {
mButtonNeutral.setText(mButtonNeutralText);
+ if (mButtonPositiveIcon != null) {
+ mButtonPositiveIcon.setBounds(0, 0, mButtonIconDimen, mButtonIconDimen);
+ mButtonPositive.setCompoundDrawables(mButtonPositiveIcon, null, null, null);
+ }
mButtonNeutral.setVisibility(View.VISIBLE);
-
whichButtons = whichButtons | BIT_BUTTON_NEUTRAL;
}
@@ -852,10 +872,13 @@
public View mCustomTitleView;
public CharSequence mMessage;
public CharSequence mPositiveButtonText;
+ public Drawable mPositiveButtonIcon;
public DialogInterface.OnClickListener mPositiveButtonListener;
public CharSequence mNegativeButtonText;
+ public Drawable mNegativeButtonIcon;
public DialogInterface.OnClickListener mNegativeButtonListener;
public CharSequence mNeutralButtonText;
+ public Drawable mNeutralButtonIcon;
public DialogInterface.OnClickListener mNeutralButtonListener;
public boolean mCancelable;
public DialogInterface.OnCancelListener mOnCancelListener;
@@ -923,17 +946,17 @@
if (mMessage != null) {
dialog.setMessage(mMessage);
}
- if (mPositiveButtonText != null) {
+ if (mPositiveButtonText != null || mPositiveButtonIcon != null) {
dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
- mPositiveButtonListener, null);
+ mPositiveButtonListener, null, mPositiveButtonIcon);
}
- if (mNegativeButtonText != null) {
+ if (mNegativeButtonText != null || mNegativeButtonIcon != null) {
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
- mNegativeButtonListener, null);
+ mNegativeButtonListener, null, mNegativeButtonIcon);
}
- if (mNeutralButtonText != null) {
+ if (mNeutralButtonText != null || mNeutralButtonIcon != null) {
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
- mNeutralButtonListener, null);
+ mNeutralButtonListener, null, mNeutralButtonIcon);
}
// For a list, the client can either supply an array of items or an
// adapter or a cursor
diff --git a/v7/appcompat/src/main/java/android/support/v7/app/AlertDialog.java b/v7/appcompat/src/main/java/android/support/v7/app/AlertDialog.java
index 4b87dcc..1712f20 100644
--- a/v7/appcompat/src/main/java/android/support/v7/app/AlertDialog.java
+++ b/v7/appcompat/src/main/java/android/support/v7/app/AlertDialog.java
@@ -207,7 +207,7 @@
* @param msg The {@link Message} to be sent when clicked.
*/
public void setButton(int whichButton, CharSequence text, Message msg) {
- mAlert.setButton(whichButton, text, null, msg);
+ mAlert.setButton(whichButton, text, null, msg, null);
}
/**
@@ -222,7 +222,25 @@
* @param listener The {@link DialogInterface.OnClickListener} to use.
*/
public void setButton(int whichButton, CharSequence text, OnClickListener listener) {
- mAlert.setButton(whichButton, text, listener, null);
+ mAlert.setButton(whichButton, text, listener, null, null);
+ }
+
+ /**
+ * Sets an icon to be displayed along with the button text and a listener to be invoked when
+ * the positive button of the dialog is pressed. This method has no effect if called after
+ * {@link #show()}.
+ *
+ * @param whichButton Which button to set the listener on, can be one of
+ * {@link DialogInterface#BUTTON_POSITIVE},
+ * {@link DialogInterface#BUTTON_NEGATIVE}, or
+ * {@link DialogInterface#BUTTON_NEUTRAL}
+ * @param text The text to display in positive button.
+ * @param listener The {@link DialogInterface.OnClickListener} to use.
+ * @param icon The {@link Drawable} to be set as an icon for the button.
+ */
+ public void setButton(int whichButton, CharSequence text, Drawable icon,
+ OnClickListener listener) {
+ mAlert.setButton(whichButton, text, listener, null, icon);
}
/**
@@ -470,6 +488,16 @@
}
/**
+ * Set an icon to be displayed for the positive button.
+ * @param icon The icon to be displayed
+ * @return This Builder object to allow for chaining of calls to set methods
+ */
+ public Builder setPositiveButtonIcon(Drawable icon) {
+ P.mPositiveButtonIcon = icon;
+ return this;
+ }
+
+ /**
* Set a listener to be invoked when the negative button of the dialog is pressed.
* @param textId The resource id of the text to display in the negative button
* @param listener The {@link DialogInterface.OnClickListener} to use.
@@ -496,6 +524,16 @@
}
/**
+ * Set an icon to be displayed for the negative button.
+ * @param icon The icon to be displayed
+ * @return This Builder object to allow for chaining of calls to set methods
+ */
+ public Builder setNegativeButtonIcon(Drawable icon) {
+ P.mNegativeButtonIcon = icon;
+ return this;
+ }
+
+ /**
* Set a listener to be invoked when the neutral button of the dialog is pressed.
* @param textId The resource id of the text to display in the neutral button
* @param listener The {@link DialogInterface.OnClickListener} to use.
@@ -522,6 +560,16 @@
}
/**
+ * Set an icon to be displayed for the neutral button.
+ * @param icon The icon to be displayed
+ * @return This Builder object to allow for chaining of calls to set methods
+ */
+ public Builder setNeutralButtonIcon(Drawable icon) {
+ P.mNeutralButtonIcon = icon;
+ return this;
+ }
+
+ /**
* Sets whether the dialog is cancelable or not. Default is true.
*
* @return This Builder object to allow for chaining of calls to set methods
diff --git a/v7/appcompat/src/main/java/android/support/v7/view/ContextThemeWrapper.java b/v7/appcompat/src/main/java/android/support/v7/view/ContextThemeWrapper.java
index aa5b36e..cc63480 100644
--- a/v7/appcompat/src/main/java/android/support/v7/view/ContextThemeWrapper.java
+++ b/v7/appcompat/src/main/java/android/support/v7/view/ContextThemeWrapper.java
@@ -16,26 +16,19 @@
package android.support.v7.view;
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
-import android.support.annotation.RestrictTo;
import android.support.annotation.StyleRes;
import android.support.v7.appcompat.R;
import android.view.LayoutInflater;
/**
- * A ContextWrapper that allows you to modify the theme from what is in the
- * wrapped context.
- *
- * @hide
+ * A context wrapper that allows you to modify or replace the theme of the wrapped context.
*/
-@RestrictTo(LIBRARY_GROUP)
public class ContextThemeWrapper extends ContextWrapper {
private int mThemeResource;
private Resources.Theme mTheme;
@@ -110,15 +103,6 @@
mOverrideConfiguration = new Configuration(overrideConfiguration);
}
- /**
- * Used by ActivityThread to apply the overridden configuration to onConfigurationChange
- * callbacks.
- * @hide
- */
- public Configuration getOverrideConfiguration() {
- return mOverrideConfiguration;
- }
-
@Override
public Resources getResources() {
return getResourcesInternal();
@@ -144,6 +128,10 @@
}
}
+ /**
+ * Returns the resource ID of the theme that is to be applied on top of the base context's
+ * theme.
+ */
public int getThemeResId() {
return mThemeResource;
}
diff --git a/v7/appcompat/src/main/java/android/support/v7/view/menu/CascadingMenuPopup.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/CascadingMenuPopup.java
index 564bbfc..834f854 100644
--- a/v7/appcompat/src/main/java/android/support/v7/view/menu/CascadingMenuPopup.java
+++ b/v7/appcompat/src/main/java/android/support/v7/view/menu/CascadingMenuPopup.java
@@ -54,7 +54,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import java.util.LinkedList;
import java.util.List;
/**
@@ -85,7 +84,7 @@
final Handler mSubMenuHoverHandler;
/** List of menus that were added before this popup was shown. */
- private final List<MenuBuilder> mPendingMenus = new LinkedList<>();
+ private final List<MenuBuilder> mPendingMenus = new ArrayList<>();
/**
* List of open menus. The first item is the root menu and each
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/ActionMenuView.java b/v7/appcompat/src/main/java/android/support/v7/widget/ActionMenuView.java
index 76e06da..14723a0 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/ActionMenuView.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/ActionMenuView.java
@@ -268,10 +268,10 @@
// Mark indices of children that can receive an extra cell.
if (lp.cellsUsed < minCells) {
minCells = lp.cellsUsed;
- minCellsAt = 1 << i;
+ minCellsAt = 1L << i;
minCellsItemCount = 1;
} else if (lp.cellsUsed == minCells) {
- minCellsAt |= 1 << i;
+ minCellsAt |= 1L << i;
minCellsItemCount++;
}
}
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextViewAutoSizeHelper.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextViewAutoSizeHelper.java
index e82e469..7e98494 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextViewAutoSizeHelper.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextViewAutoSizeHelper.java
@@ -45,8 +45,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.Hashtable;
import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Utility class which encapsulates the logic for the TextView auto-size text feature added to
@@ -66,7 +66,8 @@
private static final int DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX = 1;
// Cache of TextView methods used via reflection; the key is the method name and the value is
// the method itself or null if it can not be found.
- private static Hashtable<String, Method> sTextViewMethodByNameCache = new Hashtable<>();
+ private static ConcurrentHashMap<String, Method> sTextViewMethodByNameCache =
+ new ConcurrentHashMap<>();
// Use this to specify that any of the auto-size configuration int values have not been set.
static final float UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE = -1f;
// Ported from TextView#VERY_WIDE. Represents a maximum width in pixels the TextView takes when
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/ListPopupWindow.java b/v7/appcompat/src/main/java/android/support/v7/widget/ListPopupWindow.java
index edc9781..b98197c 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/ListPopupWindow.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/ListPopupWindow.java
@@ -283,7 +283,7 @@
mAdapter.unregisterDataSetObserver(mObserver);
}
mAdapter = adapter;
- if (mAdapter != null) {
+ if (adapter != null) {
adapter.registerDataSetObserver(mObserver);
}
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/TooltipPopup.java b/v7/appcompat/src/main/java/android/support/v7/widget/TooltipPopup.java
index dc20aa1..396fe05 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/TooltipPopup.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/TooltipPopup.java
@@ -31,6 +31,7 @@
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.TextView;
@@ -99,6 +100,7 @@
private void computePosition(View anchorView, int anchorX, int anchorY, boolean fromTouch,
WindowManager.LayoutParams outParams) {
+ outParams.token = anchorView.getApplicationWindowToken();
final int tooltipPreciseAnchorThreshold = mContext.getResources().getDimensionPixelOffset(
R.dimen.tooltip_precise_anchor_threshold);
@@ -157,7 +159,7 @@
mTmpAnchorPos[1] -= mTmpAppPos[1];
// mTmpAnchorPos is now relative to the main app window.
- outParams.x = mTmpAnchorPos[0] + offsetX - mTmpDisplayFrame.width() / 2;
+ outParams.x = mTmpAnchorPos[0] + offsetX - appView.getWidth() / 2;
final int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
mContentView.measure(spec, spec);
@@ -181,6 +183,16 @@
}
private static View getAppRootView(View anchorView) {
+ View rootView = anchorView.getRootView();
+ ViewGroup.LayoutParams lp = rootView.getLayoutParams();
+ if (lp instanceof WindowManager.LayoutParams
+ && (((WindowManager.LayoutParams) lp).type
+ == WindowManager.LayoutParams.TYPE_APPLICATION)) {
+ // This covers regular app windows and Dialog windows.
+ return rootView;
+ }
+ // For non-application window types (such as popup windows) try to find the main app window
+ // through the context.
Context context = anchorView.getContext();
while (context instanceof ContextWrapper) {
if (context instanceof Activity) {
@@ -189,6 +201,8 @@
context = ((ContextWrapper) context).getBaseContext();
}
}
- return anchorView.getRootView();
+ // Main app window not found, fall back to the anchor's root view. There is no guarantee
+ // that the tooltip position will be computed correctly.
+ return rootView;
}
}
diff --git a/v7/appcompat/tests/res/values/styles.xml b/v7/appcompat/tests/res/values/styles.xml
index b9fa921..9693b3a 100644
--- a/v7/appcompat/tests/res/values/styles.xml
+++ b/v7/appcompat/tests/res/values/styles.xml
@@ -98,4 +98,6 @@
<style name="TextView_Typeface_Monospace">
<item name="android:typeface">monospace</item>
</style>
+
+ <style name="TextAppearance" parent="TextAppearance.AppCompat" />
</resources>
diff --git a/v7/appcompat/tests/src/android/support/v7/view/ContextThemeWrapperTest.java b/v7/appcompat/tests/src/android/support/v7/view/ContextThemeWrapperTest.java
new file mode 100644
index 0000000..ab6b1da
--- /dev/null
+++ b/v7/appcompat/tests/src/android/support/v7/view/ContextThemeWrapperTest.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 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 android.support.v7.view;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.appcompat.test.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ContextThemeWrapperTest {
+ private static final int SYSTEM_DEFAULT_THEME = 0;
+
+ private Context mContext;
+
+ private static class MockContextThemeWrapper extends ContextThemeWrapper {
+ boolean mIsOnApplyThemeResourceCalled;
+ MockContextThemeWrapper(Context base, int themeres) {
+ super(base, themeres);
+ }
+
+ @Override
+ protected void onApplyThemeResource(Theme theme, int resid, boolean first) {
+ mIsOnApplyThemeResourceCalled = true;
+ super.onApplyThemeResource(theme, resid, first);
+ }
+ }
+
+ @Before
+ public void setup() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ }
+
+ @Test
+ public void testConstructor() {
+ new ContextThemeWrapper();
+
+ new ContextThemeWrapper(mContext, R.style.TextAppearance);
+
+ new ContextThemeWrapper(mContext, mContext.getTheme());
+ }
+
+ @Test
+ public void testAccessTheme() {
+ ContextThemeWrapper contextThemeWrapper = new ContextThemeWrapper(
+ mContext, SYSTEM_DEFAULT_THEME);
+ // set Theme to TextAppearance
+ contextThemeWrapper.setTheme(R.style.TextAppearance);
+ TypedArray ta = contextThemeWrapper.getTheme().obtainStyledAttributes(
+ R.styleable.TextAppearance);
+
+ // assert theme style of TextAppearance
+ verifyIdenticalTextAppearanceStyle(ta);
+ }
+
+ @Test
+ public void testGetSystemService() {
+ // Note that we can't use Mockito since ContextThemeWrapper.onApplyThemeResource is
+ // protected
+ final MockContextThemeWrapper contextThemeWrapper =
+ new MockContextThemeWrapper(mContext, R.style.TextAppearance);
+ contextThemeWrapper.getTheme();
+ assertTrue(contextThemeWrapper.mIsOnApplyThemeResourceCalled);
+
+ // All service get from contextThemeWrapper just the same as this context get,
+ // except Context.LAYOUT_INFLATER_SERVICE.
+ assertEquals(mContext.getSystemService(Context.ACTIVITY_SERVICE),
+ contextThemeWrapper.getSystemService(Context.ACTIVITY_SERVICE));
+ assertNotSame(mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE),
+ contextThemeWrapper.getSystemService(Context.LAYOUT_INFLATER_SERVICE));
+ }
+
+ @Test
+ public void testAttachBaseContext() {
+ assertTrue((new ContextThemeWrapper() {
+ public boolean test() {
+ // Set two different context to ContextThemeWrapper
+ // it should throw a exception when set it at second time.
+ // As ContextThemeWrapper is a context, we will attachBaseContext to
+ // two different ContextThemeWrapper instances.
+ try {
+ attachBaseContext(new ContextThemeWrapper(mContext,
+ R.style.TextAppearance));
+ } catch (IllegalStateException e) {
+ fail("test attachBaseContext fail");
+ }
+
+ try {
+ attachBaseContext(new ContextThemeWrapper());
+ fail("test attachBaseContext fail");
+ } catch (IllegalStateException e) {
+ // expected
+ }
+ return true;
+ }
+ }).test());
+ }
+
+ @Test
+ public void testApplyOverrideConfiguration() {
+ // Configuration.densityApi is only available on API 17 and above
+ if (Build.VERSION.SDK_INT >= 17) {
+ final int realDensity = mContext.getResources().getConfiguration().densityDpi;
+ final int expectedDensity = realDensity + 1;
+
+ ContextThemeWrapper contextThemeWrapper = new ContextThemeWrapper(
+ mContext, SYSTEM_DEFAULT_THEME);
+
+ Configuration overrideConfig = new Configuration();
+ overrideConfig.densityDpi = expectedDensity;
+ contextThemeWrapper.applyOverrideConfiguration(overrideConfig);
+
+ Configuration actualConfiguration =
+ contextThemeWrapper.getResources().getConfiguration();
+ assertEquals(expectedDensity, actualConfiguration.densityDpi);
+ }
+ }
+
+ private void verifyIdenticalTextAppearanceStyle(TypedArray ta) {
+ final int defValue = -1;
+ // get Theme and assert
+ Resources.Theme expected = mContext.getResources().newTheme();
+ expected.setTo(mContext.getTheme());
+ expected.applyStyle(R.style.TextAppearance, true);
+ TypedArray expectedTa = expected.obtainStyledAttributes(R.styleable.TextAppearance);
+ assertEquals(expectedTa.getIndexCount(), ta.getIndexCount());
+ assertEquals(expectedTa.getColor(
+ android.support.v7.appcompat.R.styleable.TextAppearance_android_textColor,
+ defValue),
+ ta.getColor(
+ android.support.v7.appcompat.R.styleable.TextAppearance_android_textColor,
+ defValue));
+ assertEquals(expectedTa.getColor(
+ android.support.v7.appcompat.R.styleable.TextAppearance_android_textColorHint,
+ defValue),
+ ta.getColor(
+ android.support.v7.appcompat.R.styleable
+ .TextAppearance_android_textColorHint,
+ defValue));
+ assertEquals(expectedTa.getColor(
+ android.support.v7.appcompat.R.styleable.TextAppearance_android_textColorLink,
+ defValue),
+ ta.getColor(
+ android.support.v7.appcompat.R.styleable
+ .TextAppearance_android_textColorLink,
+ defValue));
+ assertEquals(expectedTa.getDimension(
+ android.support.v7.appcompat.R.styleable.TextAppearance_android_textSize,
+ defValue),
+ ta.getDimension(
+ android.support.v7.appcompat.R.styleable.TextAppearance_android_textSize,
+ defValue), 0.0f);
+ assertEquals(expectedTa.getInt(
+ android.support.v7.appcompat.R.styleable.TextAppearance_android_textStyle,
+ defValue),
+ ta.getInt(android.support.v7.appcompat.R.styleable
+ .TextAppearance_android_textStyle,
+ defValue));
+ }
+}
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java
index cbc3176..eb52653 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java
@@ -35,6 +35,7 @@
import android.support.annotation.ColorInt;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.MediumTest;
+import android.support.test.filters.SdkSuppress;
import android.support.test.filters.SmallTest;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.res.ResourcesCompat;
@@ -353,10 +354,11 @@
assertEquals(Typeface.SERIF, textView.getTypeface());
}
+ @SdkSuppress(minSdkVersion = 16)
@Test
@UiThreadTest
public void testfontFamilyNamespaceHierarchy() {
- // This view has fontFamilyset in both the app and android namespace. App should be used.
+ // This view has fontFamily set in both the app and android namespace. App should be used.
TextView textView = mContainer.findViewById(R.id.textview_app_and_android_fontfamily);
assertEquals(Typeface.MONOSPACE, textView.getTypeface());
diff --git a/v7/cardview/build.gradle b/v7/cardview/build.gradle
index 23d8076..a6f98e1 100644
--- a/v7/cardview/build.gradle
+++ b/v7/cardview/build.gradle
@@ -6,16 +6,16 @@
}
dependencies {
- api project(':support-annotations')
+ api(project(":support-annotations"))
}
android {
defaultConfig {
- minSdkVersion 14
+ minSdkVersion(14)
}
sourceSets {
- main.res.srcDir 'res'
+ main.res.srcDir("res")
}
}
diff --git a/v7/cardview/lint-baseline.xml b/v7/cardview/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/v7/cardview/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/v7/cardview/res/values/attrs.xml b/v7/cardview/res/values/attrs.xml
index deed51b..8bac9cc 100644
--- a/v7/cardview/res/values/attrs.xml
+++ b/v7/cardview/res/values/attrs.xml
@@ -15,6 +15,9 @@
-->
<resources>
+ <!-- Default CardView style -->
+ <attr name="cardViewStyle" format="reference" />
+
<declare-styleable name="CardView">
<!-- Background color for CardView. -->
<attr name="cardBackgroundColor" format="color" />
diff --git a/v7/cardview/src/main/java/android/support/v7/widget/CardView.java b/v7/cardview/src/main/java/android/support/v7/widget/CardView.java
index 58a04f0..a45ee98 100644
--- a/v7/cardview/src/main/java/android/support/v7/widget/CardView.java
+++ b/v7/cardview/src/main/java/android/support/v7/widget/CardView.java
@@ -108,18 +108,57 @@
final Rect mShadowBounds = new Rect();
public CardView(@NonNull Context context) {
- super(context);
- initialize(context, null, 0);
+ this(context, null);
}
public CardView(@NonNull Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- initialize(context, attrs, 0);
+ this(context, attrs, R.attr.cardViewStyle);
}
public CardView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- initialize(context, attrs, defStyleAttr);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CardView, defStyleAttr,
+ R.style.CardView);
+ ColorStateList backgroundColor;
+ if (a.hasValue(R.styleable.CardView_cardBackgroundColor)) {
+ backgroundColor = a.getColorStateList(R.styleable.CardView_cardBackgroundColor);
+ } else {
+ // There isn't one set, so we'll compute one based on the theme
+ final TypedArray aa = getContext().obtainStyledAttributes(COLOR_BACKGROUND_ATTR);
+ final int themeColorBackground = aa.getColor(0, 0);
+ aa.recycle();
+
+ // If the theme colorBackground is light, use our own light color, otherwise dark
+ final float[] hsv = new float[3];
+ Color.colorToHSV(themeColorBackground, hsv);
+ backgroundColor = ColorStateList.valueOf(hsv[2] > 0.5f
+ ? getResources().getColor(R.color.cardview_light_background)
+ : getResources().getColor(R.color.cardview_dark_background));
+ }
+ float radius = a.getDimension(R.styleable.CardView_cardCornerRadius, 0);
+ float elevation = a.getDimension(R.styleable.CardView_cardElevation, 0);
+ float maxElevation = a.getDimension(R.styleable.CardView_cardMaxElevation, 0);
+ mCompatPadding = a.getBoolean(R.styleable.CardView_cardUseCompatPadding, false);
+ mPreventCornerOverlap = a.getBoolean(R.styleable.CardView_cardPreventCornerOverlap, true);
+ int defaultPadding = a.getDimensionPixelSize(R.styleable.CardView_contentPadding, 0);
+ mContentPadding.left = a.getDimensionPixelSize(R.styleable.CardView_contentPaddingLeft,
+ defaultPadding);
+ mContentPadding.top = a.getDimensionPixelSize(R.styleable.CardView_contentPaddingTop,
+ defaultPadding);
+ mContentPadding.right = a.getDimensionPixelSize(R.styleable.CardView_contentPaddingRight,
+ defaultPadding);
+ mContentPadding.bottom = a.getDimensionPixelSize(R.styleable.CardView_contentPaddingBottom,
+ defaultPadding);
+ if (elevation > maxElevation) {
+ maxElevation = elevation;
+ }
+ mUserSetMinWidth = a.getDimensionPixelSize(R.styleable.CardView_android_minWidth, 0);
+ mUserSetMinHeight = a.getDimensionPixelSize(R.styleable.CardView_android_minHeight, 0);
+ a.recycle();
+
+ IMPL.initialize(mCardViewDelegate, context, backgroundColor, radius,
+ elevation, maxElevation);
}
@Override
@@ -220,50 +259,6 @@
}
}
- private void initialize(Context context, AttributeSet attrs, int defStyleAttr) {
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CardView, defStyleAttr,
- R.style.CardView);
- ColorStateList backgroundColor;
- if (a.hasValue(R.styleable.CardView_cardBackgroundColor)) {
- backgroundColor = a.getColorStateList(R.styleable.CardView_cardBackgroundColor);
- } else {
- // There isn't one set, so we'll compute one based on the theme
- final TypedArray aa = getContext().obtainStyledAttributes(COLOR_BACKGROUND_ATTR);
- final int themeColorBackground = aa.getColor(0, 0);
- aa.recycle();
-
- // If the theme colorBackground is light, use our own light color, otherwise dark
- final float[] hsv = new float[3];
- Color.colorToHSV(themeColorBackground, hsv);
- backgroundColor = ColorStateList.valueOf(hsv[2] > 0.5f
- ? getResources().getColor(R.color.cardview_light_background)
- : getResources().getColor(R.color.cardview_dark_background));
- }
- float radius = a.getDimension(R.styleable.CardView_cardCornerRadius, 0);
- float elevation = a.getDimension(R.styleable.CardView_cardElevation, 0);
- float maxElevation = a.getDimension(R.styleable.CardView_cardMaxElevation, 0);
- mCompatPadding = a.getBoolean(R.styleable.CardView_cardUseCompatPadding, false);
- mPreventCornerOverlap = a.getBoolean(R.styleable.CardView_cardPreventCornerOverlap, true);
- int defaultPadding = a.getDimensionPixelSize(R.styleable.CardView_contentPadding, 0);
- mContentPadding.left = a.getDimensionPixelSize(R.styleable.CardView_contentPaddingLeft,
- defaultPadding);
- mContentPadding.top = a.getDimensionPixelSize(R.styleable.CardView_contentPaddingTop,
- defaultPadding);
- mContentPadding.right = a.getDimensionPixelSize(R.styleable.CardView_contentPaddingRight,
- defaultPadding);
- mContentPadding.bottom = a.getDimensionPixelSize(R.styleable.CardView_contentPaddingBottom,
- defaultPadding);
- if (elevation > maxElevation) {
- maxElevation = elevation;
- }
- mUserSetMinWidth = a.getDimensionPixelSize(R.styleable.CardView_android_minWidth, 0);
- mUserSetMinHeight = a.getDimensionPixelSize(R.styleable.CardView_android_minHeight, 0);
- a.recycle();
-
- IMPL.initialize(mCardViewDelegate, context, backgroundColor, radius,
- elevation, maxElevation);
- }
-
@Override
public void setMinimumWidth(int minWidth) {
mUserSetMinWidth = minWidth;
diff --git a/v7/gridlayout/api/27.0.0.ignore b/v7/gridlayout/api/27.0.0.ignore
new file mode 100644
index 0000000..938da3f
--- /dev/null
+++ b/v7/gridlayout/api/27.0.0.ignore
@@ -0,0 +1 @@
+7420ef1
diff --git a/v7/gridlayout/api/current.txt b/v7/gridlayout/api/current.txt
index 1fc6e1d..9f12b89 100644
--- a/v7/gridlayout/api/current.txt
+++ b/v7/gridlayout/api/current.txt
@@ -15,7 +15,6 @@
method public boolean getUseDefaultMargins();
method public boolean isColumnOrderPreserved();
method public boolean isRowOrderPreserved();
- method protected void onLayout(boolean, int, int, int, int);
method public void setAlignmentMode(int);
method public void setColumnCount(int);
method public void setColumnOrderPreserved(boolean);
diff --git a/v7/gridlayout/build.gradle b/v7/gridlayout/build.gradle
index 052b9db..7df5397 100644
--- a/v7/gridlayout/build.gradle
+++ b/v7/gridlayout/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,11 +7,11 @@
}
dependencies {
- api project(':support-compat')
- api project(':support-core-ui')
+ api(project(":support-compat"))
+ api(project(":support-core-ui"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
}
android {
diff --git a/v7/gridlayout/lint-baseline.xml b/v7/gridlayout/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/v7/gridlayout/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/v7/mediarouter/build.gradle b/v7/mediarouter/build.gradle
index 09e48df..dbf3da5 100644
--- a/v7/mediarouter/build.gradle
+++ b/v7/mediarouter/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,13 +7,13 @@
}
dependencies {
- api project(":support-media-compat")
- api project(":appcompat-v7")
- api project(":palette-v7")
+ api(project(":support-media-compat"))
+ api(project(":appcompat-v7"))
+ api(project(":palette-v7"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.test_rules
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(TEST_RULES)
}
android {
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
index cf6fc1f..cc372ec 100644
--- a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
+++ b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
@@ -2560,12 +2560,16 @@
// TODO: Remove the following logging when no longer needed.
if (sGlobal == null || (mBluetoothRoute != null && route.isDefault())) {
final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
// callStack[3] is the caller of this method.
for (int i = 3; i < callStack.length; i++) {
StackTraceElement caller = callStack[i];
- sb.append(caller.getClassName() + "." + caller.getMethodName()
- + ":" + caller.getLineNumber()).append(" ");
+ sb.append(caller.getClassName())
+ .append(".")
+ .append(caller.getMethodName())
+ .append(":")
+ .append(caller.getLineNumber())
+ .append(" ");
}
if (sGlobal == null) {
Log.w(TAG, "setSelectedRouteInternal is called while sGlobal is null: pkgName="
diff --git a/v7/mediarouter/src/android/support/v7/media/package.html b/v7/mediarouter/src/android/support/v7/media/package.html
index 0866a42..be2aaf2 100644
--- a/v7/mediarouter/src/android/support/v7/media/package.html
+++ b/v7/mediarouter/src/android/support/v7/media/package.html
@@ -4,7 +4,6 @@
<p>Contains APIs that control the routing of media channels and streams from the current device
to external speakers and destination devices.</p>
-<p>Compatible with API level 7 and higher.</p>
</body>
</html>
diff --git a/v7/palette/build.gradle b/v7/palette/build.gradle
index 2703f2c..a1b1fc9 100644
--- a/v7/palette/build.gradle
+++ b/v7/palette/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,10 +7,10 @@
}
dependencies {
- api project(':support-compat')
- api project(':support-core-utils')
+ api(project(":support-compat"))
+ api(project(":support-core-utils"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
+ androidTestImplementation(TEST_RUNNER)
}
android {
diff --git a/v7/palette/lint-baseline.xml b/v7/palette/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/v7/palette/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/v7/preference/build.gradle b/v7/preference/build.gradle
index f5bc372..698afb6 100644
--- a/v7/preference/build.gradle
+++ b/v7/preference/build.gradle
@@ -14,6 +14,7 @@
* limitations under the License
*/
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -22,14 +23,14 @@
}
dependencies {
- api project(':support-v4')
- api project(':appcompat-v7')
- api project(':recyclerview-v7')
+ api(project(":support-v4"))
+ api(project(":appcompat-v7"))
+ api(project(":recyclerview-v7"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
}
android {
diff --git a/v7/preference/src/main/java/android/support/v7/preference/CollapsiblePreferenceGroupController.java b/v7/preference/src/main/java/android/support/v7/preference/CollapsiblePreferenceGroupController.java
index e15ca18..b63ff75 100644
--- a/v7/preference/src/main/java/android/support/v7/preference/CollapsiblePreferenceGroupController.java
+++ b/v7/preference/src/main/java/android/support/v7/preference/CollapsiblePreferenceGroupController.java
@@ -166,7 +166,7 @@
CharSequence summary = null;
for (int i = collapsedIndex; i < flattenedPreferenceList.size(); i++) {
final Preference preference = flattenedPreferenceList.get(i);
- if (preference instanceof PreferenceGroup) {
+ if (preference instanceof PreferenceGroup || !preference.isVisible()) {
continue;
}
final CharSequence title = preference.getTitle();
diff --git a/v7/preference/tests/src/android/support/v7/preference/PreferenceGroupInitialExpandedChildrenCountTest.java b/v7/preference/tests/src/android/support/v7/preference/PreferenceGroupInitialExpandedChildrenCountTest.java
index 4f53b9a..499e2c1 100644
--- a/v7/preference/tests/src/android/support/v7/preference/PreferenceGroupInitialExpandedChildrenCountTest.java
+++ b/v7/preference/tests/src/android/support/v7/preference/PreferenceGroupInitialExpandedChildrenCountTest.java
@@ -188,6 +188,26 @@
}
/**
+ * Verifies that summary for the expand button only lists visible preferences.
+ */
+ @Test
+ @UiThreadTest
+ public void createPreferenceGroupAdapter_expandButtonSummaryShouldListVisiblePreferencesOnly() {
+ mScreen.setInitialExpandedChildrenCount(INITIAL_EXPANDED_COUNT);
+ mPreferenceList.get(INITIAL_EXPANDED_COUNT + 1).setVisible(false);
+ mPreferenceList.get(INITIAL_EXPANDED_COUNT + 4).setVisible(false);
+ PreferenceGroupAdapter preferenceGroupAdapter = new PreferenceGroupAdapter(mScreen);
+ // Preference 5 to Preference 9 are collapsed, only preferences 5, 7, 8 are visible
+ CharSequence summary = mPreferenceList.get(INITIAL_EXPANDED_COUNT).getTitle();
+ summary = mContext.getString(R.string.summary_collapsed_preference_list,
+ summary, mPreferenceList.get(INITIAL_EXPANDED_COUNT + 2).getTitle());
+ summary = mContext.getString(R.string.summary_collapsed_preference_list,
+ summary, mPreferenceList.get(INITIAL_EXPANDED_COUNT + 3).getTitle());
+ final Preference expandButton = preferenceGroupAdapter.getItem(INITIAL_EXPANDED_COUNT);
+ assertEquals(summary, expandButton.getSummary());
+ }
+
+ /**
* Verifies that clicking the expand button will show all preferences.
*/
@Test
diff --git a/v7/recyclerview/api/27.0.0.ignore b/v7/recyclerview/api/27.0.0.ignore
new file mode 100644
index 0000000..357c296
--- /dev/null
+++ b/v7/recyclerview/api/27.0.0.ignore
@@ -0,0 +1 @@
+d69e9e2
diff --git a/v7/recyclerview/api/current.txt b/v7/recyclerview/api/current.txt
index 17cd472..0909d7d 100644
--- a/v7/recyclerview/api/current.txt
+++ b/v7/recyclerview/api/current.txt
@@ -84,6 +84,9 @@
method public void recalculatePositionOfItemAt(int);
method public boolean remove(T);
method public T removeItemAt(int);
+ method public void replaceAll(T[], boolean);
+ method public void replaceAll(T...);
+ method public void replaceAll(java.util.Collection<T>);
method public int size();
method public void updateItemAt(int, T);
field public static final int INVALID_POSITION = -1; // 0xffffffff
@@ -190,6 +193,7 @@
method public boolean getStackFromEnd();
method protected boolean isLayoutRTL();
method public boolean isSmoothScrollbarEnabled();
+ method public void prepareForDrop(android.view.View, android.view.View, int, int);
method public void scrollToPositionWithOffset(int, int);
method public void setInitialPrefetchItemCount(int);
method public void setOrientation(int);
@@ -277,7 +281,7 @@
method public int findTargetSnapPosition(android.support.v7.widget.RecyclerView.LayoutManager, int, int);
}
- public class RecyclerView extends android.view.ViewGroup {
+ public class RecyclerView extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingChild2 android.support.v4.view.ScrollingView {
ctor public RecyclerView(android.content.Context);
ctor public RecyclerView(android.content.Context, android.util.AttributeSet);
ctor public RecyclerView(android.content.Context, android.util.AttributeSet, int);
@@ -336,7 +340,6 @@
method public void onChildAttachedToWindow(android.view.View);
method public void onChildDetachedFromWindow(android.view.View);
method public void onDraw(android.graphics.Canvas);
- method protected void onLayout(boolean, int, int, int, int);
method public void onScrollStateChanged(int);
method public void onScrolled(int, int);
method public void removeItemDecoration(android.support.v7.widget.RecyclerView.ItemDecoration);
diff --git a/v7/recyclerview/build.gradle b/v7/recyclerview/build.gradle
index daac4ab..0a83989 100644
--- a/v7/recyclerview/build.gradle
+++ b/v7/recyclerview/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,33 +7,33 @@
}
dependencies {
- api project(':support-annotations')
- api project(':support-compat')
- api project(':support-core-ui')
+ api(project(":support-annotations"))
+ api(project(":support-compat"))
+ api(project(":support-core-ui"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.junit
- androidTestImplementation project(':support-testutils')
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(JUNIT)
+ androidTestImplementation(project(":support-testutils"))
- testImplementation libs.junit
- testImplementation libs.mockito_core
- testImplementation libs.test_runner, { exclude module: 'support-annotations' }
+ testImplementation(JUNIT)
+ testImplementation(MOCKITO_CORE)
+ testImplementation(TEST_RUNNER)
}
android {
defaultConfig {
- minSdkVersion 14
+ minSdkVersion(14)
}
sourceSets {
- main.res.srcDirs 'res', 'res-public'
+ main.res.srcDirs "res", "res-public"
}
buildTypes.all {
- consumerProguardFiles 'proguard-rules.pro'
+ consumerProguardFiles("proguard-rules.pro")
}
}
diff --git a/v7/recyclerview/lint-baseline.xml b/v7/recyclerview/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/v7/recyclerview/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/v7/recyclerview/src/main/java/android/support/v7/util/SortedList.java b/v7/recyclerview/src/main/java/android/support/v7/util/SortedList.java
index af000a1..bd07b01 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/util/SortedList.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/util/SortedList.java
@@ -16,6 +16,7 @@
package android.support.v7.util;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.lang.reflect.Array;
@@ -51,17 +52,23 @@
T[] mData;
/**
- * A copy of the previous list contents used during the merge phase of addAll.
+ * A reference to the previous set of data that is kept during a mutation operation (addAll or
+ * replaceAll).
*/
private T[] mOldData;
+
+ /**
+ * The current index into mOldData that has not yet been processed during a mutation operation
+ * (addAll or replaceAll).
+ */
private int mOldDataStart;
private int mOldDataSize;
/**
- * The size of the valid portion of mData during the merge phase of addAll.
+ * The current index into the new data that has not yet been processed during a mutation
+ * operation (addAll or replaceAll).
*/
- private int mMergedSize;
-
+ private int mNewDataStart;
/**
* The callback instance that controls the behavior of the SortedList and get notified when
@@ -133,7 +140,7 @@
* @see Callback#areContentsTheSame(Object, Object)}
*/
public int add(T item) {
- throwIfMerging();
+ throwIfInMutationOperation();
return add(item, true);
}
@@ -142,30 +149,30 @@
* except the callback events may be in a different order/granularity since addAll can batch
* them for better performance.
* <p>
- * If allowed, may modify the input array and even take the ownership over it in order
- * to avoid extra memory allocation during sorting and deduplication.
- * </p>
+ * If allowed, will reference the input array during, and possibly after, the operation to avoid
+ * extra memory allocation, in which case you should not continue to reference or modify the
+ * array yourself.
+ * <p>
* @param items Array of items to be added into the list.
- * @param mayModifyInput If true, SortedList is allowed to modify the input.
- * @see SortedList#addAll(Object[] items)
+ * @param mayModifyInput If true, SortedList is allowed to modify and permanently reference the
+ * input array.
+ * @see SortedList#addAll(T[] items)
*/
public void addAll(T[] items, boolean mayModifyInput) {
- throwIfMerging();
+ throwIfInMutationOperation();
if (items.length == 0) {
return;
}
+
if (mayModifyInput) {
addAllInternal(items);
} else {
- T[] copy = (T[]) Array.newInstance(mTClass, items.length);
- System.arraycopy(items, 0, copy, 0, items.length);
- addAllInternal(copy);
+ addAllInternal(copyArray(items));
}
-
}
/**
- * Adds the given items to the list. Does not modify the input.
+ * Adds the given items to the list. Does not modify or retain the input.
*
* @see SortedList#addAll(T[] items, boolean mayModifyInput)
*
@@ -176,7 +183,7 @@
}
/**
- * Adds the given items to the list. Does not modify the input.
+ * Adds the given items to the list. Does not modify or retain the input.
*
* @see SortedList#addAll(T[] items, boolean mayModifyInput)
*
@@ -187,26 +194,133 @@
addAll(items.toArray(copy), true);
}
+ /**
+ * Replaces the current items with the new items, dispatching {@link ListUpdateCallback} events
+ * for each change detected as appropriate.
+ * <p>
+ * If allowed, will reference the input array during, and possibly after, the operation to avoid
+ * extra memory allocation, in which case you should not continue to reference or modify the
+ * array yourself.
+ * <p>
+ * Note: this method does not detect moves or dispatch
+ * {@link ListUpdateCallback#onMoved(int, int)} events. It instead treats moves as a remove
+ * followed by an add and therefore dispatches {@link ListUpdateCallback#onRemoved(int, int)}
+ * and {@link ListUpdateCallback#onRemoved(int, int)} events. See {@link DiffUtil} if you want
+ * your implementation to dispatch move events.
+ * <p>
+ * @param items Array of items to replace current items.
+ * @param mayModifyInput If true, SortedList is allowed to modify and permanently reference the
+ * input array.
+ * @see #replaceAll(T[])
+ */
+ public void replaceAll(@NonNull T[] items, boolean mayModifyInput) {
+ throwIfInMutationOperation();
+
+ if (mayModifyInput) {
+ replaceAllInternal(items);
+ } else {
+ replaceAllInternal(copyArray(items));
+ }
+ }
+
+ /**
+ * Replaces the current items with the new items, dispatching {@link ListUpdateCallback} events
+ * for each change detected as appropriate. Does not modify or retain the input.
+ *
+ * @see #replaceAll(T[], boolean)
+ *
+ * @param items Array of items to replace current items.
+ */
+ public void replaceAll(@NonNull T... items) {
+ replaceAll(items, false);
+ }
+
+ /**
+ * Replaces the current items with the new items, dispatching {@link ListUpdateCallback} events
+ * for each change detected as appropriate. Does not modify or retain the input.
+ *
+ * @see #replaceAll(T[], boolean)
+ *
+ * @param items Array of items to replace current items.
+ */
+ public void replaceAll(@NonNull Collection<T> items) {
+ T[] copy = (T[]) Array.newInstance(mTClass, items.size());
+ replaceAll(items.toArray(copy), true);
+ }
+
private void addAllInternal(T[] newItems) {
+ if (newItems.length < 1) {
+ return;
+ }
+
+ final int newSize = sortAndDedup(newItems);
+
+ if (mSize == 0) {
+ mData = newItems;
+ mSize = newSize;
+ mCallback.onInserted(0, newSize);
+ } else {
+ merge(newItems, newSize);
+ }
+ }
+
+ private void replaceAllInternal(@NonNull T[] newData) {
final boolean forceBatchedUpdates = !(mCallback instanceof BatchedCallback);
if (forceBatchedUpdates) {
beginBatchedUpdates();
}
- mOldData = mData;
mOldDataStart = 0;
mOldDataSize = mSize;
+ mOldData = mData;
- Arrays.sort(newItems, mCallback); // Arrays.sort is stable.
+ mNewDataStart = 0;
+ int newSize = sortAndDedup(newData);
+ mData = (T[]) Array.newInstance(mTClass, newSize);
- final int newSize = deduplicate(newItems);
- if (mSize == 0) {
- mData = newItems;
- mSize = newSize;
- mMergedSize = newSize;
- mCallback.onInserted(0, newSize);
- } else {
- merge(newItems, newSize);
+ while (mNewDataStart < newSize || mOldDataStart < mOldDataSize) {
+ if (mOldDataStart >= mOldDataSize) {
+ int insertIndex = mNewDataStart;
+ int itemCount = newSize - mNewDataStart;
+ System.arraycopy(newData, insertIndex, mData, insertIndex, itemCount);
+ mNewDataStart += itemCount;
+ mSize += itemCount;
+ mCallback.onInserted(insertIndex, itemCount);
+ break;
+ }
+ if (mNewDataStart >= newSize) {
+ int itemCount = mOldDataSize - mOldDataStart;
+ mSize -= itemCount;
+ mCallback.onRemoved(mNewDataStart, itemCount);
+ break;
+ }
+
+ T oldItem = mOldData[mOldDataStart];
+ T newItem = newData[mNewDataStart];
+
+ int result = mCallback.compare(oldItem, newItem);
+ if (result < 0) {
+ replaceAllRemove();
+ } else if (result > 0) {
+ replaceAllInsert(newItem);
+ } else {
+ if (!mCallback.areItemsTheSame(oldItem, newItem)) {
+ // The items aren't the same even though they were supposed to occupy the same
+ // place, so both notify to remove and add an item in the current location.
+ replaceAllRemove();
+ replaceAllInsert(newItem);
+ } else {
+ mData[mNewDataStart] = newItem;
+ mOldDataStart++;
+ mNewDataStart++;
+ if (!mCallback.areContentsTheSame(oldItem, newItem)) {
+ // The item is the same but the contents have changed, so notify that an
+ // onChanged event has occurred.
+ mCallback.onChanged(mNewDataStart - 1, 1,
+ mCallback.getChangePayload(oldItem, newItem));
+ }
+ }
+ }
}
mOldData = null;
@@ -216,17 +330,33 @@
}
}
+ private void replaceAllInsert(T newItem) {
+ mData[mNewDataStart] = newItem;
+ mNewDataStart++;
+ mSize++;
+ mCallback.onInserted(mNewDataStart - 1, 1);
+ }
+
+ private void replaceAllRemove() {
+ mSize--;
+ mOldDataStart++;
+ mCallback.onRemoved(mNewDataStart, 1);
+ }
+
/**
- * Remove duplicate items, leaving only the last item from each group of "same" items.
- * Move the remaining items to the beginning of the array.
+ * Sorts and removes duplicate items, leaving only the last item from each group of "same"
+ * items. Move the remaining items to the beginning of the array.
*
* @return Number of deduplicated items at the beginning of the array.
*/
- private int deduplicate(T[] items) {
+ private int sortAndDedup(@NonNull T[] items) {
if (items.length == 0) {
- throw new IllegalArgumentException("Input array must be non-empty");
+ return 0;
}
+ // Arrays.sort is stable.
+ Arrays.sort(items, mCallback);
+
// Keep track of the range of equal items at the end of the output.
// Start with the range containing just the first item.
int rangeStart = 0;
@@ -236,9 +366,6 @@
T currentItem = items[i];
int compare = mCallback.compare(items[rangeStart], currentItem);
- if (compare > 0) {
- throw new IllegalArgumentException("Input must be sorted in ascending order.");
- }
if (compare == 0) {
// The range of equal items continues, update it.
@@ -278,27 +405,36 @@
* This method assumes that newItems are sorted and deduplicated.
*/
private void merge(T[] newData, int newDataSize) {
+ final boolean forceBatchedUpdates = !(mCallback instanceof BatchedCallback);
+ if (forceBatchedUpdates) {
+ beginBatchedUpdates();
+ }
+
+ mOldData = mData;
+ mOldDataStart = 0;
+ mOldDataSize = mSize;
+
final int mergedCapacity = mSize + newDataSize + CAPACITY_GROWTH;
mData = (T[]) Array.newInstance(mTClass, mergedCapacity);
- mMergedSize = 0;
+ mNewDataStart = 0;
int newDataStart = 0;
while (mOldDataStart < mOldDataSize || newDataStart < newDataSize) {
if (mOldDataStart == mOldDataSize) {
// No more old items, copy the remaining new items.
int itemCount = newDataSize - newDataStart;
- System.arraycopy(newData, newDataStart, mData, mMergedSize, itemCount);
- mMergedSize += itemCount;
+ System.arraycopy(newData, newDataStart, mData, mNewDataStart, itemCount);
+ mNewDataStart += itemCount;
mSize += itemCount;
- mCallback.onInserted(mMergedSize - itemCount, itemCount);
+ mCallback.onInserted(mNewDataStart - itemCount, itemCount);
break;
}
if (newDataStart == newDataSize) {
// No more new items, copy the remaining old items.
int itemCount = mOldDataSize - mOldDataStart;
- System.arraycopy(mOldData, mOldDataStart, mData, mMergedSize, itemCount);
- mMergedSize += itemCount;
+ System.arraycopy(mOldData, mOldDataStart, mData, mNewDataStart, itemCount);
+ mNewDataStart += itemCount;
break;
}
@@ -307,36 +443,47 @@
int compare = mCallback.compare(oldItem, newItem);
if (compare > 0) {
// New item is lower, output it.
- mData[mMergedSize++] = newItem;
+ mData[mNewDataStart++] = newItem;
mSize++;
newDataStart++;
- mCallback.onInserted(mMergedSize - 1, 1);
+ mCallback.onInserted(mNewDataStart - 1, 1);
} else if (compare == 0 && mCallback.areItemsTheSame(oldItem, newItem)) {
// Items are the same. Output the new item, but consume both.
- mData[mMergedSize++] = newItem;
+ mData[mNewDataStart++] = newItem;
newDataStart++;
mOldDataStart++;
if (!mCallback.areContentsTheSame(oldItem, newItem)) {
- mCallback.onChanged(mMergedSize - 1, 1,
+ mCallback.onChanged(mNewDataStart - 1, 1,
mCallback.getChangePayload(oldItem, newItem));
}
} else {
// Old item is lower than or equal to (but not the same as the new). Output it.
// New item with the same sort order will be inserted later.
- mData[mMergedSize++] = oldItem;
+ mData[mNewDataStart++] = oldItem;
mOldDataStart++;
}
}
- }
- private void throwIfMerging() {
- if (mOldData != null) {
- throw new IllegalStateException("Cannot call this method from within addAll");
+ mOldData = null;
+
+ if (forceBatchedUpdates) {
+ endBatchedUpdates();
}
}
/**
- * Batches adapter updates that happen between calling this method until calling
+ * Throws an exception if called while we are in the middle of a mutation operation (addAll or
+ * replaceAll).
+ */
+ private void throwIfInMutationOperation() {
+ if (mOldData != null) {
+ throw new IllegalStateException("Data cannot be mutated in the middle of a batch "
+ + "update operation such as addAll or replaceAll.");
+ }
+ }
+
+ /**
+ * Batches adapter updates that happen after calling this method and before calling
* {@link #endBatchedUpdates()}. For example, if you add multiple items in a loop
* and they are placed into consecutive indices, SortedList calls
* {@link Callback#onInserted(int, int)} only once with the proper item count. If an event
@@ -368,7 +515,7 @@
* has no effect.
*/
public void beginBatchedUpdates() {
- throwIfMerging();
+ throwIfInMutationOperation();
if (mCallback instanceof BatchedCallback) {
return;
}
@@ -382,7 +529,7 @@
* Ends the update transaction and dispatches any remaining event to the callback.
*/
public void endBatchedUpdates() {
- throwIfMerging();
+ throwIfInMutationOperation();
if (mCallback instanceof BatchedCallback) {
((BatchedCallback) mCallback).dispatchLastEvent();
}
@@ -424,7 +571,7 @@
* @return True if item is removed, false if item cannot be found in the list.
*/
public boolean remove(T item) {
- throwIfMerging();
+ throwIfInMutationOperation();
return remove(item, true);
}
@@ -436,7 +583,7 @@
* @return The removed item.
*/
public T removeItemAt(int index) {
- throwIfMerging();
+ throwIfInMutationOperation();
T item = get(index);
removeItemAtIndex(index, true);
return item;
@@ -481,7 +628,7 @@
* @see #add(Object)
*/
public void updateItemAt(int index, T item) {
- throwIfMerging();
+ throwIfInMutationOperation();
final T existing = get(index);
// assume changed if the same object is given back
boolean contentsChanged = existing == item || !mCallback.areContentsTheSame(existing, item);
@@ -535,7 +682,7 @@
* @see #add(Object)
*/
public void recalculatePositionOfItemAt(int index) {
- throwIfMerging();
+ throwIfInMutationOperation();
// TODO can be improved
final T item = get(index);
removeItemAtIndex(index, false);
@@ -562,8 +709,8 @@
if (mOldData != null) {
// The call is made from a callback during addAll execution. The data is split
// between mData and mOldData.
- if (index >= mMergedSize) {
- return mOldData[index - mMergedSize + mOldDataStart];
+ if (index >= mNewDataStart) {
+ return mOldData[index - mNewDataStart + mOldDataStart];
}
}
return mData[index];
@@ -579,13 +726,13 @@
*/
public int indexOf(T item) {
if (mOldData != null) {
- int index = findIndexOf(item, mData, 0, mMergedSize, LOOKUP);
+ int index = findIndexOf(item, mData, 0, mNewDataStart, LOOKUP);
if (index != INVALID_POSITION) {
return index;
}
index = findIndexOf(item, mOldData, mOldDataStart, mOldDataSize, LOOKUP);
if (index != INVALID_POSITION) {
- return index - mOldDataStart + mMergedSize;
+ return index - mOldDataStart + mNewDataStart;
}
return INVALID_POSITION;
}
@@ -662,11 +809,17 @@
mSize++;
}
+ private T[] copyArray(T[] items) {
+ T[] copy = (T[]) Array.newInstance(mTClass, items.length);
+ System.arraycopy(items, 0, copy, 0, items.length);
+ return copy;
+ }
+
/**
* Removes all items from the SortedList.
*/
public void clear() {
- throwIfMerging();
+ throwIfInMutationOperation();
if (mSize == 0) {
return;
}
@@ -722,8 +875,8 @@
* so
* that you can change its behavior depending on your UI.
* <p>
- * For example, if you are using SortedList with a {@link android.support.v7.widget.RecyclerView.Adapter
- * RecyclerView.Adapter}, you should
+ * For example, if you are using SortedList with a
+ * {@link android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}, you should
* return whether the items' visual representations are the same or not.
*
* @param oldItem The previous representation of the object.
@@ -734,7 +887,7 @@
abstract public boolean areContentsTheSame(T2 oldItem, T2 newItem);
/**
- * Called by the SortedList to decide whether two object represent the same Item or not.
+ * Called by the SortedList to decide whether two objects represent the same Item or not.
* <p>
* For example, if your items have unique ids, this method should check their equality.
*
diff --git a/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java
index c8b51a4..4a65553 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java
@@ -2001,7 +2001,7 @@
}
mEatRequestLayout = 1;
}
- if (!performLayoutChildren) {
+ if (!performLayoutChildren && !mLayoutFrozen) {
// Reset the layout request eaten counter.
// This is necessary since eatRequest calls can be nested in which case the other
// call will override the inner one.
@@ -2520,9 +2520,17 @@
if (next == null || next == this) {
return false;
}
+ // panic, result view is not a child anymore, maybe workaround b/37864393
+ if (findContainingItemView(next) == null) {
+ return false;
+ }
if (focused == null) {
return true;
}
+ // panic, focused view is not a child anymore, maybe workaround b/37864393
+ if (findContainingItemView(focused) == null) {
+ return true;
+ }
mTempRect.set(0, 0, focused.getWidth(), focused.getHeight());
mTempRect2.set(0, 0, next.getWidth(), next.getHeight());
@@ -3232,7 +3240,8 @@
}
/**
- * Used when onMeasure is called before layout manager is set
+ * An implementation of {@link View#onMeasure(int, int)} to fall back to in various scenarios
+ * where this RecyclerView is otherwise lacking better information.
*/
void defaultOnMeasure(int widthSpec, int heightSpec) {
// calling LayoutManager here is not pretty but that API is already public and it is better
@@ -6536,7 +6545,8 @@
* @see #getItemViewType(int)
* @see #onBindViewHolder(ViewHolder, int)
*/
- public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
+ @NonNull
+ public abstract VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType);
/**
* Called by RecyclerView to display the data at the specified position. This method should
@@ -6558,7 +6568,7 @@
* item at the given position in the data set.
* @param position The position of the item within the adapter's data set.
*/
- public abstract void onBindViewHolder(VH holder, int position);
+ public abstract void onBindViewHolder(@NonNull VH holder, int position);
/**
* Called by RecyclerView to display the data at the specified position. This method
@@ -6589,7 +6599,8 @@
* @param payloads A non-null list of merged payloads. Can be empty list if requires full
* update.
*/
- public void onBindViewHolder(VH holder, int position, List<Object> payloads) {
+ public void onBindViewHolder(@NonNull VH holder, int position,
+ @NonNull List<Object> payloads) {
onBindViewHolder(holder, position);
}
@@ -6599,7 +6610,7 @@
*
* @see #onCreateViewHolder(ViewGroup, int)
*/
- public final VH createViewHolder(ViewGroup parent, int viewType) {
+ public final VH createViewHolder(@NonNull ViewGroup parent, int viewType) {
TraceCompat.beginSection(TRACE_CREATE_VIEW_TAG);
final VH holder = onCreateViewHolder(parent, viewType);
holder.mItemViewType = viewType;
@@ -6614,7 +6625,7 @@
*
* @see #onBindViewHolder(ViewHolder, int)
*/
- public final void bindViewHolder(VH holder, int position) {
+ public final void bindViewHolder(@NonNull VH holder, int position) {
holder.mPosition = position;
if (hasStableIds()) {
holder.mItemId = getItemId(position);
@@ -6711,7 +6722,7 @@
*
* @param holder The ViewHolder for the view being recycled
*/
- public void onViewRecycled(VH holder) {
+ public void onViewRecycled(@NonNull VH holder) {
}
/**
@@ -6748,7 +6759,7 @@
* RecyclerView will check the View's transient state again before giving a final decision.
* Default implementation returns false.
*/
- public boolean onFailedToRecycleView(VH holder) {
+ public boolean onFailedToRecycleView(@NonNull VH holder) {
return false;
}
@@ -6762,7 +6773,7 @@
*
* @param holder Holder of the view being attached
*/
- public void onViewAttachedToWindow(VH holder) {
+ public void onViewAttachedToWindow(@NonNull VH holder) {
}
/**
@@ -6774,7 +6785,7 @@
*
* @param holder Holder of the view being detached
*/
- public void onViewDetachedFromWindow(VH holder) {
+ public void onViewDetachedFromWindow(@NonNull VH holder) {
}
/**
@@ -6802,7 +6813,7 @@
*
* @see #unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver)
*/
- public void registerAdapterDataObserver(AdapterDataObserver observer) {
+ public void registerAdapterDataObserver(@NonNull AdapterDataObserver observer) {
mObservable.registerObserver(observer);
}
@@ -6816,7 +6827,7 @@
*
* @see #registerAdapterDataObserver(RecyclerView.AdapterDataObserver)
*/
- public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
+ public void unregisterAdapterDataObserver(@NonNull AdapterDataObserver observer) {
mObservable.unregisterObserver(observer);
}
@@ -6828,7 +6839,7 @@
* @param recyclerView The RecyclerView instance which started observing this adapter.
* @see #onDetachedFromRecyclerView(RecyclerView)
*/
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+ public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
}
/**
@@ -6837,7 +6848,7 @@
* @param recyclerView The RecyclerView instance which stopped observing this adapter.
* @see #onAttachedToRecyclerView(RecyclerView)
*/
- public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
+ public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
}
/**
@@ -6913,7 +6924,7 @@
*
* @see #notifyItemRangeChanged(int, int)
*/
- public final void notifyItemChanged(int position, Object payload) {
+ public final void notifyItemChanged(int position, @Nullable Object payload) {
mObservable.notifyItemRangeChanged(position, 1, payload);
}
@@ -6961,7 +6972,8 @@
*
* @see #notifyItemChanged(int)
*/
- public final void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
+ public final void notifyItemRangeChanged(int positionStart, int itemCount,
+ @Nullable Object payload) {
mObservable.notifyItemRangeChanged(positionStart, itemCount, payload);
}
@@ -7435,9 +7447,10 @@
* wants to handle the layout measurements itself.
* <p>
* This method is usually called by the LayoutManager with value {@code true} if it wants
- * to support WRAP_CONTENT. If you are using a public LayoutManager but want to customize
- * the measurement logic, you can call this method with {@code false} and override
- * {@link LayoutManager#onMeasure(int, int)} to implement your custom measurement logic.
+ * to support {@link ViewGroup.LayoutParams#WRAP_CONTENT}. If you are using a public
+ * LayoutManager but want to customize the measurement logic, you can call this method with
+ * {@code false} and override {@link LayoutManager#onMeasure(Recycler, State, int, int)} to
+ * implement your custom measurement logic.
* <p>
* AutoMeasure is a convenience mechanism for LayoutManagers to easily wrap their content or
* handle various specs provided by the RecyclerView's parent.
@@ -7511,24 +7524,26 @@
}
/**
- * Returns whether this LayoutManager supports automatic item animations.
- * A LayoutManager wishing to support item animations should obey certain
- * rules as outlined in {@link #onLayoutChildren(Recycler, State)}.
- * The default return value is <code>false</code>, so subclasses of LayoutManager
- * will not get predictive item animations by default.
- *
- * <p>Whether item animations are enabled in a RecyclerView is determined both
- * by the return value from this method and the
+ * Returns whether this LayoutManager supports "predictive item animations".
+ * <p>
+ * "Predictive item animations" are automatically created animations that show
+ * where items came from, and where they are going to, as items are added, removed,
+ * or moved within a layout.
+ * <p>
+ * A LayoutManager wishing to support predictive item animations must override this
+ * method to return true (the default implementation returns false) and must obey certain
+ * behavioral contracts outlined in {@link #onLayoutChildren(Recycler, State)}.
+ * <p>
+ * Whether item animations actually occur in a RecyclerView is actually determined by both
+ * the return value from this method and the
* {@link RecyclerView#setItemAnimator(ItemAnimator) ItemAnimator} set on the
* RecyclerView itself. If the RecyclerView has a non-null ItemAnimator but this
- * method returns false, then simple item animations will be enabled, in which
- * views that are moving onto or off of the screen are simply faded in/out. If
- * the RecyclerView has a non-null ItemAnimator and this method returns true,
- * then there will be two calls to {@link #onLayoutChildren(Recycler, State)} to
- * setup up the information needed to more intelligently predict where appearing
- * and disappearing views should be animated from/to.</p>
+ * method returns false, then only "simple item animations" will be enabled in the
+ * RecyclerView, in which views whose position are changing are simply faded in/out. If the
+ * RecyclerView has a non-null ItemAnimator and this method returns true, then predictive
+ * item animations will be enabled in the RecyclerView.
*
- * @return true if predictive item animations should be enabled, false otherwise
+ * @return true if this LayoutManager supports predictive item animations, false otherwise.
*/
public boolean supportsPredictiveItemAnimations() {
return false;
@@ -10822,8 +10837,12 @@
*/
private void onEnteredHiddenState(RecyclerView parent) {
// While the view item is in hidden state, make it invisible for the accessibility.
- mWasImportantForAccessibilityBeforeHidden =
- ViewCompat.getImportantForAccessibility(itemView);
+ if (mPendingAccessibilityState != PENDING_ACCESSIBILITY_STATE_NOT_SET) {
+ mWasImportantForAccessibilityBeforeHidden = mPendingAccessibilityState;
+ } else {
+ mWasImportantForAccessibilityBeforeHidden =
+ ViewCompat.getImportantForAccessibility(itemView);
+ }
parent.setChildImportantForAccessibilityInternal(this,
ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
@@ -11182,7 +11201,7 @@
// do nothing
}
- public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
+ public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {
// fallback to onItemRangeChanged(positionStart, itemCount) if app
// does not override this method.
onItemRangeChanged(positionStart, itemCount);
@@ -11659,7 +11678,8 @@
notifyItemRangeChanged(positionStart, itemCount, null);
}
- public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
+ public void notifyItemRangeChanged(int positionStart, int itemCount,
+ @Nullable Object payload) {
// since onItemRangeChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
@@ -11813,6 +11833,11 @@
boolean mStructureChanged = false;
+ /**
+ * True if the associated {@link RecyclerView} is in the pre-layout step where it is having
+ * its {@link LayoutManager} layout items where they will be at the beginning of a set of
+ * predictive item animations.
+ */
boolean mInPreLayout = false;
boolean mTrackOldChangeHolders = false;
@@ -11888,8 +11913,9 @@
}
/**
- * Returns true if
- * @return
+ * Returns true if the {@link RecyclerView} is in the pre-layout step where it is having its
+ * {@link LayoutManager} layout items where they will be at the beginning of a set of
+ * predictive item animations.
*/
public boolean isPreLayout() {
return mInPreLayout;
@@ -12046,6 +12072,7 @@
+ "mTargetPosition=" + mTargetPosition
+ ", mData=" + mData
+ ", mItemCount=" + mItemCount
+ + ", mIsMeasuring=" + mIsMeasuring
+ ", mPreviousLayoutItemCount=" + mPreviousLayoutItemCount
+ ", mDeletedInvisibleItemCountSincePreviousLayout="
+ mDeletedInvisibleItemCountSincePreviousLayout
diff --git a/v7/recyclerview/src/main/java/android/support/v7/widget/helper/ItemTouchHelper.java b/v7/recyclerview/src/main/java/android/support/v7/widget/helper/ItemTouchHelper.java
index aee48df..d2b6a20 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/widget/helper/ItemTouchHelper.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/widget/helper/ItemTouchHelper.java
@@ -457,7 +457,7 @@
destroyCallbacks();
}
mRecyclerView = recyclerView;
- if (mRecyclerView != null) {
+ if (recyclerView != null) {
final Resources resources = recyclerView.getResources();
mSwipeEscapeVelocity = resources
.getDimension(R.dimen.item_touch_helper_swipe_escape_velocity);
diff --git a/v7/recyclerview/src/test/java/android/support/v7/util/SortedListTest.java b/v7/recyclerview/src/test/java/android/support/v7/util/SortedListTest.java
index 47d2ac0..f8bc496 100644
--- a/v7/recyclerview/src/test/java/android/support/v7/util/SortedListTest.java
+++ b/v7/recyclerview/src/test/java/android/support/v7/util/SortedListTest.java
@@ -27,11 +27,15 @@
import org.junit.runners.JUnit4;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Queue;
import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
@RunWith(JUnit4.class)
@SmallTest
@@ -44,6 +48,8 @@
List<Pair> mUpdates = new ArrayList<Pair>();
private boolean mPayloadChanges = false;
List<PayloadChange> mPayloadUpdates = new ArrayList<>();
+ Queue<AssertListStateRunnable> mCallbackRunnables;
+ List<Event> mEvents = new ArrayList<>();
private SortedList.Callback<Item> mCallback;
InsertedCallback<Item> mInsertedCallback;
ChangedCallback<Item> mChangedCallback;
@@ -67,6 +73,7 @@
@Before
public void setUp() throws Exception {
super.setUp();
+
mCallback = new SortedList.Callback<Item>() {
@Override
public int compare(Item o1, Item o2) {
@@ -75,28 +82,35 @@
@Override
public void onInserted(int position, int count) {
+ mEvents.add(new Event(TYPE.ADD, position, count));
mAdditions.add(new Pair(position, count));
if (mInsertedCallback != null) {
mInsertedCallback.onInserted(position, count);
}
+ pollAndRun(mCallbackRunnables);
}
@Override
public void onRemoved(int position, int count) {
+ mEvents.add(new Event(TYPE.REMOVE, position, count));
mRemovals.add(new Pair(position, count));
+ pollAndRun(mCallbackRunnables);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
+ mEvents.add(new Event(TYPE.MOVE, fromPosition, toPosition));
mMoves.add(new Pair(fromPosition, toPosition));
}
@Override
public void onChanged(int position, int count) {
+ mEvents.add(new Event(TYPE.CHANGE, position, count));
mUpdates.add(new Pair(position, count));
if (mChangedCallback != null) {
mChangedCallback.onChanged(position, count);
}
+ pollAndRun(mCallbackRunnables);
}
@Override
@@ -110,7 +124,7 @@
@Override
public boolean areContentsTheSame(Item oldItem, Item newItem) {
- return oldItem.cmpField == newItem.cmpField && oldItem.data == newItem.data;
+ return oldItem.data == newItem.data;
}
@Override
@@ -127,11 +141,41 @@
return null;
}
};
- mInsertedCallback = null;
- mChangedCallback = null;
mList = new SortedList<Item>(Item.class, mCallback);
}
+ private void pollAndRun(Queue<AssertListStateRunnable> queue) {
+ if (queue != null) {
+ Runnable runnable = queue.poll();
+ assertNotNull(runnable);
+ runnable.run();
+ }
+ }
+
+ @Test
+ public void testValidMethodsDuringOnInsertedCallbackFromEmptyList() {
+
+ final Item[] items =
+ new Item[] {new Item(0), new Item(1), new Item(2)};
+
+ final AtomicInteger atomicInteger = new AtomicInteger(0);
+ mInsertedCallback = new InsertedCallback<Item>() {
+ @Override
+ public void onInserted(int position, int count) {
+ for (int i = 0; i < count; i++) {
+ assertEquals(mList.get(i), items[i]);
+ assertEquals(mList.indexOf(items[i]), i);
+ atomicInteger.incrementAndGet();
+ }
+ }
+ };
+
+ mList.add(items[0]);
+ mList.clear();
+ mList.addAll(items, false);
+ assertEquals(4, atomicInteger.get());
+ }
+
@Test
public void testEmpty() {
assertEquals("empty", mList.size(), 0);
@@ -139,16 +183,16 @@
@Test
public void testAdd() {
- Item item = new Item();
+ Item item = new Item(1);
assertEquals(insert(item), 0);
assertEquals(size(), 1);
assertTrue(mAdditions.contains(new Pair(0, 1)));
- Item item2 = new Item();
+ Item item2 = new Item(2);
item2.cmpField = item.cmpField + 1;
assertEquals(insert(item2), 1);
assertEquals(size(), 2);
assertTrue(mAdditions.contains(new Pair(1, 1)));
- Item item3 = new Item();
+ Item item3 = new Item(3);
item3.cmpField = item.cmpField - 1;
mAdditions.clear();
assertEquals(insert(item3), 0);
@@ -158,9 +202,8 @@
@Test
public void testAddDuplicate() {
- Item item = new Item();
- Item item2 = new Item(item.id, item.cmpField);
- item2.data = item.data;
+ Item item = new Item(1);
+ Item item2 = new Item(item.id);
insert(item);
assertEquals(0, insert(item2));
assertEquals(1, size());
@@ -170,7 +213,7 @@
@Test
public void testRemove() {
- Item item = new Item();
+ Item item = new Item(1);
assertFalse(remove(item));
assertEquals(0, mRemovals.size());
insert(item);
@@ -184,8 +227,8 @@
@Test
public void testRemove2() {
- Item item = new Item();
- Item item2 = new Item(item.cmpField);
+ Item item = new Item(1);
+ Item item2 = new Item(2, 1, 1);
insert(item);
assertFalse(remove(item2));
assertEquals(0, mRemovals.size());
@@ -218,11 +261,12 @@
Random random = new Random(System.nanoTime());
List<Item> copy = new ArrayList<Item>();
StringBuilder log = new StringBuilder();
+ int id = 1;
try {
for (int i = 0; i < 10000; i++) {
switch (random.nextInt(3)) {
case 0://ADD
- Item item = new Item();
+ Item item = new Item(id++);
copy.add(item);
insert(item);
log.append("add ").append(item).append("\n");
@@ -241,12 +285,13 @@
int index = random.nextInt(mList.size());
item = mList.get(index);
// TODO this cannot work
- Item newItem = new Item(item.id, item.cmpField);
- log.append("update ").append(item).append(" to ").append(newItem)
- .append("\n");
+ Item newItem =
+ new Item(item.id, item.cmpField, random.nextInt(1000));
while (newItem.data == item.data) {
newItem.data = random.nextInt(1000);
}
+ log.append("update ").append(item).append(" to ").append(newItem)
+ .append("\n");
int itemIndex = mList.add(newItem);
copy.remove(item);
copy.add(newItem);
@@ -258,10 +303,12 @@
if (copy.size() > 0) {
int index = random.nextInt(mList.size());
item = mList.get(index);
- Item newItem = new Item(item.id, random.nextInt());
+ Item newItem = new Item(item.id, random.nextInt(), random.nextInt());
mList.updateItemAt(index, newItem);
copy.remove(item);
copy.add(newItem);
+ log.append("update at ").append(index).append(" ").append(item)
+ .append(" to ").append(newItem).append("\n");
}
}
int lastCmp = Integer.MIN_VALUE;
@@ -299,14 +346,21 @@
Item[] items = new Item[count];
int id = idFrom;
for (int i = 0; i < count; i++) {
- Item item = new Item(id, id);
- item.data = id;
+ Item item = new Item(id);
items[i] = item;
id += idStep;
}
return items;
}
+ private static Item[] createItemsFromInts(int ... ints) {
+ Item[] items = new Item[ints.length];
+ for (int i = ints.length - 1; i >= 0; i--) {
+ items[i] = new Item(ints[i]);
+ }
+ return items;
+ }
+
private static Item[] shuffle(Item[] items) {
Random random = new Random(System.nanoTime());
final int count = items.length;
@@ -493,8 +547,7 @@
int uniqueId = 0;
for (int cmpField = 0; cmpField < maxCmpField; cmpField++) {
for (int id = 0; id < idsPerCmpField; id++) {
- Item item = new Item(uniqueId++, cmpField);
- item.data = generation;
+ Item item = new Item(uniqueId++, cmpField, generation);
items[index++] = item;
}
}
@@ -548,13 +601,13 @@
@Test
public void testAddAllStableSort() {
int id = 0;
- Item item = new Item(id++, 0);
+ Item item = new Item(id++, 0, 0);
mList.add(item);
// Create a few items with the same sort order.
Item[] items = new Item[3];
for (int i = 0; i < 3; i++) {
- items[i] = new Item(id++, item.cmpField);
+ items[i] = new Item(id++, item.cmpField, 0);
assertEquals(0, mCallback.compare(item, items[i]));
}
@@ -576,6 +629,7 @@
item.data = 1;
}
+
mInsertedCallback = new InsertedCallback<Item>() {
@Override
public void onInserted(int position, int count) {
@@ -585,6 +639,7 @@
assertEquals(i * 2, mList.get(i).id);
}
assertIntegrity(5, "onInserted(" + position + ", " + count + ")");
+
}
};
@@ -639,7 +694,7 @@
@Override
public void onInserted(int position, int count) {
try {
- mList.add(new Item());
+ mList.add(new Item(1));
fail("add must throw from within a callback");
} catch (IllegalStateException e) {
}
@@ -729,14 +784,14 @@
@Test
public void testAddExistingItemCallsChangeWithPayload() {
mList.addAll(
- new Item(1, 10),
- new Item(2, 20),
- new Item(3, 30)
+ new Item(1),
+ new Item(2),
+ new Item(3)
);
mPayloadChanges = true;
// add an item with the same id but a new data field i.e. send an update
- final Item twoUpdate = new Item(2, 20);
+ final Item twoUpdate = new Item(2);
twoUpdate.data = 1337;
mList.add(twoUpdate);
assertEquals(1, mPayloadUpdates.size());
@@ -750,14 +805,14 @@
@Test
public void testUpdateItemCallsChangeWithPayload() {
mList.addAll(
- new Item(1, 10),
- new Item(2, 20),
- new Item(3, 30)
+ new Item(1),
+ new Item(2),
+ new Item(3)
);
mPayloadChanges = true;
// add an item with the same id but a new data field i.e. send an update
- final Item twoUpdate = new Item(2, 20);
+ final Item twoUpdate = new Item(2);
twoUpdate.data = 1337;
mList.updateItemAt(1, twoUpdate);
assertEquals(1, mPayloadUpdates.size());
@@ -772,16 +827,16 @@
@Test
public void testAddMultipleExistingItemCallsChangeWithPayload() {
mList.addAll(
- new Item(1, 10),
- new Item(2, 20),
- new Item(3, 30)
+ new Item(1),
+ new Item(2),
+ new Item(3)
);
mPayloadChanges = true;
// add two items with the same ids but a new data fields i.e. send two updates
- final Item twoUpdate = new Item(2, 20);
+ final Item twoUpdate = new Item(2);
twoUpdate.data = 222;
- final Item threeUpdate = new Item(3, 30);
+ final Item threeUpdate = new Item(3);
threeUpdate.data = 333;
mList.addAll(twoUpdate, threeUpdate);
assertEquals(2, mPayloadUpdates.size());
@@ -796,6 +851,648 @@
assertEquals(3, size());
}
+ @Test
+ public void replaceAll_mayModifyInputFalse_doesNotModify() {
+ mList.addAll(
+ new Item(1),
+ new Item(2)
+ );
+ Item replacement0 = new Item(4);
+ Item replacement1 = new Item(3);
+ Item[] replacements = new Item[]{
+ replacement0,
+ replacement1
+ };
+
+ mList.replaceAll(replacements, false);
+
+ assertSame(replacement0, replacements[0]);
+ assertSame(replacement1, replacements[1]);
+ }
+
+ @Test
+ public void replaceAll_varArgs_isEquivalentToDefault() {
+ mList.addAll(
+ new Item(1),
+ new Item(2)
+ );
+ Item replacement0 = new Item(3);
+ Item replacement1 = new Item(4);
+
+ mList.replaceAll(replacement0, replacement1);
+
+ assertEquals(mList.get(0), replacement0);
+ assertEquals(mList.get(1), replacement1);
+ assertEquals(2, mList.size());
+ }
+
+ @Test
+ public void replaceAll_collection_isEquivalentToDefaultWithMayModifyInputFalse() {
+ mList.addAll(
+ new Item(1),
+ new Item(2)
+ );
+ Item replacement0 = new Item(4);
+ Item replacement1 = new Item(3);
+ List<Item> replacements = new ArrayList<>();
+ replacements.add(replacement0);
+ replacements.add(replacement1);
+
+ mList.replaceAll(replacements);
+
+ assertEquals(mList.get(0), replacement1);
+ assertEquals(mList.get(1), replacement0);
+ assertSame(replacements.get(0), replacement0);
+ assertSame(replacements.get(1), replacement1);
+ assertEquals(2, mList.size());
+ }
+
+ @Test
+ public void replaceAll_callsChangeWithPayload() {
+ mList.addAll(
+ new Item(1),
+ new Item(2),
+ new Item(3)
+ );
+ mPayloadChanges = true;
+ final Item twoUpdate = new Item(2);
+ twoUpdate.data = 222;
+ final Item threeUpdate = new Item(3);
+ threeUpdate.data = 333;
+
+ mList.replaceAll(twoUpdate, threeUpdate);
+
+ assertEquals(2, mPayloadUpdates.size());
+ final PayloadChange update1 = mPayloadUpdates.get(0);
+ assertEquals(0, update1.position);
+ assertEquals(1, update1.count);
+ assertEquals(222, update1.payload);
+ final PayloadChange update2 = mPayloadUpdates.get(1);
+ assertEquals(1, update2.position);
+ assertEquals(1, update2.count);
+ assertEquals(333, update2.payload);
+ }
+
+ @Test
+ public void replaceAll_totallyEquivalentData_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(1, 2, 3);
+ Item[] items2 = createItemsFromInts(1, 2, 3);
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mList.replaceAll(items2);
+
+ assertEquals(0, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ }
+
+ @Test
+ public void replaceAll_removalsAndAdds1_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(1, 3, 5);
+ Item[] items2 = createItemsFromInts(2, 4);
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(createItemsFromInts(2, 3, 5)));
+ mCallbackRunnables.add(new AssertListStateRunnable(createItemsFromInts(2, 5)));
+ mCallbackRunnables.add(new AssertListStateRunnable(createItemsFromInts(2, 4, 5)));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.REMOVE, 0, 1), mEvents.get(0));
+ assertEquals(new Event(TYPE.ADD, 0, 1), mEvents.get(1));
+ assertEquals(new Event(TYPE.REMOVE, 1, 1), mEvents.get(2));
+ assertEquals(new Event(TYPE.ADD, 1, 1), mEvents.get(3));
+ assertEquals(new Event(TYPE.REMOVE, 2, 1), mEvents.get(4));
+ assertEquals(5, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_removalsAndAdds2_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(2, 4);
+ Item[] items2 = createItemsFromInts(1, 3, 5);
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(createItemsFromInts(1, 4)));
+ mCallbackRunnables.add(new AssertListStateRunnable(createItemsFromInts(1, 3, 4)));
+ mCallbackRunnables.add(new AssertListStateRunnable(createItemsFromInts(1, 3)));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.ADD, 0, 1), mEvents.get(0));
+ assertEquals(new Event(TYPE.REMOVE, 1, 1), mEvents.get(1));
+ assertEquals(new Event(TYPE.ADD, 1, 1), mEvents.get(2));
+ assertEquals(new Event(TYPE.REMOVE, 2, 1), mEvents.get(3));
+ assertEquals(new Event(TYPE.ADD, 2, 1), mEvents.get(4));
+ assertEquals(5, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_removalsAndAdds3_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(1, 3, 5);
+ Item[] items2 = createItemsFromInts(2, 3, 4);
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(createItemsFromInts(2, 3, 5)));
+ mCallbackRunnables.add(new AssertListStateRunnable(createItemsFromInts(2, 3, 4, 5)));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.REMOVE, 0, 1), mEvents.get(0));
+ assertEquals(new Event(TYPE.ADD, 0, 1), mEvents.get(1));
+ assertEquals(new Event(TYPE.ADD, 2, 1), mEvents.get(2));
+ assertEquals(new Event(TYPE.REMOVE, 3, 1), mEvents.get(3));
+ assertEquals(4, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_removalsAndAdds4_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(2, 3, 4);
+ Item[] items2 = createItemsFromInts(1, 3, 5);
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(createItemsFromInts(1, 3, 4)));
+ mCallbackRunnables.add(new AssertListStateRunnable(createItemsFromInts(1, 3)));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.ADD, 0, 1), mEvents.get(0));
+ assertEquals(new Event(TYPE.REMOVE, 1, 1), mEvents.get(1));
+ assertEquals(new Event(TYPE.REMOVE, 2, 1), mEvents.get(2));
+ assertEquals(new Event(TYPE.ADD, 2, 1), mEvents.get(3));
+ assertEquals(4, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_removalsAndAdds5_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(1, 2, 3);
+ Item[] items2 = createItemsFromInts(3, 4, 5);
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.REMOVE, 0, 2), mEvents.get(0));
+ assertEquals(new Event(TYPE.ADD, 1, 2), mEvents.get(1));
+ assertEquals(2, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_removalsAndAdds6_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(3, 4, 5);
+ Item[] items2 = createItemsFromInts(1, 2, 3);
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.ADD, 0, 2), mEvents.get(0));
+ assertEquals(new Event(TYPE.REMOVE, 3, 2), mEvents.get(1));
+ assertEquals(2, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_move1_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(1, 2, 3);
+ Item[] items2 = new Item[]{
+ new Item(2),
+ new Item(3),
+ new Item(1, 4, 1)};
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.REMOVE, 0, 1), mEvents.get(0));
+ assertEquals(new Event(TYPE.ADD, 2, 1), mEvents.get(1));
+ assertEquals(2, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_move2_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(1, 2, 3);
+ Item[] items2 = new Item[]{
+ new Item(3, 0, 3),
+ new Item(1),
+ new Item(2)};
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.ADD, 0, 1), mEvents.get(0));
+ assertEquals(new Event(TYPE.REMOVE, 3, 1), mEvents.get(1));
+ assertEquals(2, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_move3_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(1, 3, 5, 7, 9);
+ Item[] items2 = new Item[]{
+ new Item(3, 0, 3),
+ new Item(1),
+ new Item(5),
+ new Item(9),
+ new Item(7, 10, 7),
+ };
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(3, 0, 3),
+ new Item(1),
+ new Item(5),
+ new Item(7),
+ new Item(9)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(3, 0, 3),
+ new Item(1),
+ new Item(5),
+ new Item(9)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.ADD, 0, 1), mEvents.get(0));
+ assertEquals(new Event(TYPE.REMOVE, 2, 1), mEvents.get(1));
+ assertEquals(new Event(TYPE.REMOVE, 3, 1), mEvents.get(2));
+ assertEquals(new Event(TYPE.ADD, 4, 1), mEvents.get(3));
+ assertEquals(4, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_move4_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(1, 3, 5, 7, 9);
+ Item[] items2 = new Item[]{
+ new Item(3),
+ new Item(1, 4, 1),
+ new Item(5),
+ new Item(9, 6, 9),
+ new Item(7),
+ };
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(3),
+ new Item(1, 4, 1),
+ new Item(5),
+ new Item(7),
+ new Item(9)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(3),
+ new Item(1, 4, 1),
+ new Item(5),
+ new Item(9, 6, 9),
+ new Item(7),
+ new Item(9)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.REMOVE, 0, 1), mEvents.get(0));
+ assertEquals(new Event(TYPE.ADD, 1, 1), mEvents.get(1));
+ assertEquals(new Event(TYPE.ADD, 3, 1), mEvents.get(2));
+ assertEquals(new Event(TYPE.REMOVE, 5, 1), mEvents.get(3));
+ assertEquals(4, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_move5_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(1, 3, 5, 7, 9);
+ Item[] items2 = new Item[]{
+ new Item(9, 1, 9),
+ new Item(7, 3, 7),
+ new Item(5),
+ new Item(3, 7, 3),
+ new Item(1, 9, 1),
+ };
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(9, 1, 9),
+ new Item(3),
+ new Item(5),
+ new Item(7),
+ new Item(9)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(9, 1, 9),
+ new Item(5),
+ new Item(7),
+ new Item(9)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(9, 1, 9),
+ new Item(7, 3, 7),
+ new Item(5),
+ new Item(7),
+ new Item(9)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(9, 1, 9),
+ new Item(7, 3, 7),
+ new Item(5),
+ new Item(9)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(9, 1, 9),
+ new Item(7, 3, 7),
+ new Item(5),
+ new Item(3, 7, 3),
+ new Item(9)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(9, 1, 9),
+ new Item(7, 3, 7),
+ new Item(5),
+ new Item(3, 7, 3)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.REMOVE, 0, 1), mEvents.get(0));
+ assertEquals(new Event(TYPE.ADD, 0, 1), mEvents.get(1));
+ assertEquals(new Event(TYPE.REMOVE, 1, 1), mEvents.get(2));
+ assertEquals(new Event(TYPE.ADD, 1, 1), mEvents.get(3));
+ assertEquals(new Event(TYPE.REMOVE, 3, 1), mEvents.get(4));
+ assertEquals(new Event(TYPE.ADD, 3, 1), mEvents.get(5));
+ assertEquals(new Event(TYPE.REMOVE, 4, 1), mEvents.get(6));
+ assertEquals(new Event(TYPE.ADD, 4, 1), mEvents.get(7));
+ assertEquals(8, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_orderSameItemDifferent_worksCorrectly() {
+ Item[] items1 = new Item[]{
+ new Item(1),
+ new Item(2, 3, 2),
+ new Item(5)
+ };
+ Item[] items2 = new Item[]{
+ new Item(1),
+ new Item(4, 3, 4),
+ new Item(5)
+ };
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.REMOVE, 1, 1), mEvents.get(0));
+ assertEquals(new Event(TYPE.ADD, 1, 1), mEvents.get(1));
+ assertEquals(2, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_orderSameItemSameContentsDifferent_worksCorrectly() {
+ Item[] items1 = new Item[]{
+ new Item(1),
+ new Item(3, 3, 2),
+ new Item(5)
+ };
+ Item[] items2 = new Item[]{
+ new Item(1),
+ new Item(3, 3, 4),
+ new Item(5)
+ };
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.CHANGE, 1, 1), mEvents.get(0));
+ assertEquals(1, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_allTypesOfChanges1_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(2, 5, 6);
+ Item[] items2 = new Item[]{
+ new Item(1),
+ new Item(3, 2, 3),
+ new Item(6, 6, 7)
+ };
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(createItemsFromInts(1, 5, 6)));
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(1),
+ new Item(3, 2, 3),
+ new Item(5),
+ new Item(6)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(1),
+ new Item(3, 2, 3),
+ new Item(6)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.ADD, 0, 1), mEvents.get(0));
+ assertEquals(new Event(TYPE.REMOVE, 1, 1), mEvents.get(1));
+ assertEquals(new Event(TYPE.ADD, 1, 1), mEvents.get(2));
+ assertEquals(new Event(TYPE.REMOVE, 2, 1), mEvents.get(3));
+ assertEquals(new Event(TYPE.CHANGE, 2, 1), mEvents.get(4));
+ assertEquals(5, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_allTypesOfChanges2_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(1, 4, 6);
+ Item[] items2 = new Item[]{
+ new Item(1, 1, 2),
+ new Item(3),
+ new Item(5, 4, 5)
+ };
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(1, 1, 2),
+ new Item(3),
+ new Item(4),
+ new Item(6)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(1, 1, 2),
+ new Item(3),
+ new Item(6)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(1, 1, 2),
+ new Item(3),
+ new Item(5, 4, 5),
+ new Item(6)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.CHANGE, 0, 1), mEvents.get(0));
+ assertEquals(new Event(TYPE.ADD, 1, 1), mEvents.get(1));
+ assertEquals(new Event(TYPE.REMOVE, 2, 1), mEvents.get(2));
+ assertEquals(new Event(TYPE.ADD, 2, 1), mEvents.get(3));
+ assertEquals(new Event(TYPE.REMOVE, 3, 1), mEvents.get(4));
+ assertEquals(5, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_allTypesOfChanges3_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(1, 2);
+ Item[] items2 = new Item[]{
+ new Item(2, 2, 3),
+ new Item(3, 2, 4),
+ new Item(5)
+ };
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(
+ new Item(2, 2, 3)
+ ));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.replaceAll(items2);
+
+ assertEquals(new Event(TYPE.REMOVE, 0, 1), mEvents.get(0));
+ assertEquals(new Event(TYPE.CHANGE, 0, 1), mEvents.get(1));
+ assertEquals(new Event(TYPE.ADD, 1, 2), mEvents.get(2));
+ assertEquals(3, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
+ @Test
+ public void replaceAll_newItemsAreIdentical_resultIsDeduped() {
+ Item[] items = createItemsFromInts(1, 1);
+ mList.replaceAll(items);
+
+ assertEquals(new Item(1), mList.get(0));
+ assertEquals(1, mList.size());
+ }
+
+ @Test
+ public void replaceAll_newItemsUnsorted_resultIsSorted() {
+ Item[] items = createItemsFromInts(2, 1);
+ mList.replaceAll(items);
+
+ assertEquals(new Item(1), mList.get(0));
+ assertEquals(new Item(2), mList.get(1));
+ assertEquals(2, mList.size());
+ }
+
+ @Test
+ public void replaceAll_calledAfterBeginBatchedUpdates_worksCorrectly() {
+ Item[] items1 = createItemsFromInts(1, 2, 3);
+ Item[] items2 = createItemsFromInts(4, 5, 6);
+ mList.addAll(items1);
+ mEvents.clear();
+
+ mCallbackRunnables = new LinkedList<>();
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+ mCallbackRunnables.add(new AssertListStateRunnable(items2));
+
+ mList.beginBatchedUpdates();
+ mList.replaceAll(items2);
+ mList.endBatchedUpdates();
+
+ assertEquals(new Event(TYPE.REMOVE, 0, 3), mEvents.get(0));
+ assertEquals(new Event(TYPE.ADD, 0, 3), mEvents.get(1));
+ assertEquals(2, mEvents.size());
+ assertTrue(sortedListEquals(mList, items2));
+ assertTrue(mCallbackRunnables.isEmpty());
+ }
+
private int size() {
return mList.size();
}
@@ -810,63 +1507,33 @@
static class Item {
- static int idCounter = 0;
final int id;
-
int cmpField;
+ int data;
- int data = (int) (Math.random() * 1000);//used for comparison
-
- public Item() {
- id = idCounter++;
- cmpField = (int) (Math.random() * 1000);
+ Item(int allFields) {
+ this(allFields, allFields, allFields);
}
- public Item(int cmpField) {
- id = idCounter++;
- this.cmpField = cmpField;
- }
-
- public Item(int id, int cmpField) {
+ Item(int id, int compField, int data) {
this.id = id;
- this.cmpField = cmpField;
+ this.cmpField = compField;
+ this.data = data;
}
@Override
public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
Item item = (Item) o;
- if (cmpField != item.cmpField) {
- return false;
- }
- if (id != item.id) {
- return false;
- }
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = id;
- result = 31 * result + cmpField;
- return result;
+ return id == item.id && cmpField == item.cmpField && data == item.data;
}
@Override
public String toString() {
- return "Item{" +
- "id=" + id +
- ", cmpField=" + cmpField +
- ", data=" + data +
- '}';
+ return "Item(id=" + id + ", cmpField=" + cmpField + ", data=" + data + ')';
}
}
@@ -913,6 +1580,85 @@
}
}
+ private enum TYPE {
+ ADD, REMOVE, MOVE, CHANGE
+ }
+
+ private final class AssertListStateRunnable implements Runnable {
+
+ private Item[] mExpectedItems;
+
+ AssertListStateRunnable(Item... expectedItems) {
+ this.mExpectedItems = expectedItems;
+ }
+
+ @Override
+ public void run() {
+ try {
+ assertEquals(mExpectedItems.length, mList.size());
+ for (int i = mExpectedItems.length - 1; i >= 0; i--) {
+ assertEquals(mExpectedItems[i], mList.get(i));
+ assertEquals(i, mList.indexOf(mExpectedItems[i]));
+ }
+ } catch (AssertionError assertionError) {
+ throw new AssertionError(
+ assertionError.getMessage()
+ + "\nExpected: "
+ + Arrays.toString(mExpectedItems)
+ + "\nActual: "
+ + sortedListToString(mList));
+ }
+ }
+ }
+
+ private static final class Event {
+ private final TYPE mType;
+ private final int mVal1;
+ private final int mVal2;
+
+ Event(TYPE type, int val1, int val2) {
+ this.mType = type;
+ this.mVal1 = val1;
+ this.mVal2 = val2;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Event that = (Event) o;
+ return mType == that.mType && mVal1 == that.mVal1 && mVal2 == that.mVal2;
+ }
+
+ @Override
+ public String toString() {
+ return "Event(" + mType + ", " + mVal1 + ", " + mVal2 + ")";
+ }
+ }
+
+ private <T> boolean sortedListEquals(SortedList<T> sortedList, T[] array) {
+ if (sortedList.size() != array.length) {
+ return false;
+ }
+ for (int i = sortedList.size() - 1; i >= 0; i--) {
+ if (!sortedList.get(i).equals(array[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static String sortedListToString(SortedList sortedList) {
+ StringBuilder stringBuilder = new StringBuilder("[");
+ int size = sortedList.size();
+ for (int i = 0; i < size; i++) {
+ stringBuilder.append(sortedList.get(i).toString() + ", ");
+ }
+ stringBuilder.delete(stringBuilder.length() - 2, stringBuilder.length());
+ stringBuilder.append("]");
+ return stringBuilder.toString();
+ }
+
private static final class PayloadChange {
public final int position;
public final int count;
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/ImeCleanUpTestRule.java b/v7/recyclerview/tests/src/android/support/v7/util/ImeCleanUpTestRule.java
deleted file mode 100644
index f4caad3..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/util/ImeCleanUpTestRule.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 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 android.support.v7.util;
-
-import android.graphics.Rect;
-import android.support.testutils.PollingCheck;
-import android.view.View;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * A JUnit rule that ensures that IME is closed after a test is finished (or exception thrown).
- * A test that triggers IME open/close should call setContainerView with the activity's container
- * view in order to trigger this cleanup at the end of the test. Otherwise, no cleanup happens.
- */
-public class ImeCleanUpTestRule implements TestRule {
-
- private View mContainerView;
-
- @Override
- public Statement apply(final Statement base, Description description) {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- try {
- base.evaluate();
- } finally {
- closeImeIfOpen();
- }
- }
- };
- }
-
- /**
- * Sets the container view used to calculate the total screen height and the height available
- * to the test activity.
- */
- public void setContainerView(View containerView) {
- mContainerView = containerView;
- }
-
- private void closeImeIfOpen() {
- if (mContainerView == null) {
- return;
- }
- // Ensuring that IME is closed after starting each test.
- final Rect r = new Rect();
- mContainerView.getWindowVisibleDisplayFrame(r);
- // This is the entire height of the screen available to both the view and IME
- final int screenHeight = mContainerView.getRootView().getHeight();
-
- // r.bottom is the position above IME if it's open or device button.
- // if IME is shown, r.bottom is smaller than screenHeight.
- int imeHeight = screenHeight - r.bottom;
-
- // Picking a threshold to detect when IME is open
- if (imeHeight > screenHeight * 0.15) {
- // Soft keyboard is shown, will wait for it to close after running the test. Note that
- // we don't press back button here as the IME should close by itself when a test
- // finishes. If the wait isn't done here, the IME can mess up with the layout of the
- // next test.
- PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
- @Override
- public boolean canProceed() {
- mContainerView.getWindowVisibleDisplayFrame(r);
- int imeHeight = screenHeight - r.bottom;
- return imeHeight < screenHeight * 0.15;
- }
- });
- }
- }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
index 13dd1e4..f4a8e37 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
@@ -325,16 +325,16 @@
}
}
- class GridEditTextAdapter extends EditTextAdapter {
+ class GridFocusableAdapter extends FocusableAdapter {
Set<Integer> mFullSpanItems = new HashSet<Integer>();
int mSpanPerItem = 1;
- GridEditTextAdapter(int count) {
+ GridFocusableAdapter(int count) {
this(count, 1);
}
- GridEditTextAdapter(int count, int spanPerItem) {
+ GridFocusableAdapter(int count, int spanPerItem) {
super(count);
mSpanPerItem = spanPerItem;
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
index 157fb12..eed7d20 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
@@ -35,14 +35,13 @@
import android.support.annotation.Nullable;
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
+import android.support.testutils.PollingCheck;
import android.support.v4.view.ViewCompat;
import android.support.v7.recyclerview.test.R;
-import android.text.Editable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;
@@ -325,6 +324,12 @@
result[0] = view.requestFocus();
}
});
+ PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+ @Override
+ public boolean canProceed() {
+ return view.hasFocus();
+ }
+ });
if (waitForScroll && result[0]) {
waitForIdleScroll(mRecyclerView);
}
@@ -789,34 +794,32 @@
}
}
- public class EditTextAdapter extends RecyclerView.Adapter<TestViewHolder> {
+ public class FocusableAdapter extends RecyclerView.Adapter<TestViewHolder> {
- final ArrayList<Editable> mEditables;
- public EditTextAdapter(int count) {
- mEditables = new ArrayList<>();
- for (int i = 0; i < count; ++i) {
- mEditables.add(Editable.Factory.getInstance().newEditable("Sample Text " + i));
- }
+ private int mCount;
+
+ FocusableAdapter(int count) {
+ mCount = count;
}
@Override
public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- final EditText editText = new EditText(parent.getContext());
- editText.setLayoutParams(new ViewGroup.LayoutParams(
+ final TextView textView = new TextView(parent.getContext());
+ textView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
- final TestViewHolder viewHolder = new TestViewHolder(editText);
- return viewHolder;
+ textView.setFocusable(true);
+ textView.setBackgroundResource(R.drawable.item_bg);
+ return new TestViewHolder(textView);
}
@Override
public void onBindViewHolder(TestViewHolder holder, int position) {
- ((EditText) holder.itemView).setText(Editable.Factory.getInstance().newEditable(
- mEditables.get(position)));
+ ((TextView) holder.itemView).setText("Item " + position);
}
@Override
public int getItemCount() {
- return mEditables.size();
+ return mCount;
}
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/DummyItemAnimator.java b/v7/recyclerview/tests/src/android/support/v7/widget/DummyItemAnimator.java
new file mode 100644
index 0000000..a1491fa
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/DummyItemAnimator.java
@@ -0,0 +1,263 @@
+/*
+ * 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 android.support.v7.widget;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This is a dummy ItemAnimator class that does not depends on Duration, Tests would use this class
+ * to control whenever they want the Animator to finish.
+ * 1. Test MUST call endAnimation(ViewHolder) on UI thread to finish animation of a given ViewHolder
+ * Or Test calls endAnimations() on UI thread to end animations for all.
+ * 2. Test can call getAddAnimations() etc. to get ViewHolders that currently running animation.
+ * 3. Test can call {@link #expect(int, int)} and {@link #waitFor(int)} to wait given
+ * Events are fired.
+ */
+public class DummyItemAnimator extends SimpleItemAnimator {
+
+ static final long TIMEOUT_SECOND = 10;
+
+ ArrayList<RecyclerView.ViewHolder> mAdds = new ArrayList();
+ ArrayList<RecyclerView.ViewHolder> mRemoves = new ArrayList();
+ ArrayList<RecyclerView.ViewHolder> mMoves = new ArrayList();
+ ArrayList<RecyclerView.ViewHolder> mChangesOld = new ArrayList();
+ ArrayList<RecyclerView.ViewHolder> mChangesNew = new ArrayList();
+
+ @Retention(CLASS)
+ @Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD})
+ public @interface CountDownLatchIndex {
+ }
+
+ @CountDownLatchIndex
+ public static final int ADD_START = 0;
+
+ @CountDownLatchIndex
+ public static final int ADD_FINISHED = 1;
+
+ @CountDownLatchIndex
+ public static final int REMOVE_START = 2;
+
+ @CountDownLatchIndex
+ public static final int REMOVE_FINISHED = 3;
+
+ @CountDownLatchIndex
+ public static final int MOVE_START = 4;
+
+ @CountDownLatchIndex
+ public static final int MOVE_FINISHED = 5;
+
+ @CountDownLatchIndex
+ public static final int CHANGE_OLD_START = 6;
+
+ @CountDownLatchIndex
+ public static final int CHANGE_OLD_FINISHED = 7;
+
+ @CountDownLatchIndex
+ public static final int CHANGE_NEW_START = 8;
+
+ @CountDownLatchIndex
+ public static final int CHANGE_NEW_FINISHED = 9;
+
+ static final int NUM_COUNT_DOWN_LATCH = 10;
+
+ CountDownLatch[] mCountDownLatches = new CountDownLatch[NUM_COUNT_DOWN_LATCH];
+
+
+ public List<RecyclerView.ViewHolder> getAddAnimations() {
+ return mAdds;
+ }
+
+ public List<RecyclerView.ViewHolder> getRemoveAnimations() {
+ return mRemoves;
+ }
+
+ public List<RecyclerView.ViewHolder> getMovesAnimations() {
+ return mMoves;
+ }
+
+ public List<RecyclerView.ViewHolder> getChangesOldAnimations() {
+ return mChangesOld;
+ }
+
+ public List<RecyclerView.ViewHolder> getChangesNewAnimations() {
+ return mChangesNew;
+ }
+
+ @Override
+ public boolean animateRemove(RecyclerView.ViewHolder holder) {
+ mRemoves.add(holder);
+ dispatchRemoveStarting(holder);
+ return false;
+ }
+
+ @Override
+ public boolean animateAdd(RecyclerView.ViewHolder holder) {
+ mAdds.add(holder);
+ dispatchAddStarting(holder);
+ return false;
+ }
+
+ @Override
+ public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX,
+ int toY) {
+ mMoves.add(holder);
+ dispatchMoveStarting(holder);
+ return false;
+ }
+
+ @Override
+ public boolean animateChange(RecyclerView.ViewHolder oldHolder,
+ RecyclerView.ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop) {
+ mChangesOld.add(oldHolder);
+ mChangesNew.add(newHolder);
+ dispatchChangeStarting(oldHolder, true);
+ dispatchChangeStarting(newHolder, false);
+ return false;
+ }
+
+ public void expect(@CountDownLatchIndex int index, int count) {
+ mCountDownLatches[index] = new CountDownLatch(count);
+ }
+
+ public void waitFor(@CountDownLatchIndex int index)
+ throws InterruptedException {
+ mCountDownLatches[index].await(TIMEOUT_SECOND, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public void onChangeStarting(RecyclerView.ViewHolder item, boolean oldItem) {
+ CountDownLatch latch = mCountDownLatches[oldItem ? CHANGE_OLD_START : CHANGE_NEW_START];
+ if (latch != null) {
+ latch.countDown();
+ }
+ }
+
+ @Override
+ public void onMoveStarting(RecyclerView.ViewHolder item) {
+ CountDownLatch latch = mCountDownLatches[MOVE_START];
+ if (latch != null) {
+ latch.countDown();
+ }
+ }
+
+ @Override
+ public void onAddStarting(RecyclerView.ViewHolder item) {
+ CountDownLatch latch = mCountDownLatches[ADD_START];
+ if (latch != null) {
+ latch.countDown();
+ }
+ }
+
+ @Override
+ public void onRemoveStarting(RecyclerView.ViewHolder item) {
+ CountDownLatch latch = mCountDownLatches[REMOVE_START];
+ if (latch != null) {
+ latch.countDown();
+ }
+ }
+
+ @Override
+ public void onChangeFinished(RecyclerView.ViewHolder item, boolean oldItem) {
+ CountDownLatch latch = mCountDownLatches[oldItem
+ ? CHANGE_OLD_FINISHED : CHANGE_NEW_FINISHED];
+ if (latch != null) {
+ latch.countDown();
+ }
+ }
+
+ @Override
+ public void onMoveFinished(RecyclerView.ViewHolder item) {
+ CountDownLatch latch = mCountDownLatches[MOVE_FINISHED];
+ if (latch != null) {
+ latch.countDown();
+ }
+ }
+
+ @Override
+ public void onAddFinished(RecyclerView.ViewHolder item) {
+ CountDownLatch latch = mCountDownLatches[ADD_FINISHED];
+ if (latch != null) {
+ latch.countDown();
+ }
+ }
+
+ @Override
+ public void onRemoveFinished(RecyclerView.ViewHolder item) {
+ CountDownLatch latch = mCountDownLatches[REMOVE_FINISHED];
+ if (latch != null) {
+ latch.countDown();
+ }
+ }
+
+ @Override
+ public void runPendingAnimations() {
+ }
+
+ @Override
+ public void endAnimation(RecyclerView.ViewHolder item) {
+ if (mAdds.remove(item)) {
+ dispatchAddFinished(item);
+ } else if (mRemoves.remove(item)) {
+ dispatchRemoveFinished(item);
+ } else if (mMoves.remove(item)) {
+ dispatchMoveFinished(item);
+ } else if (mChangesOld.remove(item)) {
+ dispatchChangeFinished(item, true);
+ } else if (mChangesNew.remove(item)) {
+ dispatchChangeFinished(item, false);
+ }
+ }
+
+ @Override
+ public void endAnimations() {
+ for (int i = mAdds.size() - 1; i >= 0; i--) {
+ endAnimation(mAdds.get(i));
+ }
+ for (int i = mRemoves.size() - 1; i >= 0; i--) {
+ endAnimation(mRemoves.get(i));
+ }
+ for (int i = mMoves.size() - 1; i >= 0; i--) {
+ endAnimation(mMoves.get(i));
+ }
+ for (int i = mChangesOld.size() - 1; i >= 0; i--) {
+ endAnimation(mChangesOld.get(i));
+ }
+ for (int i = mChangesNew.size() - 1; i >= 0; i--) {
+ endAnimation(mChangesNew.get(i));
+ }
+ }
+
+ @Override
+ public boolean isRunning() {
+ return mAdds.size() != 0
+ || mRemoves.size() != 0
+ || mMoves.size() != 0
+ || mChangesOld.size() != 0
+ || mChangesNew.size() != 0;
+ }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
index 23eaf52..1a5892d 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
@@ -20,7 +20,6 @@
import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
@@ -37,20 +36,15 @@
import android.support.test.filters.LargeTest;
import android.support.test.filters.SdkSuppress;
import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
import android.support.v4.view.AccessibilityDelegateCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v7.util.ImeCleanUpTestRule;
-import android.support.v7.util.TouchUtils;
import android.test.UiThreadTest;
import android.util.SparseIntArray;
import android.util.StateSet;
-import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import org.hamcrest.CoreMatchers;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -64,9 +58,6 @@
@RunWith(AndroidJUnit4.class)
public class GridLayoutManagerTest extends BaseGridLayoutManagerTest {
- @Rule
- public final ImeCleanUpTestRule imeCleanUp = new ImeCleanUpTestRule();
-
@Test
public void focusSearchFailureUp() throws Throwable {
focusSearchFailure(false);
@@ -179,100 +170,140 @@
}
}
+ /**
+ * Tests that the GridLayoutManager retains the focused element after multiple measure
+ * calls to the RecyclerView. There was a bug where the focused view was lost when the soft
+ * keyboard opened. This test simulates the measure/layout events triggered by the opening
+ * of the soft keyboard by making two calls to measure. A simulation was done because using
+ * the soft keyboard in the test caused many issues on API levels 15, 17 and 19.
+ */
@Test
- public void editTextVisibility() throws Throwable {
+ public void focusedChildStaysInViewWhenRecyclerViewShrinks() throws Throwable {
+
+ // Arrange.
+
final int spanCount = 3;
final int itemCount = 100;
- imeCleanUp.setContainerView(getActivity().getContainer());
- RecyclerView recyclerView = new WrappedRecyclerView(getActivity());
- GridEditTextAdapter editTextAdapter = new GridEditTextAdapter(itemCount) {
- @Override
- public TestViewHolder onCreateViewHolder(ViewGroup parent,
- int viewType) {
- TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation using this for kitkat tests
- testViewHolder.itemView.setBackgroundDrawable(stl);
- return testViewHolder;
- }
- };
- mActivityRule.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mActivityRule.getActivity().getWindow().setSoftInputMode(SOFT_INPUT_ADJUST_RESIZE);
- }
- });
-
- recyclerView.setLayoutParams(
- new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ final RecyclerView recyclerView = inflateWrappedRV();
+ ViewGroup.LayoutParams lp = recyclerView.getLayoutParams();
+ lp.height = WRAP_CONTENT;
+ lp.width = MATCH_PARENT;
Config config = new Config(spanCount, itemCount);
mGlm = new WrappedGridLayoutManager(getActivity(), config.mSpanCount, config.mOrientation,
config.mReverseLayout);
- editTextAdapter.assignSpanSizeLookup(mGlm);
- recyclerView.setAdapter(editTextAdapter);
recyclerView.setLayoutManager(mGlm);
- waitForFirstLayout(recyclerView);
- // First focus on the last fully visible EditText located at span index #1.
- View toFocus = findLastFullyVisibleChild(mRecyclerView);
- int focusIndex = mRecyclerView.getChildAdapterPosition(toFocus);
- focusIndex = (focusIndex / spanCount) * spanCount + 1;
- toFocus = mRecyclerView.findViewHolderForAdapterPosition(focusIndex).itemView;
- assertTrue(focusIndex >= 1 && focusIndex < itemCount);
+ GridFocusableAdapter gridFocusableAdapter = new GridFocusableAdapter(itemCount);
+ gridFocusableAdapter.assignSpanSizeLookup(mGlm);
+ recyclerView.setAdapter(gridFocusableAdapter);
- final int heightBeforeImeOpen = mRecyclerView.getHeight();
- TouchUtils.tapView(getInstrumentation(), mRecyclerView, toFocus);
- getInstrumentation().waitForIdleSync();
- // Wait for IME to pop up.
- PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+ mGlm.expectLayout(1);
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
- public boolean canProceed() {
- return mRecyclerView.getHeight() < heightBeforeImeOpen;
+ public void run() {
+ getActivity().getContainer().addView(recyclerView);
}
});
+ mGlm.waitForLayout(3);
+
+ int width = recyclerView.getWidth();
+ int height = recyclerView.getHeight();
+ final int widthMeasureSpec =
+ View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
+ final int fullHeightMeasureSpec =
+ View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
+ // "MinusOne" so that a measure call will appropriately trigger onMeasure after RecyclerView
+ // was previously laid out with the full height version.
+ final int fullHeightMinusOneMeasureSpec =
+ View.MeasureSpec.makeMeasureSpec(height - 1, View.MeasureSpec.AT_MOST);
+ final int halfHeightMeasureSpec =
+ View.MeasureSpec.makeMeasureSpec(height / 2, View.MeasureSpec.AT_MOST);
+
+ // Act 1.
+
+ // First focus on the last fully visible child located at span index #1.
+ View toFocus = findLastFullyVisibleChild(recyclerView);
+ int focusIndex = recyclerView.getChildAdapterPosition(toFocus);
+ focusIndex = (focusIndex / spanCount) * spanCount + 1;
+ toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex).itemView;
+ assertTrue(focusIndex >= 1 && focusIndex < itemCount);
+
+ requestFocus(toFocus, false);
+
+ mGlm.expectLayout(1);
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ recyclerView.measure(widthMeasureSpec, fullHeightMinusOneMeasureSpec);
+ recyclerView.measure(widthMeasureSpec, halfHeightMeasureSpec);
+ recyclerView.layout(
+ 0,
+ 0,
+ recyclerView.getMeasuredWidth(),
+ recyclerView.getMeasuredHeight());
+ }
+ });
+ mGlm.waitForLayout(3);
+
+ // Assert 1.
assertThat("Child at position " + focusIndex + " should be focused",
toFocus.hasFocus(), is(true));
assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
- isViewPartiallyInBound(mRecyclerView, toFocus));
+ isViewPartiallyInBound(recyclerView, toFocus));
- // Close IME
- final int heightBeforeImeClose = mRecyclerView.getHeight();
- getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
- getInstrumentation().waitForIdleSync();
- // Wait for IME to close
- PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+ // Act 2.
+
+ mGlm.expectLayout(1);
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
- public boolean canProceed() {
- return mRecyclerView.getHeight() > heightBeforeImeClose;
+ public void run() {
+ recyclerView.measure(widthMeasureSpec, fullHeightMeasureSpec);
+ recyclerView.layout(
+ 0,
+ 0,
+ recyclerView.getMeasuredWidth(),
+ recyclerView.getMeasuredHeight());
}
});
+ mGlm.waitForLayout(3);
+
+ // Assert 2.
+
assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
- isViewPartiallyInBound(mRecyclerView, toFocus));
+ isViewPartiallyInBound(recyclerView, toFocus));
+
+ // Act 3.
// Now focus on the first fully visible EditText located at the last span index.
- toFocus = findFirstFullyVisibleChild(mRecyclerView);
- focusIndex = mRecyclerView.getChildAdapterPosition(toFocus);
+ toFocus = findFirstFullyVisibleChild(recyclerView);
+ focusIndex = recyclerView.getChildAdapterPosition(toFocus);
focusIndex = (focusIndex / spanCount) * spanCount + (spanCount - 1);
- toFocus = mRecyclerView.findViewHolderForAdapterPosition(focusIndex).itemView;
- final int heightBeforeImeOpen2 = mRecyclerView.getHeight();
- TouchUtils.tapView(getInstrumentation(), mRecyclerView, toFocus);
- getInstrumentation().waitForIdleSync();
- // Wait for IME to pop up
- PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+ toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex).itemView;
+
+ requestFocus(toFocus, false);
+
+ mGlm.expectLayout(1);
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
- public boolean canProceed() {
- return mRecyclerView.getHeight() < heightBeforeImeOpen2;
+ public void run() {
+ recyclerView.measure(widthMeasureSpec, fullHeightMinusOneMeasureSpec);
+ recyclerView.measure(widthMeasureSpec, halfHeightMeasureSpec);
+ recyclerView.layout(
+ 0,
+ 0,
+ recyclerView.getMeasuredWidth(),
+ recyclerView.getMeasuredHeight());
}
});
+ mGlm.waitForLayout(3);
+
+ // Assert 3.
+
assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
- isViewPartiallyInBound(mRecyclerView, toFocus));
+ isViewPartiallyInBound(recyclerView, toFocus));
}
@Test
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerTest.java
index 91d0dbf..de23213 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerTest.java
@@ -20,7 +20,6 @@
import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
@@ -37,19 +36,14 @@
import android.os.Build;
import android.support.test.filters.LargeTest;
import android.support.test.filters.SdkSuppress;
-import android.support.testutils.PollingCheck;
import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v7.util.ImeCleanUpTestRule;
-import android.support.v7.util.TouchUtils;
+import android.support.v4.view.ViewCompat;
import android.util.Log;
import android.util.StateSet;
-import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
-import android.widget.LinearLayout;
-import org.junit.Rule;
import org.junit.Test;
import java.util.ArrayList;
@@ -69,68 +63,76 @@
@LargeTest
public class LinearLayoutManagerTest extends BaseLinearLayoutManagerTest {
- @Rule
- public final ImeCleanUpTestRule imeCleanUp = new ImeCleanUpTestRule();
-
+ /**
+ * Tests that the LinearLayoutManager retains the focused element after multiple measure
+ * calls to the RecyclerView. There was a bug where the focused view was lost when the soft
+ * keyboard opened. This test simulates the measure/layout events triggered by the opening
+ * of the soft keyboard by making two calls to measure. A simulation was done because using
+ * the soft keyboard in the test caused many issues on API levels 15, 17 and 19.
+ */
@Test
- public void editTextVisibility() throws Throwable {
+ public void focusedChildStaysInViewWhenRecyclerViewShrinks() throws Throwable {
- // Simulating a scenario where an EditText is tapped (which will receive focus).
- // The soft keyboard that's opened overlaps the focused EditText which will shrink RV's
- // padded bounded area. LLM should still lay out the focused EditText so that it becomes
- // visible above the soft keyboard.
- // The condition for this test is setting RV's height to a non-exact height, so that measure
- // is called twice (once with the larger height and another time with smaller height when
- // the keyboard shows up). To ensure this resizing of RV, SOFT_INPUT_ADJUST_RESIZE is set.
- imeCleanUp.setContainerView(getActivity().getContainer());
- final LinearLayout container = new LinearLayout(getActivity());
- container.setOrientation(LinearLayout.VERTICAL);
- container.setLayoutParams(
- new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup
- .LayoutParams.MATCH_PARENT));
+ // Arrange.
- final EditTextAdapter editTextAdapter = new EditTextAdapter(50);
-
- mRecyclerView = inflateWrappedRV();
- ViewGroup.LayoutParams lp = mRecyclerView.getLayoutParams();
+ final RecyclerView recyclerView = inflateWrappedRV();
+ ViewGroup.LayoutParams lp = recyclerView.getLayoutParams();
lp.height = WRAP_CONTENT;
lp.width = MATCH_PARENT;
+ recyclerView.setHasFixedSize(true);
- mRecyclerView.setHasFixedSize(true);
- mRecyclerView.setAdapter(editTextAdapter);
+ final FocusableAdapter focusableAdapter =
+ new FocusableAdapter(50);
+ recyclerView.setAdapter(focusableAdapter);
+
mLayoutManager = new WrappedLinearLayoutManager(getActivity(), VERTICAL, false);
- mRecyclerView.setLayoutManager(mLayoutManager);
-
- container.addView(mRecyclerView);
+ recyclerView.setLayoutManager(mLayoutManager);
mLayoutManager.expectLayouts(1);
mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
- getActivity().getContainer().addView(container);
+ getActivity().getContainer().addView(recyclerView);
}
});
+ mLayoutManager.waitForLayout(3);
+
+ int width = recyclerView.getWidth();
+ int height = recyclerView.getHeight();
+ final int widthMeasureSpec =
+ View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
+ final int fullHeightMeasureSpec =
+ View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
+ // "MinusOne" so that a measure call will appropriately trigger onMeasure after RecyclerView
+ // was previously laid out with the full height version.
+ final int fullHeightMinusOneMeasureSpec =
+ View.MeasureSpec.makeMeasureSpec(height - 1, View.MeasureSpec.AT_MOST);
+ final int halfHeightMeasureSpec =
+ View.MeasureSpec.makeMeasureSpec(height / 2, View.MeasureSpec.AT_MOST);
+
+ // Act 1.
+
+ View toFocus = findLastFullyVisibleChild(recyclerView);
+ int focusIndex = recyclerView.getChildAdapterPosition(toFocus);
+
+ requestFocus(toFocus, false);
+
+ mLayoutManager.expectLayouts(1);
mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
- mActivityRule.getActivity().getWindow().setSoftInputMode(SOFT_INPUT_ADJUST_RESIZE);
+ recyclerView.measure(widthMeasureSpec, fullHeightMinusOneMeasureSpec);
+ recyclerView.measure(widthMeasureSpec, halfHeightMeasureSpec);
+ recyclerView.layout(
+ 0,
+ 0,
+ recyclerView.getMeasuredWidth(),
+ recyclerView.getMeasuredHeight());
}
});
+ mLayoutManager.waitForLayout(3);
- // First focus on the last fully visible EditText.
- View toFocus = findLastFullyVisibleChild(mRecyclerView);
- int focusIndex = mRecyclerView.getChildAdapterPosition(toFocus);
-
- final int heightBeforeImeOpen = mRecyclerView.getHeight();
- TouchUtils.tapView(getInstrumentation(), mRecyclerView, toFocus);
- getInstrumentation().waitForIdleSync();
- // Wait for IME to pop up.
- PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
- @Override
- public boolean canProceed() {
- return mRecyclerView.getHeight() < heightBeforeImeOpen;
- }
- });
+ // Verify 1.
assertThat("Child at position " + focusIndex + " should be focused",
toFocus.hasFocus(), is(true));
@@ -138,40 +140,59 @@
// requestRectangleOnScreen (inside bringPointIntoView) for the focused view with a rect
// containing the content area. This rect is guaranteed to be fully visible whereas a
// portion of TextView could be out of bounds.
- assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
- isViewPartiallyInBound(mRecyclerView, toFocus));
+ assertThat("Child view at adapter pos " + focusIndex + " should be fully visible.",
+ isViewPartiallyInBound(recyclerView, toFocus), is(true));
- // Close IME
- final int heightBeforeImeClose = mRecyclerView.getHeight();
- getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
- getInstrumentation().waitForIdleSync();
- // Wait for IME to close
- PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+ // Act 2.
+
+ mLayoutManager.expectLayouts(1);
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
- public boolean canProceed() {
- return mRecyclerView.getHeight() > heightBeforeImeClose;
+ public void run() {
+ recyclerView.measure(widthMeasureSpec, fullHeightMeasureSpec);
+ recyclerView.layout(
+ 0,
+ 0,
+ recyclerView.getMeasuredWidth(),
+ recyclerView.getMeasuredHeight());
}
});
+ mLayoutManager.waitForLayout(3);
+
+ // Verify 2.
+
assertThat("Child at position " + focusIndex + " should be focused",
toFocus.hasFocus(), is(true));
assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
- isViewPartiallyInBound(mRecyclerView, toFocus));
+ isViewPartiallyInBound(recyclerView, toFocus));
+
+ // Act 3.
// Now focus on the first fully visible EditText.
- toFocus = findFirstFullyVisibleChild(mRecyclerView);
- focusIndex = mRecyclerView.getChildAdapterPosition(toFocus);
- final int heightBeforeImeOpen2 = mRecyclerView.getHeight();
- TouchUtils.tapView(getInstrumentation(), mRecyclerView, toFocus);
- getInstrumentation().waitForIdleSync();
- // Wait for IME to pop up
- PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+ toFocus = findFirstFullyVisibleChild(recyclerView);
+ focusIndex = recyclerView.getChildAdapterPosition(toFocus);
+
+ requestFocus(toFocus, false);
+
+ mLayoutManager.expectLayouts(1);
+ mActivityRule.runOnUiThread(new Runnable() {
@Override
- public boolean canProceed() {
- return mRecyclerView.getHeight() < heightBeforeImeOpen2;
+ public void run() {
+ recyclerView.measure(widthMeasureSpec, fullHeightMinusOneMeasureSpec);
+ recyclerView.measure(widthMeasureSpec, halfHeightMeasureSpec);
+ recyclerView.layout(
+ 0,
+ 0,
+ recyclerView.getMeasuredWidth(),
+ recyclerView.getMeasuredHeight());
}
});
+ mLayoutManager.waitForLayout(3);
+
+ // Assert 3.
+
assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
- isViewPartiallyInBound(mRecyclerView, toFocus));
+ isViewPartiallyInBound(recyclerView, toFocus));
}
@Test
@@ -592,7 +613,7 @@
@Override
public void onFocusChange(View v, boolean hasFocus) {
assertNull("Focus just got cleared and no children should be holding"
- + " focus now.", mRecyclerView.getFocusedChild());
+ + " focus now.", mRecyclerView.getFocusedChild());
try {
// Calling focusSearch should be a no-op here since even though there
// are unfocusable views down to scroll to, none of RV's children hold
@@ -771,6 +792,170 @@
mRecyclerView.getChildCount() <= childCount + 3 /*1 for removed view, 2 for its size*/);
}
+ void waitOneCycle() throws Throwable {
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ }
+ });
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
+ @Test
+ public void hiddenNoneRemoveViewAccessibility() throws Throwable {
+ final Config config = new Config();
+ int adapterSize = 1000;
+ final boolean[] firstItemSpecialSize = new boolean[] {false};
+ TestAdapter adapter = new TestAdapter(adapterSize) {
+ @Override
+ public void onBindViewHolder(TestViewHolder holder,
+ int position) {
+ super.onBindViewHolder(holder, position);
+ ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+ if (!(lp instanceof ViewGroup.MarginLayoutParams)) {
+ lp = new ViewGroup.MarginLayoutParams(0, 0);
+ holder.itemView.setLayoutParams(lp);
+ }
+ ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp;
+ final int maxSize;
+ if (config.mOrientation == HORIZONTAL) {
+ maxSize = mRecyclerView.getWidth();
+ mlp.height = ViewGroup.MarginLayoutParams.MATCH_PARENT;
+ } else {
+ maxSize = mRecyclerView.getHeight();
+ mlp.width = ViewGroup.MarginLayoutParams.MATCH_PARENT;
+ }
+
+ final int desiredSize;
+ if (position == 0 && firstItemSpecialSize[0]) {
+ desiredSize = maxSize / 3;
+ } else {
+ desiredSize = maxSize / 8;
+ }
+ if (config.mOrientation == HORIZONTAL) {
+ mlp.width = desiredSize;
+ } else {
+ mlp.height = desiredSize;
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(TestViewHolder holder,
+ int position, List<Object> payloads) {
+ onBindViewHolder(holder, position);
+ }
+ };
+ adapter.setHasStableIds(false);
+ config.adapter(adapter);
+ setupByConfig(config, true);
+ final DummyItemAnimator itemAnimator = new DummyItemAnimator();
+ mRecyclerView.setItemAnimator(itemAnimator);
+
+ // push last item out by increasing first item's size
+ final int childBeingPushOut = mLayoutManager.getChildCount() - 1;
+ RecyclerView.ViewHolder itemViewHolder = mRecyclerView
+ .findViewHolderForAdapterPosition(childBeingPushOut);
+ final int originalAccessibility = ViewCompat.getImportantForAccessibility(
+ itemViewHolder.itemView);
+ assertTrue(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO == originalAccessibility
+ || ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES == originalAccessibility);
+
+ itemAnimator.expect(DummyItemAnimator.MOVE_START, 1);
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ firstItemSpecialSize[0] = true;
+ mTestAdapter.notifyItemChanged(0, "XXX");
+ }
+ });
+ // wait till itemAnimator starts which will block itemView's accessibility
+ itemAnimator.waitFor(DummyItemAnimator.MOVE_START);
+ // RV Changes accessiblity after onMoveStart, so wait one more cycle.
+ waitOneCycle();
+ assertTrue(itemAnimator.getMovesAnimations().contains(itemViewHolder));
+ assertEquals(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
+ ViewCompat.getImportantForAccessibility(itemViewHolder.itemView));
+
+ // notify Change again to run predictive animation.
+ mLayoutManager.expectLayouts(2);
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mTestAdapter.notifyItemChanged(0, "XXX");
+ }
+ });
+ mLayoutManager.waitForLayout(1);
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ itemAnimator.endAnimations();
+ }
+ });
+ // scroll to the view being pushed out, it should get same view from cache as the item
+ // in adapter does not change.
+ smoothScrollToPosition(childBeingPushOut);
+ RecyclerView.ViewHolder itemViewHolder2 = mRecyclerView
+ .findViewHolderForAdapterPosition(childBeingPushOut);
+ assertSame(itemViewHolder, itemViewHolder2);
+ // the important for accessibility should be reset to YES/AUTO:
+ final int newAccessibility = ViewCompat.getImportantForAccessibility(
+ itemViewHolder.itemView);
+ assertTrue(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO == newAccessibility
+ || ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES == newAccessibility);
+ }
+
+ @Test
+ public void layoutFrozenBug70402422() throws Throwable {
+ final Config config = new Config();
+ TestAdapter adapter = new TestAdapter(2);
+ adapter.setHasStableIds(false);
+ config.adapter(adapter);
+ setupByConfig(config, true);
+ final DummyItemAnimator itemAnimator = new DummyItemAnimator();
+ mRecyclerView.setItemAnimator(itemAnimator);
+
+ final View firstItemView = mRecyclerView
+ .findViewHolderForAdapterPosition(0).itemView;
+
+ itemAnimator.expect(DummyItemAnimator.REMOVE_START, 1);
+ mTestAdapter.deleteAndNotify(1, 1);
+ itemAnimator.waitFor(DummyItemAnimator.REMOVE_START);
+
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mRecyclerView.setLayoutFrozen(true);
+ }
+ });
+ // requestLayout during item animation, which should be eaten by setLayoutFrozen(true)
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ firstItemView.requestLayout();
+ }
+ });
+ assertTrue(firstItemView.isLayoutRequested());
+ assertFalse(mRecyclerView.isLayoutRequested());
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ itemAnimator.endAnimations();
+ }
+ });
+ // When setLayoutFrozen(false), the firstItemView should run a layout pass and clear
+ // isLayoutRequested() flag.
+ mLayoutManager.expectLayouts(1);
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mRecyclerView.setLayoutFrozen(false);
+ }
+ });
+ mLayoutManager.waitForLayout(1);
+ assertFalse(firstItemView.isLayoutRequested());
+ assertFalse(mRecyclerView.isLayoutRequested());
+ }
+
@Test
public void keepFocusOnRelayout() throws Throwable {
setupByConfig(new Config(VERTICAL, false, false).itemCount(500), true);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
index 1c03c0f..dbad400 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
@@ -46,6 +46,7 @@
import static org.mockito.Mockito.verify;
import android.content.Context;
+import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -1532,7 +1533,33 @@
@Test
public void scrollToPositionCallback() throws Throwable {
- RecyclerView recyclerView = new RecyclerView(getActivity());
+
+ class TestRecyclerView extends RecyclerView {
+
+ private CountDownLatch mDrawLatch;
+
+ TestRecyclerView(Context context) {
+ super(context);
+ }
+
+ public void expectDraws(int count) {
+ mDrawLatch = new CountDownLatch(count);
+ }
+
+ public void waitForDraw(int seconds) throws InterruptedException {
+ mDrawLatch.await(seconds, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public void onDraw(Canvas c) {
+ super.onDraw(c);
+ if (mDrawLatch != null) {
+ mDrawLatch.countDown();
+ }
+ }
+ }
+
+ TestRecyclerView recyclerView = new TestRecyclerView(getActivity());
TestLayoutManager tlm = new TestLayoutManager() {
int scrollPos = RecyclerView.NO_POSITION;
@@ -1562,7 +1589,6 @@
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
rvCounter.incrementAndGet();
- super.onScrolled(recyclerView, dx, dy);
}
});
@@ -1574,13 +1600,16 @@
}
});
+ recyclerView.expectDraws(1);
tlm.expectLayouts(1);
setRecyclerView(recyclerView);
tlm.waitForLayout(2);
-
+ recyclerView.waitForDraw(2);
assertEquals("RV on scroll should be called for initialization", 1, rvCounter.get());
assertEquals("VTO on scroll should be called for initialization", 1,
viewGroupCounter.get());
+
+ recyclerView.expectDraws(1);
tlm.expectLayouts(1);
freezeLayout(true);
scrollToPosition(3);
@@ -1588,13 +1617,15 @@
freezeLayout(false);
scrollToPosition(3);
tlm.waitForLayout(2);
+ recyclerView.waitForDraw(2);
assertEquals("RV on scroll should be called", 2, rvCounter.get());
assertEquals("VTO on scroll should be called", 2, viewGroupCounter.get());
+
+ recyclerView.expectDraws(1);
tlm.expectLayouts(1);
requestLayoutOnUIThread(recyclerView);
tlm.waitForLayout(2);
- // wait for draw :/
- Thread.sleep(1000);
+ recyclerView.waitForDraw(2);
assertEquals("on scroll should NOT be called", 2, rvCounter.get());
assertEquals("on scroll should NOT be called", 2, viewGroupCounter.get());
}
diff --git a/wear/Android.mk b/wear/Android.mk
index fe9b8d3..96934f7 100644
--- a/wear/Android.mk
+++ b/wear/Android.mk
@@ -32,9 +32,11 @@
include $(CLEAR_VARS)
LOCAL_USE_AAPT2 := true
+LOCAL_AAPT2_ONLY := true
LOCAL_MODULE := android-support-wear
LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
+LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_SHARED_ANDROID_LIBRARIES := \
android-support-core-ui \
diff --git a/wear/api/27.0.0.ignore b/wear/api/27.0.0.ignore
new file mode 100644
index 0000000..ebc6632
--- /dev/null
+++ b/wear/api/27.0.0.ignore
@@ -0,0 +1 @@
+a55e0de
diff --git a/wear/api/current.txt b/wear/api/current.txt
index e9b7d86..3fd2465 100644
--- a/wear/api/current.txt
+++ b/wear/api/current.txt
@@ -2,7 +2,7 @@
public final class AmbientMode extends android.app.Fragment {
ctor public AmbientMode();
- method public static <T extends android.app.Activity & android.support.wear.ambient.AmbientMode.AmbientCallbackProvider> android.support.wear.ambient.AmbientMode.AmbientController attachAmbientSupport(T);
+ method public static <T extends android.app.Activity> android.support.wear.ambient.AmbientMode.AmbientController attachAmbientSupport(T);
field public static final java.lang.String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
field public static final java.lang.String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
field public static final java.lang.String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
@@ -48,7 +48,6 @@
ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet);
ctor public BoxInsetLayout(android.content.Context, android.util.AttributeSet, int);
method public android.support.wear.widget.BoxInsetLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
- method protected void onLayout(boolean, int, int, int, int);
}
public static class BoxInsetLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
@@ -182,7 +181,7 @@
method public void peekDrawer();
}
- public class WearableDrawerLayout extends android.widget.FrameLayout implements android.view.View.OnLayoutChangeListener {
+ public class WearableDrawerLayout extends android.widget.FrameLayout implements android.support.v4.view.NestedScrollingParent android.view.View.OnLayoutChangeListener {
ctor public WearableDrawerLayout(android.content.Context);
ctor public WearableDrawerLayout(android.content.Context, android.util.AttributeSet);
ctor public WearableDrawerLayout(android.content.Context, android.util.AttributeSet, int);
diff --git a/wear/build.gradle b/wear/build.gradle
index 458f722..79c69ee 100644
--- a/wear/build.gradle
+++ b/wear/build.gradle
@@ -1,3 +1,4 @@
+import static android.support.dependencies.DependenciesKt.*
import android.support.LibraryGroups
import android.support.LibraryVersions
@@ -6,18 +7,18 @@
}
dependencies {
- api project(':support-annotations')
- api project(':support-core-ui')
- api project(':support-fragment')
- api project(':percent')
- api project(':recyclerview-v7')
+ api(project(":support-annotations"))
+ api(project(":support-core-ui"))
+ api(project(":support-fragment"))
+ api(project(":percent"))
+ api(project(":recyclerview-v7"))
- androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
- androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
- androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
- androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
- provided fileTree(dir: 'wear_stubs', include: ['com.google.android.wearable-stubs.jar'])
+ compileOnly fileTree(dir: 'wear_stubs', include: ['com.google.android.wearable-stubs.jar'])
}
android {
@@ -44,5 +45,4 @@
mavenGroup = LibraryGroups.SUPPORT
inceptionYear = "2016"
description = "Android Wear Support UI"
- legacySourceLocation = true
}
diff --git a/wear/lint-baseline.xml b/wear/lint-baseline.xml
deleted file mode 100644
index 8bc6f6f..0000000
--- a/wear/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-</issues>
diff --git a/wear/tests/AndroidManifest.xml b/wear/src/androidTest/AndroidManifest.xml
similarity index 90%
rename from wear/tests/AndroidManifest.xml
rename to wear/src/androidTest/AndroidManifest.xml
index ce78477..67ccd91 100644
--- a/wear/tests/AndroidManifest.xml
+++ b/wear/src/androidTest/AndroidManifest.xml
@@ -55,6 +55,13 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+
+ <activity android:name="android.support.wear.ambient.AmbientModeResumeTestActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
<!-- Test app is iOS compatible. -->
<meta-data
android:name="com.google.android.wearable.standalone"
diff --git a/wear/tests/NO_DOCS b/wear/src/androidTest/NO_DOCS
similarity index 100%
rename from wear/tests/NO_DOCS
rename to wear/src/androidTest/NO_DOCS
diff --git a/wear/tests/src/android/support/wear/ambient/AmbientDelegateTest.java b/wear/src/androidTest/java/android/support/wear/ambient/AmbientDelegateTest.java
similarity index 100%
rename from wear/tests/src/android/support/wear/ambient/AmbientDelegateTest.java
rename to wear/src/androidTest/java/android/support/wear/ambient/AmbientDelegateTest.java
diff --git a/wear/src/androidTest/java/android/support/wear/ambient/AmbientModeResumeTest.java b/wear/src/androidTest/java/android/support/wear/ambient/AmbientModeResumeTest.java
new file mode 100644
index 0000000..32de769
--- /dev/null
+++ b/wear/src/androidTest/java/android/support/wear/ambient/AmbientModeResumeTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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 android.support.wear.ambient;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.wear.widget.util.WakeLockRule;
+
+import com.google.android.wearable.compat.WearableActivityController;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AmbientModeResumeTest {
+ @Rule
+ public final WakeLockRule mWakeLock = new WakeLockRule();
+
+ @Rule
+ public final ActivityTestRule<AmbientModeResumeTestActivity> mActivityRule =
+ new ActivityTestRule<>(AmbientModeResumeTestActivity.class);
+
+ @Test
+ public void testActivityDefaults() throws Throwable {
+ assertTrue(WearableActivityController.getLastInstance().isAutoResumeEnabled());
+ assertFalse(WearableActivityController.getLastInstance().isAmbientEnabled());
+ }
+}
diff --git a/car/tests/src/android/support/car/widget/ColumnCardViewTestActivity.java b/wear/src/androidTest/java/android/support/wear/ambient/AmbientModeResumeTestActivity.java
similarity index 67%
copy from car/tests/src/android/support/car/widget/ColumnCardViewTestActivity.java
copy to wear/src/androidTest/java/android/support/wear/ambient/AmbientModeResumeTestActivity.java
index 693e4a1..0ca3c15 100644
--- a/car/tests/src/android/support/car/widget/ColumnCardViewTestActivity.java
+++ b/wear/src/androidTest/java/android/support/wear/ambient/AmbientModeResumeTestActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -13,17 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package android.support.car.widget;
+package android.support.wear.ambient;
import android.app.Activity;
import android.os.Bundle;
-import android.support.car.test.R;
-public class ColumnCardViewTestActivity extends Activity {
+public class AmbientModeResumeTestActivity extends Activity {
+ AmbientMode.AmbientController mAmbientController;
+
@Override
- public void onCreate(Bundle savedInstanceState) {
+ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_column_card_view);
+ mAmbientController = AmbientMode.attachAmbientSupport(this);
}
}
diff --git a/wear/tests/src/android/support/wear/ambient/AmbientModeTest.java b/wear/src/androidTest/java/android/support/wear/ambient/AmbientModeTest.java
similarity index 100%
rename from wear/tests/src/android/support/wear/ambient/AmbientModeTest.java
rename to wear/src/androidTest/java/android/support/wear/ambient/AmbientModeTest.java
diff --git a/wear/tests/src/android/support/wear/ambient/AmbientModeTestActivity.java b/wear/src/androidTest/java/android/support/wear/ambient/AmbientModeTestActivity.java
similarity index 100%
rename from wear/tests/src/android/support/wear/ambient/AmbientModeTestActivity.java
rename to wear/src/androidTest/java/android/support/wear/ambient/AmbientModeTestActivity.java
diff --git a/wear/tests/src/android/support/wear/utils/MetadataTestActivity.java b/wear/src/androidTest/java/android/support/wear/utils/MetadataTestActivity.java
similarity index 99%
rename from wear/tests/src/android/support/wear/utils/MetadataTestActivity.java
rename to wear/src/androidTest/java/android/support/wear/utils/MetadataTestActivity.java
index 86d92ab..b934b5b 100644
--- a/wear/tests/src/android/support/wear/utils/MetadataTestActivity.java
+++ b/wear/src/androidTest/java/android/support/wear/utils/MetadataTestActivity.java
@@ -34,4 +34,4 @@
assertEquals(R.drawable.preview_face_circular,
MetadataConstants.getPreviewDrawableResourceId(this, true));
}
-}
\ No newline at end of file
+}
diff --git a/wear/tests/src/android/support/wear/widget/BoxInsetLayoutTest.java b/wear/src/androidTest/java/android/support/wear/widget/BoxInsetLayoutTest.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/BoxInsetLayoutTest.java
rename to wear/src/androidTest/java/android/support/wear/widget/BoxInsetLayoutTest.java
diff --git a/wear/tests/src/android/support/wear/widget/CircularProgressLayoutControllerTest.java b/wear/src/androidTest/java/android/support/wear/widget/CircularProgressLayoutControllerTest.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/CircularProgressLayoutControllerTest.java
rename to wear/src/androidTest/java/android/support/wear/widget/CircularProgressLayoutControllerTest.java
diff --git a/wear/tests/src/android/support/wear/widget/CircularProgressLayoutTest.java b/wear/src/androidTest/java/android/support/wear/widget/CircularProgressLayoutTest.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/CircularProgressLayoutTest.java
rename to wear/src/androidTest/java/android/support/wear/widget/CircularProgressLayoutTest.java
diff --git a/wear/tests/src/android/support/wear/widget/LayoutTestActivity.java b/wear/src/androidTest/java/android/support/wear/widget/LayoutTestActivity.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/LayoutTestActivity.java
rename to wear/src/androidTest/java/android/support/wear/widget/LayoutTestActivity.java
diff --git a/wear/tests/src/android/support/wear/widget/RoundedDrawableTest.java b/wear/src/androidTest/java/android/support/wear/widget/RoundedDrawableTest.java
similarity index 99%
rename from wear/tests/src/android/support/wear/widget/RoundedDrawableTest.java
rename to wear/src/androidTest/java/android/support/wear/widget/RoundedDrawableTest.java
index 21aee7b..b01b3fa 100644
--- a/wear/tests/src/android/support/wear/widget/RoundedDrawableTest.java
+++ b/wear/src/androidTest/java/android/support/wear/widget/RoundedDrawableTest.java
@@ -33,11 +33,11 @@
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
+import android.support.test.filters.SdkSuppress;
import android.support.test.filters.SmallTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.support.wear.test.R;
-import android.support.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Rule;
diff --git a/wear/tests/src/android/support/wear/widget/ScrollManagerTest.java b/wear/src/androidTest/java/android/support/wear/widget/ScrollManagerTest.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/ScrollManagerTest.java
rename to wear/src/androidTest/java/android/support/wear/widget/ScrollManagerTest.java
diff --git a/wear/tests/src/android/support/wear/widget/SwipeDismissFrameLayoutTest.java b/wear/src/androidTest/java/android/support/wear/widget/SwipeDismissFrameLayoutTest.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/SwipeDismissFrameLayoutTest.java
rename to wear/src/androidTest/java/android/support/wear/widget/SwipeDismissFrameLayoutTest.java
diff --git a/wear/tests/src/android/support/wear/widget/SwipeDismissFrameLayoutTestActivity.java b/wear/src/androidTest/java/android/support/wear/widget/SwipeDismissFrameLayoutTestActivity.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/SwipeDismissFrameLayoutTestActivity.java
rename to wear/src/androidTest/java/android/support/wear/widget/SwipeDismissFrameLayoutTestActivity.java
diff --git a/wear/tests/src/android/support/wear/widget/SwipeDismissPreferenceFragment.java b/wear/src/androidTest/java/android/support/wear/widget/SwipeDismissPreferenceFragment.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/SwipeDismissPreferenceFragment.java
rename to wear/src/androidTest/java/android/support/wear/widget/SwipeDismissPreferenceFragment.java
diff --git a/wear/tests/src/android/support/wear/widget/WearableLinearLayoutManagerTest.java b/wear/src/androidTest/java/android/support/wear/widget/WearableLinearLayoutManagerTest.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/WearableLinearLayoutManagerTest.java
rename to wear/src/androidTest/java/android/support/wear/widget/WearableLinearLayoutManagerTest.java
diff --git a/wear/tests/src/android/support/wear/widget/WearableRecyclerViewTest.java b/wear/src/androidTest/java/android/support/wear/widget/WearableRecyclerViewTest.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/WearableRecyclerViewTest.java
rename to wear/src/androidTest/java/android/support/wear/widget/WearableRecyclerViewTest.java
diff --git a/wear/tests/src/android/support/wear/widget/WearableRecyclerViewTestActivity.java b/wear/src/androidTest/java/android/support/wear/widget/WearableRecyclerViewTestActivity.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/WearableRecyclerViewTestActivity.java
rename to wear/src/androidTest/java/android/support/wear/widget/WearableRecyclerViewTestActivity.java
diff --git a/wear/tests/src/android/support/wear/widget/drawer/DrawerTestActivity.java b/wear/src/androidTest/java/android/support/wear/widget/drawer/DrawerTestActivity.java
similarity index 97%
rename from wear/tests/src/android/support/wear/widget/drawer/DrawerTestActivity.java
rename to wear/src/androidTest/java/android/support/wear/widget/drawer/DrawerTestActivity.java
index 14af0e1..414b97b 100644
--- a/wear/tests/src/android/support/wear/widget/drawer/DrawerTestActivity.java
+++ b/wear/src/androidTest/java/android/support/wear/widget/drawer/DrawerTestActivity.java
@@ -152,9 +152,9 @@
DrawerStyle.ONLY_ACTION_DRAWER_WITH_TITLE
})
public @interface DrawerStyle {
- int BOTH_DRAWER_NAV_SINGLE_PAGE = 0;
- int BOTH_DRAWER_NAV_MULTI_PAGE = 1;
- int ONLY_ACTION_DRAWER_WITH_TITLE = 2;
+ int BOTH_DRAWER_NAV_SINGLE_PAGE = 0;
+ int BOTH_DRAWER_NAV_MULTI_PAGE = 1;
+ int ONLY_ACTION_DRAWER_WITH_TITLE = 2;
}
/**
diff --git a/wear/tests/src/android/support/wear/widget/drawer/WearableDrawerLayoutEspressoTest.java b/wear/src/androidTest/java/android/support/wear/widget/drawer/WearableDrawerLayoutEspressoTest.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/drawer/WearableDrawerLayoutEspressoTest.java
rename to wear/src/androidTest/java/android/support/wear/widget/drawer/WearableDrawerLayoutEspressoTest.java
diff --git a/wear/tests/src/android/support/wear/widget/util/ArcSwipe.java b/wear/src/androidTest/java/android/support/wear/widget/util/ArcSwipe.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/util/ArcSwipe.java
rename to wear/src/androidTest/java/android/support/wear/widget/util/ArcSwipe.java
diff --git a/wear/tests/src/android/support/wear/widget/util/ArcSwipeTest.java b/wear/src/androidTest/java/android/support/wear/widget/util/ArcSwipeTest.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/util/ArcSwipeTest.java
rename to wear/src/androidTest/java/android/support/wear/widget/util/ArcSwipeTest.java
diff --git a/wear/tests/src/android/support/wear/widget/util/AsyncViewActions.java b/wear/src/androidTest/java/android/support/wear/widget/util/AsyncViewActions.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/util/AsyncViewActions.java
rename to wear/src/androidTest/java/android/support/wear/widget/util/AsyncViewActions.java
diff --git a/wear/tests/src/android/support/wear/widget/util/MoreViewAssertions.java b/wear/src/androidTest/java/android/support/wear/widget/util/MoreViewAssertions.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/util/MoreViewAssertions.java
rename to wear/src/androidTest/java/android/support/wear/widget/util/MoreViewAssertions.java
diff --git a/wear/tests/src/android/support/wear/widget/util/WakeLockRule.java b/wear/src/androidTest/java/android/support/wear/widget/util/WakeLockRule.java
similarity index 100%
rename from wear/tests/src/android/support/wear/widget/util/WakeLockRule.java
rename to wear/src/androidTest/java/android/support/wear/widget/util/WakeLockRule.java
diff --git a/wear/tests/src/com/google/android/wearable/compat/WearableActivityController.java b/wear/src/androidTest/java/com/google/android/wearable/compat/WearableActivityController.java
similarity index 97%
rename from wear/tests/src/com/google/android/wearable/compat/WearableActivityController.java
rename to wear/src/androidTest/java/com/google/android/wearable/compat/WearableActivityController.java
index 7823f23..0a76af0 100644
--- a/wear/tests/src/com/google/android/wearable/compat/WearableActivityController.java
+++ b/wear/src/androidTest/java/com/google/android/wearable/compat/WearableActivityController.java
@@ -33,7 +33,7 @@
private AmbientCallback mCallback;
private boolean mAmbientEnabled = false;
- private boolean mAutoResumeEnabled = false;
+ private boolean mAutoResumeEnabled = true;
private boolean mAmbient = false;
public WearableActivityController(String tag, Activity activity, AmbientCallback callback) {
diff --git a/wear/tests/res/drawable/preview_face.png b/wear/src/androidTest/res/drawable/preview_face.png
similarity index 100%
rename from wear/tests/res/drawable/preview_face.png
rename to wear/src/androidTest/res/drawable/preview_face.png
Binary files differ
diff --git a/wear/tests/res/drawable/preview_face_circular.png b/wear/src/androidTest/res/drawable/preview_face_circular.png
similarity index 100%
rename from wear/tests/res/drawable/preview_face_circular.png
rename to wear/src/androidTest/res/drawable/preview_face_circular.png
Binary files differ
diff --git a/wear/tests/res/drawable/rounded_drawable.xml b/wear/src/androidTest/res/drawable/rounded_drawable.xml
similarity index 100%
rename from wear/tests/res/drawable/rounded_drawable.xml
rename to wear/src/androidTest/res/drawable/rounded_drawable.xml
diff --git a/wear/tests/res/drawable/test_drawable.xml b/wear/src/androidTest/res/drawable/test_drawable.xml
similarity index 100%
rename from wear/tests/res/drawable/test_drawable.xml
rename to wear/src/androidTest/res/drawable/test_drawable.xml
diff --git a/wear/tests/res/layout/box_inset_layout_testcase_1.xml b/wear/src/androidTest/res/layout/box_inset_layout_testcase_1.xml
similarity index 100%
rename from wear/tests/res/layout/box_inset_layout_testcase_1.xml
rename to wear/src/androidTest/res/layout/box_inset_layout_testcase_1.xml
diff --git a/wear/tests/res/layout/box_inset_layout_testcase_2.xml b/wear/src/androidTest/res/layout/box_inset_layout_testcase_2.xml
similarity index 100%
rename from wear/tests/res/layout/box_inset_layout_testcase_2.xml
rename to wear/src/androidTest/res/layout/box_inset_layout_testcase_2.xml
diff --git a/wear/tests/res/layout/box_inset_layout_testcase_3.xml b/wear/src/androidTest/res/layout/box_inset_layout_testcase_3.xml
similarity index 100%
rename from wear/tests/res/layout/box_inset_layout_testcase_3.xml
rename to wear/src/androidTest/res/layout/box_inset_layout_testcase_3.xml
diff --git a/wear/tests/res/layout/box_inset_layout_testcase_4.xml b/wear/src/androidTest/res/layout/box_inset_layout_testcase_4.xml
similarity index 100%
rename from wear/tests/res/layout/box_inset_layout_testcase_4.xml
rename to wear/src/androidTest/res/layout/box_inset_layout_testcase_4.xml
diff --git a/wear/tests/res/layout/circular_progress_layout.xml b/wear/src/androidTest/res/layout/circular_progress_layout.xml
similarity index 100%
rename from wear/tests/res/layout/circular_progress_layout.xml
rename to wear/src/androidTest/res/layout/circular_progress_layout.xml
diff --git a/wear/tests/res/layout/curved_offsetting_helper_child.xml b/wear/src/androidTest/res/layout/curved_offsetting_helper_child.xml
similarity index 100%
rename from wear/tests/res/layout/curved_offsetting_helper_child.xml
rename to wear/src/androidTest/res/layout/curved_offsetting_helper_child.xml
diff --git a/wear/tests/res/layout/rounded_drawable_layout.xml b/wear/src/androidTest/res/layout/rounded_drawable_layout.xml
similarity index 100%
rename from wear/tests/res/layout/rounded_drawable_layout.xml
rename to wear/src/androidTest/res/layout/rounded_drawable_layout.xml
diff --git a/wear/tests/res/layout/swipe_dismiss_layout_testcase_1.xml b/wear/src/androidTest/res/layout/swipe_dismiss_layout_testcase_1.xml
similarity index 100%
rename from wear/tests/res/layout/swipe_dismiss_layout_testcase_1.xml
rename to wear/src/androidTest/res/layout/swipe_dismiss_layout_testcase_1.xml
diff --git a/wear/tests/res/layout/swipe_dismiss_layout_testcase_2.xml b/wear/src/androidTest/res/layout/swipe_dismiss_layout_testcase_2.xml
similarity index 100%
rename from wear/tests/res/layout/swipe_dismiss_layout_testcase_2.xml
rename to wear/src/androidTest/res/layout/swipe_dismiss_layout_testcase_2.xml
diff --git a/wear/tests/res/layout/swipe_dismiss_layout_testcase_3.xml b/wear/src/androidTest/res/layout/swipe_dismiss_layout_testcase_3.xml
similarity index 100%
rename from wear/tests/res/layout/swipe_dismiss_layout_testcase_3.xml
rename to wear/src/androidTest/res/layout/swipe_dismiss_layout_testcase_3.xml
diff --git a/wear/tests/res/layout/test_multi_page_nav_drawer_layout.xml b/wear/src/androidTest/res/layout/test_multi_page_nav_drawer_layout.xml
similarity index 100%
rename from wear/tests/res/layout/test_multi_page_nav_drawer_layout.xml
rename to wear/src/androidTest/res/layout/test_multi_page_nav_drawer_layout.xml
diff --git a/wear/tests/res/layout/test_only_action_drawer_with_title_layout.xml b/wear/src/androidTest/res/layout/test_only_action_drawer_with_title_layout.xml
similarity index 100%
rename from wear/tests/res/layout/test_only_action_drawer_with_title_layout.xml
rename to wear/src/androidTest/res/layout/test_only_action_drawer_with_title_layout.xml
diff --git a/wear/tests/res/layout/test_single_page_nav_drawer_layout.xml b/wear/src/androidTest/res/layout/test_single_page_nav_drawer_layout.xml
similarity index 100%
rename from wear/tests/res/layout/test_single_page_nav_drawer_layout.xml
rename to wear/src/androidTest/res/layout/test_single_page_nav_drawer_layout.xml
diff --git a/wear/tests/res/layout/wearable_recycler_view_basic.xml b/wear/src/androidTest/res/layout/wearable_recycler_view_basic.xml
similarity index 100%
rename from wear/tests/res/layout/wearable_recycler_view_basic.xml
rename to wear/src/androidTest/res/layout/wearable_recycler_view_basic.xml
diff --git a/wear/tests/res/menu/action_drawer.xml b/wear/src/androidTest/res/menu/action_drawer.xml
similarity index 100%
rename from wear/tests/res/menu/action_drawer.xml
rename to wear/src/androidTest/res/menu/action_drawer.xml
diff --git a/wear/tests/res/values-sw213dp/styles.xml b/wear/src/androidTest/res/values-sw213dp/styles.xml
similarity index 100%
rename from wear/tests/res/values-sw213dp/styles.xml
rename to wear/src/androidTest/res/values-sw213dp/styles.xml
diff --git a/wear/tests/res/values/colors.xml b/wear/src/androidTest/res/values/colors.xml
similarity index 100%
rename from wear/tests/res/values/colors.xml
rename to wear/src/androidTest/res/values/colors.xml
diff --git a/wear/tests/res/values/dimens.xml b/wear/src/androidTest/res/values/dimens.xml
similarity index 100%
rename from wear/tests/res/values/dimens.xml
rename to wear/src/androidTest/res/values/dimens.xml
diff --git a/wear/tests/res/values/styles.xml b/wear/src/androidTest/res/values/styles.xml
similarity index 100%
rename from wear/tests/res/values/styles.xml
rename to wear/src/androidTest/res/values/styles.xml
diff --git a/wear/AndroidManifest.xml b/wear/src/main/AndroidManifest.xml
similarity index 100%
rename from wear/AndroidManifest.xml
rename to wear/src/main/AndroidManifest.xml
diff --git a/wear/src/main/java/android/support/wear/ambient/AmbientMode.java b/wear/src/main/java/android/support/wear/ambient/AmbientMode.java
index 5db9383..0077a5b 100644
--- a/wear/src/main/java/android/support/wear/ambient/AmbientMode.java
+++ b/wear/src/main/java/android/support/wear/ambient/AmbientMode.java
@@ -21,7 +21,9 @@
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.CallSuper;
+import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
+import android.util.Log;
import com.google.android.wearable.compat.WearableActivityController;
@@ -48,6 +50,7 @@
* }</pre>
*/
public final class AmbientMode extends Fragment {
+ private static final String TAG = "AmbientMode";
/**
* Property in bundle passed to {@code AmbientCallback#onEnterAmbient(Bundle)} to indicate
@@ -104,9 +107,6 @@
* running (after onResume, before onPause). All drawing should complete by the conclusion
* of this method. Note that {@code invalidate()} calls will be executed before resuming
* lower-power mode.
- * <p>
- * <p><em>Derived classes must call through to the super class's implementation of this
- * method. If they do not, an exception will be thrown.</em>
*
* @param ambientDetails bundle containing information about the display being used.
* It includes information about low-bit color and burn-in protection.
@@ -122,9 +122,6 @@
/**
* Called when an activity should exit ambient mode. This event is sent while an activity is
* running (after onResume, before onPause).
- * <p>
- * <p><em>Derived classes must call through to the super class's implementation of this
- * method. If they do not, an exception will be thrown.</em>
*/
public void onExitAmbient() {}
}
@@ -133,20 +130,27 @@
new AmbientDelegate.AmbientCallback() {
@Override
public void onEnterAmbient(Bundle ambientDetails) {
- mSuppliedCallback.onEnterAmbient(ambientDetails);
+ if (mSuppliedCallback != null) {
+ mSuppliedCallback.onEnterAmbient(ambientDetails);
+ }
}
@Override
public void onExitAmbient() {
- mSuppliedCallback.onExitAmbient();
+ if (mSuppliedCallback != null) {
+ mSuppliedCallback.onExitAmbient();
+ }
}
@Override
public void onUpdateAmbient() {
- mSuppliedCallback.onUpdateAmbient();
+ if (mSuppliedCallback != null) {
+ mSuppliedCallback.onUpdateAmbient();
+ }
}
};
private AmbientDelegate mDelegate;
+ @Nullable
private AmbientCallback mSuppliedCallback;
private AmbientController mController;
@@ -166,8 +170,7 @@
if (context instanceof AmbientCallbackProvider) {
mSuppliedCallback = ((AmbientCallbackProvider) context).getAmbientCallback();
} else {
- throw new IllegalArgumentException(
- "fragment should attach to an activity that implements AmbientCallback");
+ Log.w(TAG, "No callback provided - enabling only smart resume");
}
}
@@ -176,7 +179,9 @@
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDelegate.onCreate();
- mDelegate.setAmbientEnabled();
+ if (mSuppliedCallback != null) {
+ mDelegate.setAmbientEnabled();
+ }
}
@Override
@@ -215,15 +220,19 @@
}
/**
- * Attach ambient support to the given activity.
+ * Attach ambient support to the given activity. Calling this method with an Activity
+ * implementing the {@link AmbientCallbackProvider} interface will provide you with an
+ * opportunity to react to ambient events such as {@code onEnterAmbient}. Alternatively,
+ * you can call this method with an Activity which does not implement
+ * the {@link AmbientCallbackProvider} interface and that will only enable the auto-resume
+ * functionality. This is equivalent to providing (@code null} from
+ * the {@link AmbientCallbackProvider}.
*
- * @param activity the activity to attach ambient support to. This activity has to also
- * implement {@link AmbientCallbackProvider}
+ * @param activity the activity to attach ambient support to.
* @return the associated {@link AmbientController} which can be used to query the state of
* ambient mode.
*/
- public static <T extends Activity & AmbientCallbackProvider> AmbientController
- attachAmbientSupport(T activity) {
+ public static <T extends Activity> AmbientController attachAmbientSupport(T activity) {
FragmentManager fragmentManager = activity.getFragmentManager();
AmbientMode ambientFragment = (AmbientMode) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
if (ambientFragment == null) {