Merge "Move slices to androidx.slice package." into pi-preview1-androidx-dev
am: 71f41d78f9
Change-Id: I7f22286a0843dab6afeb6e976066151cce890313
diff --git a/annotations/build.gradle b/annotations/build.gradle
index 03d2e6c..15274fe 100644
--- a/annotations/build.gradle
+++ b/annotations/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportJavaLibraryPlugin")
diff --git a/app-toolkit/common/build.gradle b/app-toolkit/common/build.gradle
index db61b3f..81a34ad 100644
--- a/app-toolkit/common/build.gradle
+++ b/app-toolkit/common/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension;
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension;
plugins {
id("SupportJavaLibraryPlugin")
diff --git a/app-toolkit/core-testing/build.gradle b/app-toolkit/core-testing/build.gradle
index 8e7ccfb..e4c2e17 100644
--- a/app-toolkit/core-testing/build.gradle
+++ b/app-toolkit/core-testing/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/app-toolkit/init.gradle b/app-toolkit/init.gradle
index d3d7754..3c58368 100644
--- a/app-toolkit/init.gradle
+++ b/app-toolkit/init.gradle
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-import android.support.DacOptions
-import android.support.license.CheckExternalDependencyLicensesTask
+import androidx.build.DacOptions
+import androidx.build.license.CheckExternalDependencyLicensesTask
+
apply from: "${ext.supportRootFolder}/buildSrc/init.gradle"
init.setSdkInLocalPropertiesFile()
diff --git a/app-toolkit/runtime/build.gradle b/app-toolkit/runtime/build.gradle
index cd74aae..5c8f2d9 100644
--- a/app-toolkit/runtime/build.gradle
+++ b/app-toolkit/runtime/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.SupportLibraryExtension
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.SupportLibraryExtension
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/asynclayoutinflater/api/0.0.0.txt b/asynclayoutinflater/api/0.0.0.txt
new file mode 100644
index 0000000..83a85be
--- /dev/null
+++ b/asynclayoutinflater/api/0.0.0.txt
@@ -0,0 +1,13 @@
+package android.support.v4.view {
+
+ public final class AsyncLayoutInflater {
+ ctor public AsyncLayoutInflater(android.content.Context);
+ method public void inflate(int, android.view.ViewGroup, android.support.v4.view.AsyncLayoutInflater.OnInflateFinishedListener);
+ }
+
+ public static abstract interface AsyncLayoutInflater.OnInflateFinishedListener {
+ method public abstract void onInflateFinished(android.view.View, int, android.view.ViewGroup);
+ }
+
+}
+
diff --git a/asynclayoutinflater/build.gradle b/asynclayoutinflater/build.gradle
index 597b01d..a83d876 100644
--- a/asynclayoutinflater/build.gradle
+++ b/asynclayoutinflater/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/build.gradle b/build.gradle
index 0307507..c8683d4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import android.support.DacOptions
+
+import androidx.build.DacOptions
def currentJvmVersion = org.gradle.api.JavaVersion.current()
if (currentJvmVersion.getMajorVersion() != "8") {
diff --git a/buildSrc/init.gradle b/buildSrc/init.gradle
index 38b41e8..4faeac5 100644
--- a/buildSrc/init.gradle
+++ b/buildSrc/init.gradle
@@ -15,9 +15,9 @@
*/
-import android.support.DiffAndDocs
-import android.support.gmaven.GMavenVersionChecker
-import android.support.license.CheckExternalDependencyLicensesTask
+import androidx.build.DiffAndDocs
+import androidx.build.gmaven.GMavenVersionChecker
+import androidx.build.license.CheckExternalDependencyLicensesTask
import com.android.build.gradle.internal.coverage.JacocoReportTask
import com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask
import org.gradle.api.logging.configuration.ShowStacktrace
diff --git a/buildSrc/repos.gradle b/buildSrc/repos.gradle
index ba56c75..da1155e 100644
--- a/buildSrc/repos.gradle
+++ b/buildSrc/repos.gradle
@@ -46,7 +46,7 @@
// Full checkout prebuilts updated by update_current.py
"${repos.prebuiltsRoot}/sdk/current/support/m2repository",
// Unbundled checkout prebuilts updated by fullsdk drop
- "${getFullSdkPath(repos.prebuiltsRoot)}/extras/m2repository"]
+ "${getFullSdkPath(repos.prebuiltsRoot)}/extras/android/m2repository"]
/**
* Adds maven repositories to the given repository handler.
diff --git a/buildSrc/src/main/kotlin/android/support/DiffAndDocs.kt b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
similarity index 97%
rename from buildSrc/src/main/kotlin/android/support/DiffAndDocs.kt
rename to buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
index 72564cc..213a8a8 100644
--- a/buildSrc/src/main/kotlin/android/support/DiffAndDocs.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
-import android.support.checkapi.ApiXmlConversionTask
-import android.support.checkapi.CheckApiTask
-import android.support.checkapi.UpdateApiTask
-import android.support.doclava.DoclavaTask
-import android.support.docs.GenerateDocsTask
-import android.support.jdiff.JDiffTask
+import androidx.build.checkapi.ApiXmlConversionTask
+import androidx.build.checkapi.CheckApiTask
+import androidx.build.checkapi.UpdateApiTask
+import androidx.build.doclava.DoclavaTask
+import androidx.build.docs.GenerateDocsTask
+import androidx.build.jdiff.JDiffTask
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.api.LibraryVariant
import org.gradle.api.GradleException
@@ -228,7 +228,9 @@
*/
private fun createOldApiXml(project: Project, doclavaConfig: Configuration) =
project.tasks.createWithConfig("oldApiXml", ApiXmlConversionTask::class.java) {
- val toApi = project.processProperty("toApi")?.let { Version.parseOrNull(it) }
+ val toApi = project.processProperty("toApi")?.let {
+ Version.parseOrNull(it)
+ }
val fromApi = project.processProperty("fromApi")
classpath = project.files(doclavaConfig.resolve())
val rootFolder = project.projectDir
diff --git a/buildSrc/src/main/kotlin/android/support/ErrorProneConfiguration.kt b/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
similarity index 96%
rename from buildSrc/src/main/kotlin/android/support/ErrorProneConfiguration.kt
rename to buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
index 74f0505..53e6154 100644
--- a/buildSrc/src/main/kotlin/android/support/ErrorProneConfiguration.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
import net.ltgt.gradle.errorprone.ErrorProneToolChain
import org.gradle.api.tasks.compile.JavaCompile
@@ -40,6 +40,7 @@
"-Xep:OperatorPrecedence:ERROR",
"-Xep:IntLongMath:ERROR",
"-Xep:MissingFail:ERROR",
+ "-Xep:JavaLangClash:ERROR",
// Nullaway
"-XepIgnoreUnknownCheckNames", // https://github.com/uber/NullAway/issues/25
diff --git a/buildSrc/src/main/kotlin/android/support/LibraryGroups.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
similarity index 97%
rename from buildSrc/src/main/kotlin/android/support/LibraryGroups.kt
rename to buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
index 2f64e5d..385c04c 100644
--- a/buildSrc/src/main/kotlin/android/support/LibraryGroups.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
/**
* The list of maven group names of all the libraries in this project.
diff --git a/buildSrc/src/main/kotlin/android/support/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
similarity index 94%
rename from buildSrc/src/main/kotlin/android/support/LibraryVersions.kt
rename to buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
index 7daa0b7..7d00959 100644
--- a/buildSrc/src/main/kotlin/android/support/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
/**
* The list of versions codes of all the libraries in this project.
@@ -33,7 +33,7 @@
/**
* Version code for Lifecycle extensions (ProcessLifecycleOwner, Fragment support)
*/
- val LIFECYCLES_EXT = Version("1.1.0")
+ val LIFECYCLES_EXT = Version("1.2.0-alpha1")
/**
* Version code for Lifecycle LiveData
diff --git a/buildSrc/src/main/kotlin/android/support/MavenUploadHelper.kt b/buildSrc/src/main/kotlin/androidx/build/MavenUploadHelper.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/MavenUploadHelper.kt
rename to buildSrc/src/main/kotlin/androidx/build/MavenUploadHelper.kt
index c8be47a..dc86936 100644
--- a/buildSrc/src/main/kotlin/android/support/MavenUploadHelper.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/MavenUploadHelper.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
import com.android.build.gradle.LibraryPlugin
import org.gradle.api.Project
diff --git a/buildSrc/src/main/kotlin/android/support/SourceJarTaskHelper.kt b/buildSrc/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/SourceJarTaskHelper.kt
rename to buildSrc/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
index 992171e..5a11175 100644
--- a/buildSrc/src/main/kotlin/android/support/SourceJarTaskHelper.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
import com.android.build.gradle.LibraryExtension
import com.android.builder.core.BuilderConstants
diff --git a/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidLibraryPlugin.kt
similarity index 96%
rename from buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
rename to buildSrc/src/main/kotlin/androidx/build/SupportAndroidLibraryPlugin.kt
index 85b556a..da8dc88 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidLibraryPlugin.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
-import android.support.SupportConfig.INSTRUMENTATION_RUNNER
-import android.support.license.CheckExternalDependencyLicensesTask
+import androidx.build.SupportConfig.INSTRUMENTATION_RUNNER
+import androidx.build.license.CheckExternalDependencyLicensesTask
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.internal.dsl.LintOptions
import com.android.build.gradle.tasks.GenerateBuildConfig
diff --git a/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppExtension.kt b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidTestAppExtension.kt
similarity index 89%
rename from buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppExtension.kt
rename to buildSrc/src/main/kotlin/androidx/build/SupportAndroidTestAppExtension.kt
index 66dd873..3d3e0aa 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppExtension.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidTestAppExtension.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
-import android.support.SupportConfig.DEFAULT_MIN_SDK_VERSION
+import androidx.build.SupportConfig.DEFAULT_MIN_SDK_VERSION
import org.gradle.api.Project
/**
diff --git a/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidTestAppPlugin.kt
similarity index 94%
rename from buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppPlugin.kt
rename to buildSrc/src/main/kotlin/androidx/build/SupportAndroidTestAppPlugin.kt
index 1604bbe..1142ea0 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidTestAppPlugin.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
-import android.support.SupportConfig.INSTRUMENTATION_RUNNER
-import android.support.license.CheckExternalDependencyLicensesTask
+import androidx.build.SupportConfig.INSTRUMENTATION_RUNNER
+import androidx.build.license.CheckExternalDependencyLicensesTask
import com.android.build.gradle.AppExtension
import net.ltgt.gradle.errorprone.ErrorProneBasePlugin
import net.ltgt.gradle.errorprone.ErrorProneToolChain
diff --git a/buildSrc/src/main/kotlin/android/support/SupportConfig.kt b/buildSrc/src/main/kotlin/androidx/build/SupportConfig.kt
similarity index 97%
rename from buildSrc/src/main/kotlin/android/support/SupportConfig.kt
rename to buildSrc/src/main/kotlin/androidx/build/SupportConfig.kt
index 42b298c..1f216f7 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportConfig.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportConfig.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
import org.gradle.api.Project
import org.gradle.api.plugins.ExtraPropertiesExtension
diff --git a/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/SupportJavaLibraryPlugin.kt
similarity index 93%
rename from buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt
rename to buildSrc/src/main/kotlin/androidx/build/SupportJavaLibraryPlugin.kt
index f3651ab..24546f1 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportJavaLibraryPlugin.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
-import android.support.license.CheckExternalDependencyLicensesTask
+import androidx.build.license.CheckExternalDependencyLicensesTask
import net.ltgt.gradle.errorprone.ErrorProneBasePlugin
import net.ltgt.gradle.errorprone.ErrorProneToolChain
import org.gradle.api.JavaVersion
diff --git a/buildSrc/src/main/kotlin/android/support/SupportKotlinLibraryPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/SupportKotlinLibraryPlugin.kt
similarity index 90%
rename from buildSrc/src/main/kotlin/android/support/SupportKotlinLibraryPlugin.kt
rename to buildSrc/src/main/kotlin/androidx/build/SupportKotlinLibraryPlugin.kt
index 8651ef8..4103aad 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportKotlinLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportKotlinLibraryPlugin.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.support
+package androidx.build
-import android.support.license.CheckExternalDependencyLicensesTask
+import androidx.build.license.CheckExternalDependencyLicensesTask
import org.gradle.api.JavaVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
diff --git a/buildSrc/src/main/kotlin/android/support/SupportLibraryExtension.kt b/buildSrc/src/main/kotlin/androidx/build/SupportLibraryExtension.kt
similarity index 93%
rename from buildSrc/src/main/kotlin/android/support/SupportLibraryExtension.kt
rename to buildSrc/src/main/kotlin/androidx/build/SupportLibraryExtension.kt
index fb2f3b5..4f69460 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportLibraryExtension.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportLibraryExtension.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
-import android.support.SupportConfig.DEFAULT_MIN_SDK_VERSION
+import androidx.build.SupportConfig.DEFAULT_MIN_SDK_VERSION
import groovy.lang.Closure
import org.gradle.api.Project
import java.util.ArrayList
diff --git a/buildSrc/src/main/kotlin/android/support/Version.kt b/buildSrc/src/main/kotlin/androidx/build/Version.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/Version.kt
rename to buildSrc/src/main/kotlin/androidx/build/Version.kt
index 6348b0c..75855d5 100644
--- a/buildSrc/src/main/kotlin/android/support/Version.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/Version.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
import java.io.File
import java.util.regex.Matcher
diff --git a/buildSrc/src/main/kotlin/android/support/VersionFileWriterTask.kt b/buildSrc/src/main/kotlin/androidx/build/VersionFileWriterTask.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/VersionFileWriterTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/VersionFileWriterTask.kt
index cde11e6..9fbe3ba 100644
--- a/buildSrc/src/main/kotlin/android/support/VersionFileWriterTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/VersionFileWriterTask.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
import com.android.build.gradle.LibraryExtension
import org.gradle.api.DefaultTask
diff --git a/buildSrc/src/main/kotlin/android/support/checkapi/ApiXmlConversionTask.kt b/buildSrc/src/main/kotlin/androidx/build/checkapi/ApiXmlConversionTask.kt
similarity index 97%
rename from buildSrc/src/main/kotlin/android/support/checkapi/ApiXmlConversionTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/checkapi/ApiXmlConversionTask.kt
index a4733b2..419d66f 100644
--- a/buildSrc/src/main/kotlin/android/support/checkapi/ApiXmlConversionTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/checkapi/ApiXmlConversionTask.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.checkapi
+package androidx.build.checkapi
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.JavaExec
diff --git a/buildSrc/src/main/kotlin/android/support/checkapi/CheckApiTask.kt b/buildSrc/src/main/kotlin/androidx/build/checkapi/CheckApiTask.kt
similarity index 99%
rename from buildSrc/src/main/kotlin/android/support/checkapi/CheckApiTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/checkapi/CheckApiTask.kt
index be9f877..44f7d39 100644
--- a/buildSrc/src/main/kotlin/android/support/checkapi/CheckApiTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/checkapi/CheckApiTask.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.checkapi
+package androidx.build.checkapi
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
diff --git a/buildSrc/src/main/kotlin/android/support/checkapi/UpdateApiTask.kt b/buildSrc/src/main/kotlin/androidx/build/checkapi/UpdateApiTask.kt
similarity index 97%
rename from buildSrc/src/main/kotlin/android/support/checkapi/UpdateApiTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/checkapi/UpdateApiTask.kt
index 16c625a..810d50b 100644
--- a/buildSrc/src/main/kotlin/android/support/checkapi/UpdateApiTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/checkapi/UpdateApiTask.kt
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.support.checkapi
+package androidx.build.checkapi
-import android.support.Version
+import androidx.build.Version
import com.google.common.io.Files
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
diff --git a/buildSrc/src/main/kotlin/android/support/dependencies/Dependencies.kt b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/dependencies/Dependencies.kt
rename to buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
index 0844832..4199fae 100644
--- a/buildSrc/src/main/kotlin/android/support/dependencies/Dependencies.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.dependencies
+package androidx.build.dependencies
const val AUTO_COMMON = "com.google.auto:auto-common:0.6"
const val ANTLR = "org.antlr:antlr4:4.5.3"
diff --git a/buildSrc/src/main/kotlin/android/support/doclava/DoclavaTask.kt b/buildSrc/src/main/kotlin/androidx/build/doclava/DoclavaTask.kt
similarity index 99%
rename from buildSrc/src/main/kotlin/android/support/doclava/DoclavaTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/doclava/DoclavaTask.kt
index b30611d..3f0a6f5 100644
--- a/buildSrc/src/main/kotlin/android/support/doclava/DoclavaTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/doclava/DoclavaTask.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.doclava
+package androidx.build.doclava
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
diff --git a/buildSrc/src/main/kotlin/android/support/docs/GenerateDocsTask.kt b/buildSrc/src/main/kotlin/androidx/build/docs/GenerateDocsTask.kt
similarity index 94%
rename from buildSrc/src/main/kotlin/android/support/docs/GenerateDocsTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/docs/GenerateDocsTask.kt
index e889a54..4bbb830 100644
--- a/buildSrc/src/main/kotlin/android/support/docs/GenerateDocsTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/docs/GenerateDocsTask.kt
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package android.support.docs
+package androidx.build.docs
-import android.support.Version
-import android.support.doclava.DoclavaTask
+import androidx.build.Version
+import androidx.build.doclava.DoclavaTask
import java.io.File
open class GenerateDocsTask : DoclavaTask() {
diff --git a/buildSrc/src/main/kotlin/android/support/gmaven/GMavenVersionChecker.kt b/buildSrc/src/main/kotlin/androidx/build/gmaven/GMavenVersionChecker.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/gmaven/GMavenVersionChecker.kt
rename to buildSrc/src/main/kotlin/androidx/build/gmaven/GMavenVersionChecker.kt
index 7fc4836..3c1b8d0 100644
--- a/buildSrc/src/main/kotlin/android/support/gmaven/GMavenVersionChecker.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/gmaven/GMavenVersionChecker.kt
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.support.gmaven
+package androidx.build.gmaven
-import android.support.Version
+import androidx.build.Version
import groovy.util.XmlSlurper
import groovy.util.slurpersupport.Node
import groovy.util.slurpersupport.NodeChild
diff --git a/buildSrc/src/main/kotlin/android/support/jdiff/JDiffTask.kt b/buildSrc/src/main/kotlin/androidx/build/jdiff/JDiffTask.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/jdiff/JDiffTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/jdiff/JDiffTask.kt
index a6abc57..dfeb322 100644
--- a/buildSrc/src/main/kotlin/android/support/jdiff/JDiffTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/jdiff/JDiffTask.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.jdiff
+package androidx.build.jdiff
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
diff --git a/buildSrc/src/main/kotlin/android/support/license/CheckExternalDependencyLicensesTask.kt b/buildSrc/src/main/kotlin/androidx/build/license/CheckExternalDependencyLicensesTask.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/license/CheckExternalDependencyLicensesTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/license/CheckExternalDependencyLicensesTask.kt
index 771f222..2dc4e01 100644
--- a/buildSrc/src/main/kotlin/android/support/license/CheckExternalDependencyLicensesTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/license/CheckExternalDependencyLicensesTask.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.support.license
+package androidx.build.license
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidLibraryPlugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidLibraryPlugin.properties
index 222602b..25c8e4e 100644
--- a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidLibraryPlugin.properties
+++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidLibraryPlugin.properties
@@ -1 +1 @@
-implementation-class=android.support.SupportAndroidLibraryPlugin
\ No newline at end of file
+implementation-class=androidx.build.SupportAndroidLibraryPlugin
\ No newline at end of file
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidTestAppPlugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidTestAppPlugin.properties
index 4c794f1..8bb9716 100644
--- a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidTestAppPlugin.properties
+++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidTestAppPlugin.properties
@@ -1 +1 @@
-implementation-class=android.support.SupportAndroidTestAppPlugin
\ No newline at end of file
+implementation-class=androidx.build.SupportAndroidTestAppPlugin
\ No newline at end of file
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportJavaLibraryPlugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportJavaLibraryPlugin.properties
index 89755b7..acc6819 100644
--- a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportJavaLibraryPlugin.properties
+++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportJavaLibraryPlugin.properties
@@ -1 +1 @@
-implementation-class=android.support.SupportJavaLibraryPlugin
\ No newline at end of file
+implementation-class=androidx.build.SupportJavaLibraryPlugin
\ No newline at end of file
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportKotlinLibraryPlugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportKotlinLibraryPlugin.properties
index d93c20a..f50d743 100644
--- a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportKotlinLibraryPlugin.properties
+++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportKotlinLibraryPlugin.properties
@@ -1 +1 @@
-implementation-class=android.support.SupportKotlinLibraryPlugin
+implementation-class=androidx.build.SupportKotlinLibraryPlugin
diff --git a/buildSrc/src/test/kotlin/android/support/VersionTest.kt b/buildSrc/src/test/kotlin/androidx/build/VersionTest.kt
similarity index 95%
rename from buildSrc/src/test/kotlin/android/support/VersionTest.kt
rename to buildSrc/src/test/kotlin/androidx/build/VersionTest.kt
index 339acab..fc803d9 100644
--- a/buildSrc/src/test/kotlin/android/support/VersionTest.kt
+++ b/buildSrc/src/test/kotlin/androidx/build/VersionTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support
+package androidx.build
import org.junit.Assert.assertEquals
import org.junit.Test
diff --git a/car/build.gradle b/car/build.gradle
index 251be6d..a1212e2 100644
--- a/car/build.gradle
+++ b/car/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/collections/build.gradle b/collections/build.gradle
index 3145c4a..a5ebc43 100644
--- a/collections/build.gradle
+++ b/collections/build.gradle
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportJavaLibraryPlugin")
diff --git a/compat/build.gradle b/compat/build.gradle
index f52c5ff..3cb9b06 100644
--- a/compat/build.gradle
+++ b/compat/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
@@ -15,7 +15,7 @@
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'), {
+ androidTestImplementation project(':internal-testutils'), {
exclude group: 'com.android.support', module: 'support-compat'
}
}
diff --git a/compat/res/values-port/bools.xml b/compat/res/values-port/bools.xml
deleted file mode 100644
index 25053be..0000000
--- a/compat/res/values-port/bools.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<resources>
-
- <bool name="abc_action_bar_embed_tabs">false</bool>
-
-</resources>
diff --git a/compat/src/androidTest/java/android/support/v4/widget/ContentLoadingProgressBarTest.java b/compat/src/androidTest/java/android/support/v4/widget/ContentLoadingProgressBarTest.java
index c8bc229..9375aad 100644
--- a/compat/src/androidTest/java/android/support/v4/widget/ContentLoadingProgressBarTest.java
+++ b/compat/src/androidTest/java/android/support/v4/widget/ContentLoadingProgressBarTest.java
@@ -22,7 +22,6 @@
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
import android.view.View;
import org.junit.Before;
@@ -30,6 +29,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import androidx.testutils.PollingCheck;
+
/**
* Tests for {@link ContentLoadingProgressBar}
*/
diff --git a/content/build.gradle b/content/build.gradle
index 990f308..ea39651 100644
--- a/content/build.gradle
+++ b/content/build.gradle
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/coordinatorlayout/api/0.0.0.txt b/coordinatorlayout/api/0.0.0.txt
new file mode 100644
index 0000000..a5a44a2
--- /dev/null
+++ b/coordinatorlayout/api/0.0.0.txt
@@ -0,0 +1,97 @@
+package android.support.design.widget {
+
+ 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);
+ method public void dispatchDependentViewsChanged(android.view.View);
+ method public boolean doViewsOverlap(android.view.View, android.view.View);
+ method protected android.support.design.widget.CoordinatorLayout.LayoutParams generateDefaultLayoutParams();
+ method public android.support.design.widget.CoordinatorLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
+ method protected android.support.design.widget.CoordinatorLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
+ method public java.util.List<android.view.View> getDependencies(android.view.View);
+ method public java.util.List<android.view.View> getDependents(android.view.View);
+ method public android.graphics.drawable.Drawable getStatusBarBackground();
+ method public boolean isPointInChildBounds(android.view.View, int, int);
+ method public void onAttachedToWindow();
+ method public void onDetachedFromWindow();
+ method public void onDraw(android.graphics.Canvas);
+ 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);
+ method public void onNestedScroll(android.view.View, int, int, int, int, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+ method public void onStopNestedScroll(android.view.View, int);
+ method public void setStatusBarBackground(android.graphics.drawable.Drawable);
+ method public void setStatusBarBackgroundColor(int);
+ method public void setStatusBarBackgroundResource(int);
+ }
+
+ public static abstract interface CoordinatorLayout.AttachedBehavior {
+ method public abstract android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
+ }
+
+ public static abstract class CoordinatorLayout.Behavior<V extends android.view.View> {
+ ctor public CoordinatorLayout.Behavior();
+ ctor public CoordinatorLayout.Behavior(android.content.Context, android.util.AttributeSet);
+ method public boolean blocksInteractionBelow(android.support.design.widget.CoordinatorLayout, V);
+ method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect);
+ method public int getScrimColor(android.support.design.widget.CoordinatorLayout, V);
+ method public float getScrimOpacity(android.support.design.widget.CoordinatorLayout, V);
+ method public static java.lang.Object getTag(android.view.View);
+ method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+ method public android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.support.design.widget.CoordinatorLayout, V, android.support.v4.view.WindowInsetsCompat);
+ method public void onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
+ method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+ method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+ method public void onDetachedFromLayoutParams();
+ method public boolean onInterceptTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
+ method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, V, int);
+ method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, V, int, int, int, int);
+ method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float, boolean);
+ method public boolean onNestedPreFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float);
+ method public deprecated void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
+ method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[], int);
+ method public deprecated void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int);
+ method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int, int);
+ method public deprecated void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
+ method public void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int, int);
+ method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean);
+ method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, V, android.os.Parcelable);
+ method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, V);
+ method public deprecated boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
+ method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int, int);
+ method public deprecated void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+ method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int);
+ method public boolean onTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
+ method public static void setTag(android.view.View, java.lang.Object);
+ }
+
+ public static abstract deprecated class CoordinatorLayout.DefaultBehavior implements java.lang.annotation.Annotation {
+ }
+
+ public static class CoordinatorLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public CoordinatorLayout.LayoutParams(int, int);
+ ctor public CoordinatorLayout.LayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
+ ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ method public int getAnchorId();
+ method public android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
+ method public void setAnchorId(int);
+ method public void setBehavior(android.support.design.widget.CoordinatorLayout.Behavior);
+ field public int anchorGravity;
+ field public int dodgeInsetEdges;
+ field public int gravity;
+ field public int insetEdge;
+ field public int keyline;
+ }
+
+ protected static class CoordinatorLayout.SavedState extends android.support.v4.view.AbsSavedState {
+ ctor public CoordinatorLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
+ ctor public CoordinatorLayout.SavedState(android.os.Parcelable);
+ field public static final android.os.Parcelable.Creator<android.support.design.widget.CoordinatorLayout.SavedState> CREATOR;
+ }
+
+}
+
diff --git a/coordinatorlayout/build.gradle b/coordinatorlayout/build.gradle
index c6ce55b..0f9e7ab 100644
--- a/coordinatorlayout/build.gradle
+++ b/coordinatorlayout/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
@@ -15,7 +15,7 @@
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'), {
+ androidTestImplementation project(':internal-testutils'), {
exclude group: 'com.android.support', module: 'support-core-ui'
}
}
diff --git a/coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseTestActivity.java b/coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseTestActivity.java
index 0dd56e4..4272f56 100755
--- a/coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseTestActivity.java
+++ b/coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseTestActivity.java
@@ -18,9 +18,10 @@
import android.os.Bundle;
import android.support.annotation.LayoutRes;
-import android.support.testutils.RecreatedActivity;
import android.view.WindowManager;
+import androidx.testutils.RecreatedActivity;
+
abstract class BaseTestActivity extends RecreatedActivity {
private boolean mDestroyed;
diff --git a/core-ui/build.gradle b/core-ui/build.gradle
index 12f5525..9fd62d1 100644
--- a/core-ui/build.gradle
+++ b/core-ui/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
@@ -24,7 +24,7 @@
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'), {
+ androidTestImplementation project(':internal-testutils'), {
exclude group: 'com.android.support', module: 'support-core-ui'
}
diff --git a/core-utils/build.gradle b/core-utils/build.gradle
index ffc0ab8..9f66444 100644
--- a/core-utils/build.gradle
+++ b/core-utils/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/cursoradapter/api/0.0.0.txt b/cursoradapter/api/0.0.0.txt
new file mode 100644
index 0000000..07f7287
--- /dev/null
+++ b/cursoradapter/api/0.0.0.txt
@@ -0,0 +1,61 @@
+package android.support.v4.widget {
+
+ 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);
+ method public abstract void bindView(android.view.View, android.content.Context, android.database.Cursor);
+ method public void changeCursor(android.database.Cursor);
+ method public java.lang.CharSequence convertToString(android.database.Cursor);
+ method public int getCount();
+ method public android.database.Cursor getCursor();
+ method public android.widget.Filter getFilter();
+ method public android.widget.FilterQueryProvider getFilterQueryProvider();
+ method public java.lang.Object getItem(int);
+ method public long getItemId(int);
+ method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
+ method protected deprecated void init(android.content.Context, android.database.Cursor, boolean);
+ method public android.view.View newDropDownView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+ method public abstract android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+ method protected void onContentChanged();
+ method public android.database.Cursor runQueryOnBackgroundThread(java.lang.CharSequence);
+ method public void setFilterQueryProvider(android.widget.FilterQueryProvider);
+ method public android.database.Cursor swapCursor(android.database.Cursor);
+ field public static final deprecated int FLAG_AUTO_REQUERY = 1; // 0x1
+ field public static final int FLAG_REGISTER_CONTENT_OBSERVER = 2; // 0x2
+ }
+
+ public abstract class ResourceCursorAdapter extends android.support.v4.widget.CursorAdapter {
+ ctor public deprecated ResourceCursorAdapter(android.content.Context, int, android.database.Cursor);
+ ctor public deprecated ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, boolean);
+ ctor public ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, int);
+ method public android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+ method public void setDropDownViewResource(int);
+ method public void setViewResource(int);
+ }
+
+ public class SimpleCursorAdapter extends android.support.v4.widget.ResourceCursorAdapter {
+ ctor public deprecated SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[]);
+ ctor public SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[], int);
+ method public void bindView(android.view.View, android.content.Context, android.database.Cursor);
+ method public void changeCursorAndColumns(android.database.Cursor, java.lang.String[], int[]);
+ method public android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter getCursorToStringConverter();
+ method public int getStringConversionColumn();
+ method public android.support.v4.widget.SimpleCursorAdapter.ViewBinder getViewBinder();
+ method public void setCursorToStringConverter(android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter);
+ method public void setStringConversionColumn(int);
+ method public void setViewBinder(android.support.v4.widget.SimpleCursorAdapter.ViewBinder);
+ method public void setViewImage(android.widget.ImageView, java.lang.String);
+ method public void setViewText(android.widget.TextView, java.lang.String);
+ }
+
+ public static abstract interface SimpleCursorAdapter.CursorToStringConverter {
+ method public abstract java.lang.CharSequence convertToString(android.database.Cursor);
+ }
+
+ public static abstract interface SimpleCursorAdapter.ViewBinder {
+ method public abstract boolean setViewValue(android.view.View, android.database.Cursor, int);
+ }
+
+}
+
diff --git a/cursoradapter/build.gradle b/cursoradapter/build.gradle
index d08a8bc..2e379a1 100644
--- a/cursoradapter/build.gradle
+++ b/cursoradapter/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/customtabs/build.gradle b/customtabs/build.gradle
index ced95b8..8df42d0 100644
--- a/customtabs/build.gradle
+++ b/customtabs/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
@@ -14,7 +14,7 @@
androidTestImplementation(TEST_RUNNER)
androidTestImplementation(ESPRESSO_CORE)
- androidTestImplementation(project(":support-testutils"))
+ androidTestImplementation(project(":internal-testutils"))
}
supportLibrary {
diff --git a/customtabs/src/androidTest/java/android/support/customtabs/PostMessageServiceConnectionTest.java b/customtabs/src/androidTest/java/android/support/customtabs/PostMessageServiceConnectionTest.java
index 07d21a8..381afae 100644
--- a/customtabs/src/androidTest/java/android/support/customtabs/PostMessageServiceConnectionTest.java
+++ b/customtabs/src/androidTest/java/android/support/customtabs/PostMessageServiceConnectionTest.java
@@ -26,7 +26,6 @@
import android.support.test.rule.ActivityTestRule;
import android.support.test.rule.ServiceTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
import org.junit.Before;
import org.junit.Rule;
@@ -35,6 +34,8 @@
import java.util.concurrent.TimeoutException;
+import androidx.testutils.PollingCheck;
+
/**
* Tests for {@link PostMessageServiceConnection} with no {@link CustomTabsService} component.
*/
diff --git a/customtabs/src/androidTest/java/android/support/customtabs/PostMessageTest.java b/customtabs/src/androidTest/java/android/support/customtabs/PostMessageTest.java
index 7e342b4..6e96b45 100644
--- a/customtabs/src/androidTest/java/android/support/customtabs/PostMessageTest.java
+++ b/customtabs/src/androidTest/java/android/support/customtabs/PostMessageTest.java
@@ -29,7 +29,6 @@
import android.support.test.rule.ActivityTestRule;
import android.support.test.rule.ServiceTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
import org.junit.Before;
import org.junit.Rule;
@@ -38,6 +37,8 @@
import java.util.concurrent.atomic.AtomicBoolean;
+import androidx.testutils.PollingCheck;
+
/**
* Tests for a complete loop between a browser side {@link CustomTabsService}
diff --git a/customview/api/0.0.0.txt b/customview/api/0.0.0.txt
new file mode 100644
index 0000000..1e8a9c1
--- /dev/null
+++ b/customview/api/0.0.0.txt
@@ -0,0 +1,105 @@
+package android.support.v4.view {
+
+ public abstract class AbsSavedState implements android.os.Parcelable {
+ ctor protected AbsSavedState(android.os.Parcelable);
+ ctor protected AbsSavedState(android.os.Parcel);
+ ctor protected AbsSavedState(android.os.Parcel, java.lang.ClassLoader);
+ method public int describeContents();
+ method public final android.os.Parcelable getSuperState();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.view.AbsSavedState> CREATOR;
+ field public static final android.support.v4.view.AbsSavedState EMPTY_STATE;
+ }
+
+}
+
+package android.support.v4.widget {
+
+ public abstract class ExploreByTouchHelper extends android.support.v4.view.AccessibilityDelegateCompat {
+ ctor public ExploreByTouchHelper(android.view.View);
+ method public final boolean clearKeyboardFocusForVirtualView(int);
+ method public final boolean dispatchHoverEvent(android.view.MotionEvent);
+ method public final boolean dispatchKeyEvent(android.view.KeyEvent);
+ method public final int getAccessibilityFocusedVirtualViewId();
+ method public deprecated int getFocusedVirtualView();
+ method public final int getKeyboardFocusedVirtualViewId();
+ method protected abstract int getVirtualViewAt(float, float);
+ method protected abstract void getVisibleVirtualViews(java.util.List<java.lang.Integer>);
+ method public final void invalidateRoot();
+ method public final void invalidateVirtualView(int);
+ method public final void invalidateVirtualView(int, int);
+ method public final void onFocusChanged(boolean, int, android.graphics.Rect);
+ method protected abstract boolean onPerformActionForVirtualView(int, int, android.os.Bundle);
+ method protected void onPopulateEventForHost(android.view.accessibility.AccessibilityEvent);
+ method protected void onPopulateEventForVirtualView(int, android.view.accessibility.AccessibilityEvent);
+ method protected void onPopulateNodeForHost(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+ method protected abstract void onPopulateNodeForVirtualView(int, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+ method protected void onVirtualViewKeyboardFocusChanged(int, boolean);
+ method public final boolean requestKeyboardFocusForVirtualView(int);
+ method public final boolean sendEventForVirtualView(int, int);
+ field public static final int HOST_ID = -1; // 0xffffffff
+ field public static final int INVALID_ID = -2147483648; // 0x80000000
+ }
+
+ public class ViewDragHelper {
+ method public void abort();
+ method protected boolean canScroll(android.view.View, boolean, int, int, int, int);
+ method public void cancel();
+ method public void captureChildView(android.view.View, int);
+ method public boolean checkTouchSlop(int);
+ method public boolean checkTouchSlop(int, int);
+ method public boolean continueSettling(boolean);
+ method public static android.support.v4.widget.ViewDragHelper create(android.view.ViewGroup, android.support.v4.widget.ViewDragHelper.Callback);
+ method public static android.support.v4.widget.ViewDragHelper create(android.view.ViewGroup, float, android.support.v4.widget.ViewDragHelper.Callback);
+ method public android.view.View findTopChildUnder(int, int);
+ method public void flingCapturedView(int, int, int, int);
+ method public int getActivePointerId();
+ method public android.view.View getCapturedView();
+ method public int getEdgeSize();
+ method public float getMinVelocity();
+ method public int getTouchSlop();
+ method public int getViewDragState();
+ method public boolean isCapturedViewUnder(int, int);
+ method public boolean isEdgeTouched(int);
+ method public boolean isEdgeTouched(int, int);
+ method public boolean isPointerDown(int);
+ method public boolean isViewUnder(android.view.View, int, int);
+ method public void processTouchEvent(android.view.MotionEvent);
+ method public void setEdgeTrackingEnabled(int);
+ method public void setMinVelocity(float);
+ method public boolean settleCapturedViewAt(int, int);
+ method public boolean shouldInterceptTouchEvent(android.view.MotionEvent);
+ method public boolean smoothSlideViewTo(android.view.View, int, int);
+ field public static final int DIRECTION_ALL = 3; // 0x3
+ field public static final int DIRECTION_HORIZONTAL = 1; // 0x1
+ field public static final int DIRECTION_VERTICAL = 2; // 0x2
+ field public static final int EDGE_ALL = 15; // 0xf
+ field public static final int EDGE_BOTTOM = 8; // 0x8
+ field public static final int EDGE_LEFT = 1; // 0x1
+ field public static final int EDGE_RIGHT = 2; // 0x2
+ field public static final int EDGE_TOP = 4; // 0x4
+ field public static final int INVALID_POINTER = -1; // 0xffffffff
+ field public static final int STATE_DRAGGING = 1; // 0x1
+ field public static final int STATE_IDLE = 0; // 0x0
+ field public static final int STATE_SETTLING = 2; // 0x2
+ }
+
+ public static abstract class ViewDragHelper.Callback {
+ ctor public ViewDragHelper.Callback();
+ method public int clampViewPositionHorizontal(android.view.View, int, int);
+ method public int clampViewPositionVertical(android.view.View, int, int);
+ method public int getOrderedChildIndex(int);
+ method public int getViewHorizontalDragRange(android.view.View);
+ method public int getViewVerticalDragRange(android.view.View);
+ method public void onEdgeDragStarted(int, int);
+ method public boolean onEdgeLock(int);
+ method public void onEdgeTouched(int, int);
+ method public void onViewCaptured(android.view.View, int);
+ method public void onViewDragStateChanged(int);
+ method public void onViewPositionChanged(android.view.View, int, int, int, int);
+ method public void onViewReleased(android.view.View, float, float);
+ method public abstract boolean tryCaptureView(android.view.View, int);
+ }
+
+}
+
diff --git a/customview/build.gradle b/customview/build.gradle
index 108ec71..421a2e0 100644
--- a/customview/build.gradle
+++ b/customview/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/documentfile/api/0.0.0.txt b/documentfile/api/0.0.0.txt
new file mode 100644
index 0000000..6d7790b
--- /dev/null
+++ b/documentfile/api/0.0.0.txt
@@ -0,0 +1,29 @@
+package android.support.v4.provider {
+
+ public abstract class DocumentFile {
+ method public abstract boolean canRead();
+ method public abstract boolean canWrite();
+ method public abstract android.support.v4.provider.DocumentFile createDirectory(java.lang.String);
+ method public abstract android.support.v4.provider.DocumentFile createFile(java.lang.String, java.lang.String);
+ method public abstract boolean delete();
+ method public abstract boolean exists();
+ method public android.support.v4.provider.DocumentFile findFile(java.lang.String);
+ method public static android.support.v4.provider.DocumentFile fromFile(java.io.File);
+ method public static android.support.v4.provider.DocumentFile fromSingleUri(android.content.Context, android.net.Uri);
+ method public static android.support.v4.provider.DocumentFile fromTreeUri(android.content.Context, android.net.Uri);
+ method public abstract java.lang.String getName();
+ method public android.support.v4.provider.DocumentFile getParentFile();
+ method public abstract java.lang.String getType();
+ method public abstract android.net.Uri getUri();
+ method public abstract boolean isDirectory();
+ method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+ method public abstract boolean isFile();
+ method public abstract boolean isVirtual();
+ method public abstract long lastModified();
+ method public abstract long length();
+ method public abstract android.support.v4.provider.DocumentFile[] listFiles();
+ method public abstract boolean renameTo(java.lang.String);
+ }
+
+}
+
diff --git a/documentfile/build.gradle b/documentfile/build.gradle
index 2f59518..460332f 100644
--- a/documentfile/build.gradle
+++ b/documentfile/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/drawerlayout/api/0.0.0.txt b/drawerlayout/api/0.0.0.txt
new file mode 100644
index 0000000..c1a0b4c
--- /dev/null
+++ b/drawerlayout/api/0.0.0.txt
@@ -0,0 +1,81 @@
+package android.support.v4.widget {
+
+ public class DrawerLayout extends android.view.ViewGroup {
+ ctor public DrawerLayout(android.content.Context);
+ ctor public DrawerLayout(android.content.Context, android.util.AttributeSet);
+ ctor public DrawerLayout(android.content.Context, android.util.AttributeSet, int);
+ method public void addDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
+ method public void closeDrawer(android.view.View);
+ method public void closeDrawer(android.view.View, boolean);
+ method public void closeDrawer(int);
+ method public void closeDrawer(int, boolean);
+ method public void closeDrawers();
+ method public float getDrawerElevation();
+ method public int getDrawerLockMode(int);
+ method public int getDrawerLockMode(android.view.View);
+ method public java.lang.CharSequence getDrawerTitle(int);
+ method public android.graphics.drawable.Drawable getStatusBarBackgroundDrawable();
+ method public boolean isDrawerOpen(android.view.View);
+ method public boolean isDrawerOpen(int);
+ method public boolean isDrawerVisible(android.view.View);
+ method public boolean isDrawerVisible(int);
+ method public void onDraw(android.graphics.Canvas);
+ method public void openDrawer(android.view.View);
+ method public void openDrawer(android.view.View, boolean);
+ method public void openDrawer(int);
+ method public void openDrawer(int, boolean);
+ method public void removeDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
+ method public void setDrawerElevation(float);
+ method public deprecated void setDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
+ method public void setDrawerLockMode(int);
+ method public void setDrawerLockMode(int, int);
+ method public void setDrawerLockMode(int, android.view.View);
+ method public void setDrawerShadow(android.graphics.drawable.Drawable, int);
+ method public void setDrawerShadow(int, int);
+ method public void setDrawerTitle(int, java.lang.CharSequence);
+ method public void setScrimColor(int);
+ method public void setStatusBarBackground(android.graphics.drawable.Drawable);
+ method public void setStatusBarBackground(int);
+ method public void setStatusBarBackgroundColor(int);
+ field public static final int LOCK_MODE_LOCKED_CLOSED = 1; // 0x1
+ field public static final int LOCK_MODE_LOCKED_OPEN = 2; // 0x2
+ field public static final int LOCK_MODE_UNDEFINED = 3; // 0x3
+ field public static final int LOCK_MODE_UNLOCKED = 0; // 0x0
+ field public static final int STATE_DRAGGING = 1; // 0x1
+ field public static final int STATE_IDLE = 0; // 0x0
+ field public static final int STATE_SETTLING = 2; // 0x2
+ }
+
+ public static abstract interface DrawerLayout.DrawerListener {
+ method public abstract void onDrawerClosed(android.view.View);
+ method public abstract void onDrawerOpened(android.view.View);
+ method public abstract void onDrawerSlide(android.view.View, float);
+ method public abstract void onDrawerStateChanged(int);
+ }
+
+ public static class DrawerLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public DrawerLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public DrawerLayout.LayoutParams(int, int);
+ ctor public DrawerLayout.LayoutParams(int, int, int);
+ ctor public DrawerLayout.LayoutParams(android.support.v4.widget.DrawerLayout.LayoutParams);
+ ctor public DrawerLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public DrawerLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ field public int gravity;
+ }
+
+ protected static class DrawerLayout.SavedState extends android.support.v4.view.AbsSavedState {
+ ctor public DrawerLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
+ ctor public DrawerLayout.SavedState(android.os.Parcelable);
+ field public static final android.os.Parcelable.Creator<android.support.v4.widget.DrawerLayout.SavedState> CREATOR;
+ }
+
+ public static abstract class DrawerLayout.SimpleDrawerListener implements android.support.v4.widget.DrawerLayout.DrawerListener {
+ ctor public DrawerLayout.SimpleDrawerListener();
+ method public void onDrawerClosed(android.view.View);
+ method public void onDrawerOpened(android.view.View);
+ method public void onDrawerSlide(android.view.View, float);
+ method public void onDrawerStateChanged(int);
+ }
+
+}
+
diff --git a/drawerlayout/build.gradle b/drawerlayout/build.gradle
index 1d1476b..b4cc482 100644
--- a/drawerlayout/build.gradle
+++ b/drawerlayout/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/dynamic-animation/build.gradle b/dynamic-animation/build.gradle
index 451e874..04d3c33 100644
--- a/dynamic-animation/build.gradle
+++ b/dynamic-animation/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/emoji/appcompat/build.gradle b/emoji/appcompat/build.gradle
index 8a75f66..5c00c8e 100644
--- a/emoji/appcompat/build.gradle
+++ b/emoji/appcompat/build.gradle
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/emoji/bundled/build.gradle b/emoji/bundled/build.gradle
index 7c3a76a..181f893 100644
--- a/emoji/bundled/build.gradle
+++ b/emoji/bundled/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/emoji/core/build.gradle b/emoji/core/build.gradle
index 449ebb1..4936635 100644
--- a/emoji/core/build.gradle
+++ b/emoji/core/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
import java.util.zip.ZipException
import java.util.zip.ZipFile
@@ -28,7 +28,7 @@
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')
+ androidTestImplementation project(':internal-testutils')
}
android {
diff --git a/emoji/core/src/androidTest/java/android/support/text/emoji/EmojiKeyboardTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/EmojiKeyboardTest.java
index 1c647ce..aafa0d1 100644
--- a/emoji/core/src/androidTest/java/android/support/text/emoji/EmojiKeyboardTest.java
+++ b/emoji/core/src/androidTest/java/android/support/text/emoji/EmojiKeyboardTest.java
@@ -30,7 +30,6 @@
import android.support.test.filters.Suppress;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
import android.support.text.emoji.test.R;
import android.support.text.emoji.util.KeyboardUtil;
import android.support.text.emoji.util.TestString;
@@ -44,6 +43,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import androidx.testutils.PollingCheck;
+
@LargeTest
@RunWith(AndroidJUnit4.class)
@Suppress
diff --git a/exifinterface/build.gradle b/exifinterface/build.gradle
index e81d422..1914d9c 100644
--- a/exifinterface/build.gradle
+++ b/exifinterface/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/fragment/build.gradle b/fragment/build.gradle
index 4a3c1d1..9e7f478 100644
--- a/fragment/build.gradle
+++ b/fragment/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
@@ -18,7 +18,7 @@
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'), {
+ androidTestImplementation project(':internal-testutils'), {
exclude group: 'com.android.support', module: 'support-fragment'
}
}
diff --git a/fragment/src/androidTest/java/android/support/v4/app/FragmentManagerNonConfigTest.java b/fragment/src/androidTest/java/android/support/v4/app/FragmentManagerNonConfigTest.java
index dc62c01..c3bea05 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/FragmentManagerNonConfigTest.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/FragmentManagerNonConfigTest.java
@@ -21,13 +21,14 @@
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.FragmentActivityUtils;
import android.support.v4.app.test.NonConfigOnStopActivity;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import androidx.testutils.FragmentActivityUtils;
+
@MediumTest
@RunWith(AndroidJUnit4.class)
public class FragmentManagerNonConfigTest {
diff --git a/fragment/src/androidTest/java/android/support/v4/app/HangingFragmentTest.java b/fragment/src/androidTest/java/android/support/v4/app/HangingFragmentTest.java
index bf8726f..bb8d1db 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/HangingFragmentTest.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/HangingFragmentTest.java
@@ -19,7 +19,6 @@
import android.support.test.filters.SmallTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.FragmentActivityUtils;
import android.support.v4.app.test.HangingFragmentActivity;
import org.junit.Assert;
@@ -27,6 +26,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import androidx.testutils.FragmentActivityUtils;
@RunWith(AndroidJUnit4.class)
@SmallTest
diff --git a/fragment/src/androidTest/java/android/support/v4/app/LoaderTest.java b/fragment/src/androidTest/java/android/support/v4/app/LoaderTest.java
index 1d89e27..4a1837f 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/LoaderTest.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/LoaderTest.java
@@ -32,8 +32,6 @@
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.FragmentActivityUtils;
-import android.support.testutils.RecreatedActivity;
import android.support.v4.app.test.LoaderActivity;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
@@ -46,6 +44,9 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import androidx.testutils.FragmentActivityUtils;
+import androidx.testutils.RecreatedActivity;
+
@RunWith(AndroidJUnit4.class)
@MediumTest
public class LoaderTest {
diff --git a/fragment/src/androidTest/java/android/support/v4/app/test/HangingFragmentActivity.java b/fragment/src/androidTest/java/android/support/v4/app/test/HangingFragmentActivity.java
index 80b9aa5..bdf29cb 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/test/HangingFragmentActivity.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/test/HangingFragmentActivity.java
@@ -19,7 +19,8 @@
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.fragment.test.R;
-import android.support.testutils.RecreatedActivity;
+
+import androidx.testutils.RecreatedActivity;
public class HangingFragmentActivity extends RecreatedActivity {
diff --git a/fragment/src/androidTest/java/android/support/v4/app/test/LoaderActivity.java b/fragment/src/androidTest/java/android/support/v4/app/test/LoaderActivity.java
index f6ddf9c..1c88dbe 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/test/LoaderActivity.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/test/LoaderActivity.java
@@ -21,7 +21,6 @@
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.fragment.test.R;
-import android.support.testutils.RecreatedActivity;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
@@ -31,6 +30,8 @@
import android.view.ViewGroup;
import android.widget.TextView;
+import androidx.testutils.RecreatedActivity;
+
public class LoaderActivity extends RecreatedActivity
implements LoaderManager.LoaderCallbacks<String> {
private static final int TEXT_LOADER_ID = 14;
diff --git a/fragment/src/androidTest/java/android/support/v4/app/test/NonConfigOnStopActivity.java b/fragment/src/androidTest/java/android/support/v4/app/test/NonConfigOnStopActivity.java
index 9d71388..f52ddbd 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/test/NonConfigOnStopActivity.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/test/NonConfigOnStopActivity.java
@@ -16,9 +16,10 @@
package android.support.v4.app.test;
-import android.support.testutils.RecreatedActivity;
import android.support.v4.app.Fragment;
+import androidx.testutils.RecreatedActivity;
+
public class NonConfigOnStopActivity extends RecreatedActivity {
@Override
protected void onStop() {
diff --git a/fragment/src/main/java/android/support/v4/app/DialogFragment.java b/fragment/src/main/java/android/support/v4/app/DialogFragment.java
index b6bbb48..b585863 100644
--- a/fragment/src/main/java/android/support/v4/app/DialogFragment.java
+++ b/fragment/src/main/java/android/support/v4/app/DialogFragment.java
@@ -320,7 +320,8 @@
}
@Override
- public LayoutInflater onGetLayoutInflater(Bundle savedInstanceState) {
+ @NonNull
+ public LayoutInflater onGetLayoutInflater(@Nullable Bundle savedInstanceState) {
if (!mShowsDialog) {
return super.onGetLayoutInflater(savedInstanceState);
}
@@ -375,7 +376,7 @@
* @return Return a new Dialog instance to be displayed by the Fragment.
*/
@NonNull
- public Dialog onCreateDialog(Bundle savedInstanceState) {
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
return new Dialog(getActivity(), getTheme());
}
@@ -395,7 +396,7 @@
}
@Override
- public void onActivityCreated(Bundle savedInstanceState) {
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (!mShowsDialog) {
@@ -436,7 +437,7 @@
}
@Override
- public void onSaveInstanceState(Bundle outState) {
+ public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
if (mDialog != null) {
Bundle dialogState = mDialog.onSaveInstanceState();
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 9eade40..92abbeb 100644
--- a/fragment/src/main/java/android/support/v4/app/Fragment.java
+++ b/fragment/src/main/java/android/support/v4/app/Fragment.java
@@ -302,7 +302,8 @@
* Thrown by {@link Fragment#instantiate(Context, String, Bundle)} when
* there is an instantiation failure.
*/
- static public class InstantiationException extends RuntimeException {
+ @SuppressWarnings("JavaLangClash")
+ public static class InstantiationException extends RuntimeException {
public InstantiationException(String msg, Exception cause) {
super(msg, cause);
}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 70c7ad6..f05ac0d 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=../../../../tools/external/gradle/gradle-4.5-bin.zip
+distributionUrl=../../../../tools/external/gradle/gradle-4.6-bin.zip
diff --git a/graphics/drawable/animated/build.gradle b/graphics/drawable/animated/build.gradle
index 2f18053..ffaceff 100644
--- a/graphics/drawable/animated/build.gradle
+++ b/graphics/drawable/animated/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/graphics/drawable/animated/lint-baseline.xml b/graphics/drawable/animated/lint-baseline.xml
deleted file mode 100644
index 9fbd83c..0000000
--- a/graphics/drawable/animated/lint-baseline.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-beta6">
-
- <issue
- id="ResourceType"
- message="Expected resource of type anim"
- errorLine1=" parser = resources.getAnimation(id);"
- errorLine2=" ~~">
- <location
- file="src/main/java/android/support/graphics/drawable/AnimatorInflaterCompat.java"
- line="130"
- column="45"/>
- </issue>
-
-</issues>
diff --git a/graphics/drawable/static/build.gradle b/graphics/drawable/static/build.gradle
index 9388480..63282c0 100644
--- a/graphics/drawable/static/build.gradle
+++ b/graphics/drawable/static/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/heifwriter/build.gradle b/heifwriter/build.gradle
index 278521c..c1e1aff 100644
--- a/heifwriter/build.gradle
+++ b/heifwriter/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/interpolator/api/0.0.0.txt b/interpolator/api/0.0.0.txt
new file mode 100644
index 0000000..7de1883
--- /dev/null
+++ b/interpolator/api/0.0.0.txt
@@ -0,0 +1,16 @@
+package android.support.v4.view.animation {
+
+ public class FastOutLinearInInterpolator implements android.view.animation.Interpolator {
+ ctor public FastOutLinearInInterpolator();
+ }
+
+ public class FastOutSlowInInterpolator implements android.view.animation.Interpolator {
+ ctor public FastOutSlowInInterpolator();
+ }
+
+ public class LinearOutSlowInInterpolator implements android.view.animation.Interpolator {
+ ctor public LinearOutSlowInInterpolator();
+ }
+
+}
+
diff --git a/interpolator/build.gradle b/interpolator/build.gradle
index 6bc6e04..49c31e2 100644
--- a/interpolator/build.gradle
+++ b/interpolator/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/jetifier/jetifier/core/build.gradle b/jetifier/jetifier/core/build.gradle
index 683a020..5e4f5c0 100644
--- a/jetifier/jetifier/core/build.gradle
+++ b/jetifier/jetifier/core/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License
*/
-import static android.support.dependencies.DependenciesKt.KOTLIN_STDLIB
+import static androidx.build.dependencies.DependenciesKt.KOTLIN_STDLIB
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportKotlinLibraryPlugin")
diff --git a/jetifier/jetifier/gradle-plugin/build.gradle b/jetifier/jetifier/gradle-plugin/build.gradle
index 4a8d0fb..a2b1cfc 100644
--- a/jetifier/jetifier/gradle-plugin/build.gradle
+++ b/jetifier/jetifier/gradle-plugin/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License
*/
-import static android.support.dependencies.DependenciesKt.KOTLIN_STDLIB
+import static androidx.build.dependencies.DependenciesKt.KOTLIN_STDLIB
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportKotlinLibraryPlugin")
diff --git a/leanback/build.gradle b/leanback/build.gradle
index 36ba9e2..da4b168 100644
--- a/leanback/build.gradle
+++ b/leanback/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/lifecycle/common-java8/build.gradle b/lifecycle/common-java8/build.gradle
index bee8b9c..0f4ffd8 100644
--- a/lifecycle/common-java8/build.gradle
+++ b/lifecycle/common-java8/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions;
-import android.support.SupportLibraryExtension;
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions;
+import androidx.build.SupportLibraryExtension;
plugins {
id("SupportJavaLibraryPlugin")
diff --git a/lifecycle/common/build.gradle b/lifecycle/common/build.gradle
index 866a656..89f46a7 100644
--- a/lifecycle/common/build.gradle
+++ b/lifecycle/common/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions;
-import android.support.SupportLibraryExtension;
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions;
+import androidx.build.SupportLibraryExtension;
plugins {
id("SupportJavaLibraryPlugin")
diff --git a/lifecycle/compiler/build.gradle b/lifecycle/compiler/build.gradle
index 534d1ec..fec3d99 100644
--- a/lifecycle/compiler/build.gradle
+++ b/lifecycle/compiler/build.gradle
@@ -1,8 +1,11 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
-apply plugin: android.support.SupportKotlinLibraryPlugin
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
+
+plugins {
+ id("SupportKotlinLibraryPlugin")
+}
sourceSets {
test.java.srcDirs += 'src/tests/kotlin'
diff --git a/lifecycle/extensions/build.gradle b/lifecycle/extensions/build.gradle
index e8ab2f6..2875ab4 100644
--- a/lifecycle/extensions/build.gradle
+++ b/lifecycle/extensions/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/lifecycle/integration-tests/testapp/build.gradle b/lifecycle/integration-tests/testapp/build.gradle
index 25b5b75..c8fba58 100644
--- a/lifecycle/integration-tests/testapp/build.gradle
+++ b/lifecycle/integration-tests/testapp/build.gradle
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
plugins {
id("SupportAndroidTestAppPlugin")
diff --git a/lifecycle/livedata-core/api/current.txt b/lifecycle/livedata-core/api/current.txt
index 0c855c4..7e1d451 100644
--- a/lifecycle/livedata-core/api/current.txt
+++ b/lifecycle/livedata-core/api/current.txt
@@ -5,12 +5,12 @@
method public T getValue();
method public boolean hasActiveObservers();
method public boolean hasObservers();
- method public void observe(android.arch.lifecycle.LifecycleOwner, android.arch.lifecycle.Observer<T>);
- method public void observeForever(android.arch.lifecycle.Observer<T>);
+ method public void observe(android.arch.lifecycle.LifecycleOwner, android.arch.lifecycle.Observer<? super T>);
+ method public void observeForever(android.arch.lifecycle.Observer<? super T>);
method protected void onActive();
method protected void onInactive();
method protected void postValue(T);
- method public void removeObserver(android.arch.lifecycle.Observer<T>);
+ method public void removeObserver(android.arch.lifecycle.Observer<? super T>);
method public void removeObservers(android.arch.lifecycle.LifecycleOwner);
method protected void setValue(T);
}
diff --git a/lifecycle/livedata-core/build.gradle b/lifecycle/livedata-core/build.gradle
index 58765a0..becb17e 100644
--- a/lifecycle/livedata-core/build.gradle
+++ b/lifecycle/livedata-core/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/lifecycle/livedata-core/src/main/java/android/arch/lifecycle/LiveData.java b/lifecycle/livedata-core/src/main/java/android/arch/lifecycle/LiveData.java
index fc8fb31..b49185a 100644
--- a/lifecycle/livedata-core/src/main/java/android/arch/lifecycle/LiveData.java
+++ b/lifecycle/livedata-core/src/main/java/android/arch/lifecycle/LiveData.java
@@ -61,7 +61,7 @@
static final int START_VERSION = -1;
private static final Object NOT_SET = new Object();
- private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers =
+ private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();
// how many observers are in active state
@@ -121,7 +121,7 @@
considerNotify(initiator);
initiator = null;
} else {
- for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
+ for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
@@ -162,7 +162,7 @@
* @param observer The observer that will receive the events
*/
@MainThread
- public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
+ public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
@@ -195,7 +195,7 @@
* @param observer The observer that will receive the events
*/
@MainThread
- public void observeForever(@NonNull Observer<T> observer) {
+ public void observeForever(@NonNull Observer<? super T> observer) {
assertMainThread("observeForever");
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
@@ -215,7 +215,7 @@
* @param observer The Observer to receive events.
*/
@MainThread
- public void removeObserver(@NonNull final Observer<T> observer) {
+ public void removeObserver(@NonNull final Observer<? super T> observer) {
assertMainThread("removeObserver");
ObserverWrapper removed = mObservers.remove(observer);
if (removed == null) {
@@ -234,7 +234,7 @@
@MainThread
public void removeObservers(@NonNull final LifecycleOwner owner) {
assertMainThread("removeObservers");
- for (Map.Entry<Observer<T>, ObserverWrapper> entry : mObservers) {
+ for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) {
if (entry.getValue().isAttachedTo(owner)) {
removeObserver(entry.getKey());
}
@@ -351,7 +351,7 @@
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull final LifecycleOwner mOwner;
- LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
+ LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@@ -382,11 +382,11 @@
}
private abstract class ObserverWrapper {
- final Observer<T> mObserver;
+ final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
- ObserverWrapper(Observer<T> observer) {
+ ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
@@ -422,7 +422,7 @@
private class AlwaysActiveObserver extends ObserverWrapper {
- AlwaysActiveObserver(Observer<T> observer) {
+ AlwaysActiveObserver(Observer<? super T> observer) {
super(observer);
}
diff --git a/lifecycle/livedata/api/current.txt b/lifecycle/livedata/api/current.txt
index f9783ec..13f8154 100644
--- a/lifecycle/livedata/api/current.txt
+++ b/lifecycle/livedata/api/current.txt
@@ -2,7 +2,7 @@
public class MediatorLiveData<T> extends android.arch.lifecycle.MutableLiveData {
ctor public MediatorLiveData();
- method public <S> void addSource(android.arch.lifecycle.LiveData<S>, android.arch.lifecycle.Observer<S>);
+ method public <S> void addSource(android.arch.lifecycle.LiveData<S>, android.arch.lifecycle.Observer<? super S>);
method public <S> void removeSource(android.arch.lifecycle.LiveData<S>);
}
diff --git a/lifecycle/livedata/build.gradle b/lifecycle/livedata/build.gradle
index 7047886..cf3b50c 100644
--- a/lifecycle/livedata/build.gradle
+++ b/lifecycle/livedata/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/lifecycle/livedata/src/main/java/android/arch/lifecycle/MediatorLiveData.java b/lifecycle/livedata/src/main/java/android/arch/lifecycle/MediatorLiveData.java
index 5864739..3960163 100644
--- a/lifecycle/livedata/src/main/java/android/arch/lifecycle/MediatorLiveData.java
+++ b/lifecycle/livedata/src/main/java/android/arch/lifecycle/MediatorLiveData.java
@@ -82,7 +82,7 @@
* @param <S> The type of data hold by {@code source} LiveData
*/
@MainThread
- public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<S> onChanged) {
+ public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
Source<S> e = new Source<>(source, onChanged);
Source<?> existing = mSources.putIfAbsent(source, e);
if (existing != null && existing.mObserver != onChanged) {
@@ -129,10 +129,10 @@
private static class Source<V> implements Observer<V> {
final LiveData<V> mLiveData;
- final Observer<V> mObserver;
+ final Observer<? super V> mObserver;
int mVersion = START_VERSION;
- Source(LiveData<V> liveData, final Observer<V> observer) {
+ Source(LiveData<V> liveData, final Observer<? super V> observer) {
mLiveData = liveData;
mObserver = observer;
}
diff --git a/lifecycle/reactivestreams/build.gradle b/lifecycle/reactivestreams/build.gradle
index 5c22e4a..12f12b1 100644
--- a/lifecycle/reactivestreams/build.gradle
+++ b/lifecycle/reactivestreams/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/lifecycle/runtime/build.gradle b/lifecycle/runtime/build.gradle
index aee73c0..f7f6ff8 100644
--- a/lifecycle/runtime/build.gradle
+++ b/lifecycle/runtime/build.gradle
@@ -1,7 +1,7 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/lifecycle/viewmodel/build.gradle b/lifecycle/viewmodel/build.gradle
index 914d9ce..1494733 100644
--- a/lifecycle/viewmodel/build.gradle
+++ b/lifecycle/viewmodel/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/loader/api/0.0.0.txt b/loader/api/0.0.0.txt
new file mode 100644
index 0000000..d0027ea
--- /dev/null
+++ b/loader/api/0.0.0.txt
@@ -0,0 +1,98 @@
+package android.support.v4.app {
+
+ public abstract class LoaderManager {
+ ctor public LoaderManager();
+ method public abstract void destroyLoader(int);
+ method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method public static void enableDebugLogging(boolean);
+ method public abstract <D> android.support.v4.content.Loader<D> getLoader(int);
+ method public boolean hasRunningLoaders();
+ method public abstract <D> android.support.v4.content.Loader<D> initLoader(int, android.os.Bundle, android.support.v4.app.LoaderManager.LoaderCallbacks<D>);
+ method public abstract <D> android.support.v4.content.Loader<D> restartLoader(int, android.os.Bundle, android.support.v4.app.LoaderManager.LoaderCallbacks<D>);
+ }
+
+ public static abstract interface LoaderManager.LoaderCallbacks<D> {
+ method public abstract android.support.v4.content.Loader<D> onCreateLoader(int, android.os.Bundle);
+ method public abstract void onLoadFinished(android.support.v4.content.Loader<D>, D);
+ method public abstract void onLoaderReset(android.support.v4.content.Loader<D>);
+ }
+
+}
+
+package android.support.v4.content {
+
+ public abstract class AsyncTaskLoader<D> extends android.support.v4.content.Loader {
+ ctor public AsyncTaskLoader(android.content.Context);
+ method public void cancelLoadInBackground();
+ method public boolean isLoadInBackgroundCanceled();
+ method public abstract D loadInBackground();
+ method public void onCanceled(D);
+ method protected D onLoadInBackground();
+ method public void setUpdateThrottle(long);
+ }
+
+ public class CursorLoader extends android.support.v4.content.AsyncTaskLoader {
+ ctor public CursorLoader(android.content.Context);
+ ctor public CursorLoader(android.content.Context, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+ method public void deliverResult(android.database.Cursor);
+ method public java.lang.String[] getProjection();
+ method public java.lang.String getSelection();
+ method public java.lang.String[] getSelectionArgs();
+ method public java.lang.String getSortOrder();
+ method public android.net.Uri getUri();
+ method public android.database.Cursor loadInBackground();
+ method public void onCanceled(android.database.Cursor);
+ method public void setProjection(java.lang.String[]);
+ method public void setSelection(java.lang.String);
+ method public void setSelectionArgs(java.lang.String[]);
+ method public void setSortOrder(java.lang.String);
+ method public void setUri(android.net.Uri);
+ }
+
+ public class Loader<D> {
+ ctor public Loader(android.content.Context);
+ method public void abandon();
+ method public boolean cancelLoad();
+ method public void commitContentChanged();
+ method public java.lang.String dataToString(D);
+ method public void deliverCancellation();
+ method public void deliverResult(D);
+ method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method public void forceLoad();
+ method public android.content.Context getContext();
+ method public int getId();
+ method public boolean isAbandoned();
+ method public boolean isReset();
+ method public boolean isStarted();
+ method protected void onAbandon();
+ method protected boolean onCancelLoad();
+ method public void onContentChanged();
+ method protected void onForceLoad();
+ method protected void onReset();
+ method protected void onStartLoading();
+ method protected void onStopLoading();
+ method public void registerListener(int, android.support.v4.content.Loader.OnLoadCompleteListener<D>);
+ method public void registerOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
+ method public void reset();
+ method public void rollbackContentChanged();
+ method public final void startLoading();
+ method public void stopLoading();
+ method public boolean takeContentChanged();
+ method public void unregisterListener(android.support.v4.content.Loader.OnLoadCompleteListener<D>);
+ method public void unregisterOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
+ }
+
+ public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
+ ctor public Loader.ForceLoadContentObserver();
+ }
+
+ public static abstract interface Loader.OnLoadCanceledListener<D> {
+ method public abstract void onLoadCanceled(android.support.v4.content.Loader<D>);
+ }
+
+ public static abstract interface Loader.OnLoadCompleteListener<D> {
+ method public abstract void onLoadComplete(android.support.v4.content.Loader<D>, D);
+ }
+
+}
+
diff --git a/loader/build.gradle b/loader/build.gradle
index 45cad2a..b89ac0c 100644
--- a/loader/build.gradle
+++ b/loader/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/localbroadcastmanager/api/0.0.0.txt b/localbroadcastmanager/api/0.0.0.txt
new file mode 100644
index 0000000..5c02abe
--- /dev/null
+++ b/localbroadcastmanager/api/0.0.0.txt
@@ -0,0 +1,12 @@
+package android.support.v4.content {
+
+ public final class LocalBroadcastManager {
+ method public static android.support.v4.content.LocalBroadcastManager getInstance(android.content.Context);
+ method public void registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
+ method public boolean sendBroadcast(android.content.Intent);
+ method public void sendBroadcastSync(android.content.Intent);
+ method public void unregisterReceiver(android.content.BroadcastReceiver);
+ }
+
+}
+
diff --git a/localbroadcastmanager/build.gradle b/localbroadcastmanager/build.gradle
index a3d35bf..2709f7d 100644
--- a/localbroadcastmanager/build.gradle
+++ b/localbroadcastmanager/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/media-compat/build.gradle b/media-compat/build.gradle
index 29c91b7..f952731 100644
--- a/media-compat/build.gradle
+++ b/media-compat/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
@@ -14,7 +14,7 @@
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')
+ androidTestImplementation project(':internal-testutils')
}
android {
diff --git a/media-compat/version-compat-tests/current/client/build.gradle b/media-compat/version-compat-tests/current/client/build.gradle
index 2a247df..385462f 100644
--- a/media-compat/version-compat-tests/current/client/build.gradle
+++ b/media-compat/version-compat-tests/current/client/build.gradle
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/media-compat/version-compat-tests/current/service/build.gradle b/media-compat/version-compat-tests/current/service/build.gradle
index 2a247df..385462f 100644
--- a/media-compat/version-compat-tests/current/service/build.gradle
+++ b/media-compat/version-compat-tests/current/service/build.gradle
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/media-compat/version-compat-tests/lib/build.gradle b/media-compat/version-compat-tests/lib/build.gradle
index caa6c7e..df9e75c 100644
--- a/media-compat/version-compat-tests/lib/build.gradle
+++ b/media-compat/version-compat-tests/lib/build.gradle
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/media-compat/version-compat-tests/previous/client/build.gradle b/media-compat/version-compat-tests/previous/client/build.gradle
index 31f33fe..4319f69 100644
--- a/media-compat/version-compat-tests/previous/client/build.gradle
+++ b/media-compat/version-compat-tests/previous/client/build.gradle
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/media-compat/version-compat-tests/previous/service/build.gradle b/media-compat/version-compat-tests/previous/service/build.gradle
index 765e406..28c88c3 100644
--- a/media-compat/version-compat-tests/previous/service/build.gradle
+++ b/media-compat/version-compat-tests/previous/service/build.gradle
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/paging/common/build.gradle b/paging/common/build.gradle
index dbe6b06..bc1d3a8 100644
--- a/paging/common/build.gradle
+++ b/paging/common/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension;
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension;
plugins {
id("SupportJavaLibraryPlugin")
diff --git a/paging/integration-tests/testapp/build.gradle b/paging/integration-tests/testapp/build.gradle
index d1b0aec..9aab333 100644
--- a/paging/integration-tests/testapp/build.gradle
+++ b/paging/integration-tests/testapp/build.gradle
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
plugins {
diff --git a/paging/runtime/build.gradle b/paging/runtime/build.gradle
index 4c42b30..20a39d4 100644
--- a/paging/runtime/build.gradle
+++ b/paging/runtime/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/percent/build.gradle b/percent/build.gradle
index 9585323..7209ac2 100644
--- a/percent/build.gradle
+++ b/percent/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/persistence/db-framework/build.gradle b/persistence/db-framework/build.gradle
index bae3d02..15f638b 100644
--- a/persistence/db-framework/build.gradle
+++ b/persistence/db-framework/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/persistence/db/build.gradle b/persistence/db/build.gradle
index 657ef1e..5c9cb2d 100644
--- a/persistence/db/build.gradle
+++ b/persistence/db/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/preference-leanback/build.gradle b/preference-leanback/build.gradle
index fc88f28..e5c19da 100644
--- a/preference-leanback/build.gradle
+++ b/preference-leanback/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/print/api/0.0.0.txt b/print/api/0.0.0.txt
new file mode 100644
index 0000000..5277150
--- /dev/null
+++ b/print/api/0.0.0.txt
@@ -0,0 +1,29 @@
+package android.support.v4.print {
+
+ public final class PrintHelper {
+ ctor public PrintHelper(android.content.Context);
+ method public int getColorMode();
+ method public int getOrientation();
+ method public int getScaleMode();
+ method public void printBitmap(java.lang.String, android.graphics.Bitmap);
+ method public void printBitmap(java.lang.String, android.graphics.Bitmap, android.support.v4.print.PrintHelper.OnPrintFinishCallback);
+ method public void printBitmap(java.lang.String, android.net.Uri) throws java.io.FileNotFoundException;
+ method public void printBitmap(java.lang.String, android.net.Uri, android.support.v4.print.PrintHelper.OnPrintFinishCallback) throws java.io.FileNotFoundException;
+ method public void setColorMode(int);
+ method public void setOrientation(int);
+ method public void setScaleMode(int);
+ method public static boolean systemSupportsPrint();
+ field public static final int COLOR_MODE_COLOR = 2; // 0x2
+ field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1
+ field public static final int ORIENTATION_LANDSCAPE = 1; // 0x1
+ field public static final int ORIENTATION_PORTRAIT = 2; // 0x2
+ field public static final int SCALE_MODE_FILL = 2; // 0x2
+ field public static final int SCALE_MODE_FIT = 1; // 0x1
+ }
+
+ public static abstract interface PrintHelper.OnPrintFinishCallback {
+ method public abstract void onFinish();
+ }
+
+}
+
diff --git a/print/build.gradle b/print/build.gradle
index 78fc9db..d3af888 100644
--- a/print/build.gradle
+++ b/print/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/print/src/main/java/android/support/v4/print/PrintHelper.java b/print/src/main/java/android/support/v4/print/PrintHelper.java
index ce342e3..5f445b7 100644
--- a/print/src/main/java/android/support/v4/print/PrintHelper.java
+++ b/print/src/main/java/android/support/v4/print/PrintHelper.java
@@ -39,6 +39,8 @@
import android.print.PrintManager;
import android.print.pdf.PrintedPdfDocument;
import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.Log;
@@ -136,9 +138,11 @@
int getOrientation();
- void printBitmap(String jobName, Bitmap bitmap, OnPrintFinishCallback callback);
+ void printBitmap(@NonNull String jobName, @NonNull Bitmap bitmap,
+ @Nullable OnPrintFinishCallback callback);
- void printBitmap(String jobName, Uri imageFile, OnPrintFinishCallback callback)
+ void printBitmap(@NonNull String jobName, @NonNull Uri imageFile,
+ @Nullable OnPrintFinishCallback callback)
throws FileNotFoundException;
}
@@ -885,7 +889,7 @@
*
* @param context A context for accessing system resources.
*/
- public PrintHelper(Context context) {
+ public PrintHelper(@NonNull Context context) {
if (Build.VERSION.SDK_INT >= 24) {
mImpl = new PrintHelperApi24(context);
} else if (Build.VERSION.SDK_INT >= 23) {
@@ -975,7 +979,7 @@
* @param jobName The print job name.
* @param bitmap The bitmap to print.
*/
- public void printBitmap(String jobName, Bitmap bitmap) {
+ public void printBitmap(@NonNull String jobName, @NonNull Bitmap bitmap) {
mImpl.printBitmap(jobName, bitmap, null);
}
@@ -986,7 +990,8 @@
* @param bitmap The bitmap to print.
* @param callback Optional callback to observe when printing is finished.
*/
- public void printBitmap(String jobName, Bitmap bitmap, OnPrintFinishCallback callback) {
+ public void printBitmap(@NonNull String jobName, @NonNull Bitmap bitmap,
+ @Nullable OnPrintFinishCallback callback) {
mImpl.printBitmap(jobName, bitmap, callback);
}
@@ -999,7 +1004,8 @@
* @param imageFile The <code>Uri</code> pointing to an image to print.
* @throws FileNotFoundException if <code>Uri</code> is not pointing to a valid image.
*/
- public void printBitmap(String jobName, Uri imageFile) throws FileNotFoundException {
+ public void printBitmap(@NonNull String jobName, @NonNull Uri imageFile)
+ throws FileNotFoundException {
mImpl.printBitmap(jobName, imageFile, null);
}
@@ -1013,7 +1019,8 @@
* @throws FileNotFoundException if <code>Uri</code> is not pointing to a valid image.
* @param callback Optional callback to observe when printing is finished.
*/
- public void printBitmap(String jobName, Uri imageFile, OnPrintFinishCallback callback)
+ public void printBitmap(@NonNull String jobName, @NonNull Uri imageFile,
+ @Nullable OnPrintFinishCallback callback)
throws FileNotFoundException {
mImpl.printBitmap(jobName, imageFile, callback);
}
diff --git a/recommendation/build.gradle b/recommendation/build.gradle
index b401eb8..4f4a737 100644
--- a/recommendation/build.gradle
+++ b/recommendation/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/recyclerview-selection/build.gradle b/recyclerview-selection/build.gradle
index 85745d6..94f8a05 100644
--- a/recyclerview-selection/build.gradle
+++ b/recyclerview-selection/build.gradle
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/room/common/build.gradle b/room/common/build.gradle
index 9457308..1bf6652 100644
--- a/room/common/build.gradle
+++ b/room/common/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension;
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension;
plugins {
id("SupportJavaLibraryPlugin")
diff --git a/room/compiler/build.gradle b/room/compiler/build.gradle
index c3319ac..3599893 100644
--- a/room/compiler/build.gradle
+++ b/room/compiler/build.gradle
@@ -15,14 +15,16 @@
*/
-import android.support.SupportConfig
+import androidx.build.SupportConfig
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
-apply plugin: android.support.SupportKotlinLibraryPlugin
+plugins {
+ id("SupportKotlinLibraryPlugin")
+}
def antlrOut = "$buildDir/generated/antlr/grammar-gen/"
sourceSets {
diff --git a/room/guava/build.gradle b/room/guava/build.gradle
index 8660aae..3837406 100644
--- a/room/guava/build.gradle
+++ b/room/guava/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/room/integration-tests/kotlintestapp/build.gradle b/room/integration-tests/kotlintestapp/build.gradle
index 1dc0a79..162f325 100644
--- a/room/integration-tests/kotlintestapp/build.gradle
+++ b/room/integration-tests/kotlintestapp/build.gradle
@@ -17,7 +17,7 @@
//./gradlew :r:in:k:clean :r:in:k:cC --no-daemon
// -Dorg.gradle.debug=true
// -Dkotlin.compiler.execution.strategy="in-process"
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
plugins {
id("SupportAndroidTestAppPlugin")
diff --git a/room/integration-tests/testapp/build.gradle b/room/integration-tests/testapp/build.gradle
index 45ec9c6..401cc07 100644
--- a/room/integration-tests/testapp/build.gradle
+++ b/room/integration-tests/testapp/build.gradle
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
plugins {
id("SupportAndroidTestAppPlugin")
diff --git a/room/migration/build.gradle b/room/migration/build.gradle
index acadb71..2b683e8 100644
--- a/room/migration/build.gradle
+++ b/room/migration/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension;
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension;
plugins {
id("SupportJavaLibraryPlugin")
diff --git a/room/runtime/build.gradle b/room/runtime/build.gradle
index 1022616..739725c 100644
--- a/room/runtime/build.gradle
+++ b/room/runtime/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/room/rxjava2/build.gradle b/room/rxjava2/build.gradle
index d3d7bc9..8dcaa6b 100644
--- a/room/rxjava2/build.gradle
+++ b/room/rxjava2/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/room/testing/build.gradle b/room/testing/build.gradle
index d584b54..48ac8a7 100644
--- a/room/testing/build.gradle
+++ b/room/testing/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/samples/SupportContentDemos/lint-baseline.xml b/samples/SupportContentDemos/lint-baseline.xml
index d25b380..1dfd06e 100644
--- a/samples/SupportContentDemos/lint-baseline.xml
+++ b/samples/SupportContentDemos/lint-baseline.xml
@@ -35,17 +35,6 @@
</issue>
<issue
- id="WrongConstant"
- message="Must be one of: BaseTransientBottomBar.LENGTH_INDEFINITE, BaseTransientBottomBar.LENGTH_SHORT, BaseTransientBottomBar.LENGTH_LONG or value must be ≥ 1 (was 0)"
- errorLine1=" msg, Snackbar.LENGTH_LONG)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/com/example/android/support/content/demos/ContentPagerDemoActivity.java"
- line="143"
- column="22"/>
- </issue>
-
- <issue
id="AllowBackup"
message="On SDK version 23 and up, your app data will be automatically backed up and restored on app install. Consider adding the attribute `android:fullBackupContent` to specify an `@xml` resource which configures which files to backup. More info: https://developer.android.com/training/backup/autosyncapi.html"
errorLine1=" <application"
diff --git a/samples/SupportSliceDemos/build.gradle b/samples/SupportSliceDemos/build.gradle
index a0b236d..4eb590e 100644
--- a/samples/SupportSliceDemos/build.gradle
+++ b/samples/SupportSliceDemos/build.gradle
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
plugins {
id("SupportAndroidTestAppPlugin")
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
index 1df92f9..6230dd0 100644
--- a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
@@ -46,6 +46,8 @@
*/
public class SampleSliceProvider extends SliceProvider {
+ private static final boolean TEST_CUSTOM_SEE_MORE = false;
+
public static final String ACTION_WIFI_CHANGED =
"com.example.androidx.slice.action.WIFI_CHANGED";
public static final String ACTION_TOAST =
@@ -414,18 +416,50 @@
state = ""; // just don't show anything?
break;
}
+
+ // Set the first row as a toggle
boolean finalWifiEnabled = wifiEnabled;
SliceAction primaryAction = new SliceAction(getIntent(Settings.ACTION_WIFI_SETTINGS),
Icon.createWithResource(getContext(), R.drawable.ic_wifi), "Wi-fi Settings");
- return new ListBuilder(getContext(), sliceUri)
+ ListBuilder lb = new ListBuilder(getContext(), sliceUri)
.setColor(0xff4285f4)
.addRow(b -> b
.setTitle("Wi-fi")
.setSubtitle(state)
.addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED, null),
"Toggle wifi", finalWifiEnabled))
- .setPrimaryAction(primaryAction))
- .build();
+ .setPrimaryAction(primaryAction));
+
+ // Add fake wifi networks
+ int[] wifiIcons = new int[] {R.drawable.ic_wifi_full, R.drawable.ic_wifi_low,
+ R.drawable.ic_wifi_fair};
+ for (int i = 0; i < 10; i++) {
+ final int iconId = wifiIcons[i % wifiIcons.length];
+ Icon icon = Icon.createWithResource(getContext(), iconId);
+ final String networkName = "Network" + i;
+ ListBuilder.RowBuilder rb = new ListBuilder.RowBuilder(lb);
+ rb.setTitleItem(icon)
+ .setTitle("Network" + networkName);
+ boolean locked = i % 3 == 0;
+ if (locked) {
+ rb.addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_lock));
+ }
+ String message = locked ? "Open wifi password dialog" : "Connect to " + networkName;
+ rb.setPrimaryAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, message), icon,
+ message));
+ lb.addRow(rb);
+ }
+
+ // Add see more intent
+ if (TEST_CUSTOM_SEE_MORE) {
+ lb.addSeeMoreRow(rb -> rb
+ .setTitle("See all available networks")
+ .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_right_caret))
+ .setPrimaryAction(primaryAction));
+ } else {
+ lb.addSeeMoreAction(primaryAction.getAction());
+ }
+ return lb.build();
}
private Slice createStarRatingInputRange(Uri sliceUri) {
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
index c7751c4..f55bf4b 100644
--- a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
@@ -67,6 +67,7 @@
private static final String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
private static final boolean TEST_INTENT = false;
private static final boolean TEST_THEMES = false;
+ private static final boolean SCROLLING_ENABLED = true;
private ArrayList<Uri> mSliceUris = new ArrayList<Uri>();
private int mSelectedMode;
@@ -289,6 +290,7 @@
if (mSliceLiveData != null) {
mSliceLiveData.removeObservers(this);
}
+ v.setScrollable(SCROLLING_ENABLED);
return v;
}
}
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_lock.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_lock.xml
new file mode 100644
index 0000000..7a79428
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_lock.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ Copyright 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector android:height="16dp" android:viewportHeight="24.0"
+ android:viewportWidth="24.0" android:width="16dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FF000000" android:pathData="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1s3.1,1.39 3.1,3.1v2L8.9,8L8.9,6zM18,20L6,20L6,10h12v10z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_more.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_more.xml
new file mode 100644
index 0000000..a4f9d06
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_more.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_right_caret.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_right_caret.xml
new file mode 100644
index 0000000..3310e62
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_right_caret.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_fair.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_fair.xml
new file mode 100644
index 0000000..4e92a64
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_fair.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ Copyright 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"
+ android:fillAlpha=".3"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M3.53,10.95l8.46,10.54 0.01,0.01 0.01,-0.01 8.46,-10.54C20.04,10.62 16.81,8 12,8c-4.81,0 -8.04,2.62 -8.47,2.95z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_full.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_full.xml
new file mode 100644
index 0000000..0b37310
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_full.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_low.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_low.xml
new file mode 100644
index 0000000..87c84ce
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_low.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ Copyright 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"
+ android:fillAlpha=".3"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M6.67,14.86L12,21.49v0.01l0.01,-0.01 5.33,-6.63C17.06,14.65 15.03,13 12,13s-5.06,1.65 -5.33,1.86z"/>
+</vector>
diff --git a/samples/ViewPager2Demos/OWNERS b/samples/ViewPager2Demos/OWNERS
new file mode 100644
index 0000000..e24ee8b
--- /dev/null
+++ b/samples/ViewPager2Demos/OWNERS
@@ -0,0 +1 @@
+jgielzak@google.com
\ No newline at end of file
diff --git a/samples/ViewPager2Demos/src/main/AndroidManifest.xml b/samples/ViewPager2Demos/src/main/AndroidManifest.xml
index 57e52d3..71d115e 100644
--- a/samples/ViewPager2Demos/src/main/AndroidManifest.xml
+++ b/samples/ViewPager2Demos/src/main/AndroidManifest.xml
@@ -16,7 +16,7 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.androidx.widget.viewpager2">
+ package="com.example.androidx.viewpager2">
<application
android:icon="@drawable/app_sample_code"
@@ -31,6 +31,13 @@
</intent-filter>
</activity>
+ <activity android:name=".CardFragmentActivity" android:label="CardsFragmentDemo">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.SAMPLE_CODE"/>
+ </intent-filter>
+ </activity>
+
<activity android:name=".BrowseActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/BrowseActivity.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/BrowseActivity.java
similarity index 97%
rename from samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/BrowseActivity.java
rename to samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/BrowseActivity.java
index 6c36994..41e4f99 100644
--- a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/BrowseActivity.java
+++ b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/BrowseActivity.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.example.androidx.widget.viewpager2;
+package com.example.androidx.viewpager2;
import android.app.ListActivity;
import android.content.Intent;
@@ -45,7 +45,7 @@
super.onCreate(savedInstanceState);
Intent intent = getIntent();
- String path = intent.getStringExtra("com.example.androidx.widget.viewpager2");
+ String path = intent.getStringExtra("com.example.androidx.viewpager2");
if (path == null) {
path = "";
@@ -131,7 +131,7 @@
protected Intent browseIntent(String path) {
Intent result = new Intent();
result.setClass(this, BrowseActivity.class);
- result.putExtra("com.example.androidx.widget.viewpager2", path);
+ result.putExtra("com.example.androidx.viewpager2", path);
return result;
}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/CardActivity.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/CardActivity.java
new file mode 100644
index 0000000..7c43127
--- /dev/null
+++ b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/CardActivity.java
@@ -0,0 +1,82 @@
+/*
+ * 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 com.example.androidx.viewpager2;
+
+import static java.util.Collections.unmodifiableList;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.RecyclerView;
+import android.view.ViewGroup;
+
+import com.example.androidx.viewpager2.cards.Card;
+import com.example.androidx.viewpager2.cards.CardView;
+
+import java.util.List;
+
+import androidx.viewpager2.widget.ViewPager2;
+
+/**
+ * Shows how to use {@link ViewPager2#setAdapter(RecyclerView.Adapter)}
+ *
+ * @see CardFragmentActivity
+ */
+public class CardActivity extends Activity {
+ private static final List<Card> sCards = unmodifiableList(Card.createDeck52());
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ setContentView(R.layout.activity_card_layout);
+
+ this.<ViewPager2>findViewById(R.id.view_pager).setAdapter(
+ new RecyclerView.Adapter<CardViewHolder>() {
+ @NonNull
+ public CardViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+ int viewType) {
+ return new CardViewHolder(new CardView(getLayoutInflater(), parent));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull CardViewHolder holder, int position) {
+ holder.bind(sCards.get(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ return sCards.size();
+ }
+ });
+ }
+
+ /** @inheritDoc */
+ public static class CardViewHolder extends RecyclerView.ViewHolder {
+ private final CardView mCardView;
+
+ /** {@inheritDoc} */
+ public CardViewHolder(CardView cardView) {
+ super(cardView.getView());
+ mCardView = cardView;
+ }
+
+ /** @see CardView#bind(Card) */
+ public void bind(Card card) {
+ mCardView.bind(card);
+ }
+ }
+}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/CardFragmentActivity.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/CardFragmentActivity.java
new file mode 100644
index 0000000..fe4e538
--- /dev/null
+++ b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/CardFragmentActivity.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.androidx.viewpager2;
+
+import static java.util.Collections.unmodifiableList;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.example.androidx.viewpager2.cards.Card;
+import com.example.androidx.viewpager2.cards.CardView;
+
+import java.util.List;
+
+import androidx.viewpager2.widget.ViewPager2;
+import androidx.viewpager2.widget.ViewPager2.FragmentProvider;
+
+/**
+ * Shows how to use {@link ViewPager2#setAdapter(FragmentManager, FragmentProvider, int)}
+ *
+ * @see CardActivity
+ */
+public class CardFragmentActivity extends FragmentActivity {
+ private static final List<Card> sCards = unmodifiableList(Card.createDeck52());
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ setContentView(R.layout.activity_card_layout);
+
+ this.<ViewPager2>findViewById(R.id.view_pager).setAdapter(getSupportFragmentManager(),
+ new FragmentProvider() {
+ @Override
+ public Fragment getItem(int position) {
+ return CardFragment.create(sCards.get(position));
+ }
+
+ @Override
+ public int getCount() {
+ return sCards.size();
+ }
+ },
+ ViewPager2.FragmentRetentionPolicy.SAVE_STATE);
+ }
+
+ /** {@inheritDoc} */
+ public static class CardFragment extends Fragment {
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ CardView cardView = new CardView(getLayoutInflater(), container);
+ cardView.bind(Card.fromBundle(getArguments()));
+ return cardView.getView();
+ }
+
+ /** Creates a Fragment for a given {@link Card} */
+ public static CardFragment create(Card card) {
+ CardFragment fragment = new CardFragment();
+ fragment.setArguments(card.toBundle());
+ return fragment;
+ }
+ }
+}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/cards/Card.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/cards/Card.java
new file mode 100644
index 0000000..28b8fd1
--- /dev/null
+++ b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/cards/Card.java
@@ -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 com.example.androidx.viewpager2.cards;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.unmodifiableSet;
+
+import android.os.Bundle;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Playing card
+ */
+public class Card {
+ private static final String ARGS_BUNDLE = Card.class.getName() + ":Bundle";
+
+ private static final Set<Character> SUITS = unmodifiableSet(new LinkedHashSet<>(
+ asList('♣' /* clubs*/, '♦' /* diamonds*/, '♥' /* hearts*/, '♠' /*spades*/)));
+ private static final Set<Character> VALUES = unmodifiableSet(new LinkedHashSet<>(
+ asList('2', '3', '4', '5', '6', '7', '8', '9', 'â’‘', 'J', 'Q', 'K', 'A')));
+
+ private final char mSuit;
+ private final char mValue;
+
+ public Card(char suit, char value) {
+ this.mSuit = checkValidValue(suit, SUITS);
+ this.mValue = checkValidValue(value, VALUES);
+ }
+
+ char getSuit() {
+ return mSuit;
+ }
+
+ String getCornerLabel() {
+ return mValue + "\n" + mSuit;
+ }
+
+ /** Use in conjunction with {@link Card#fromBundle(Bundle)} */
+ public Bundle toBundle() {
+ Bundle args = new Bundle(1);
+ args.putCharArray(ARGS_BUNDLE, new char[]{mSuit, mValue});
+ return args;
+ }
+
+ /** Use in conjunction with {@link Card#toBundle()} */
+ public static Card fromBundle(Bundle bundle) {
+ char[] spec = bundle.getCharArray(ARGS_BUNDLE);
+ return new Card(spec[0], spec[1]);
+ }
+
+ private static char checkValidValue(char value, Set<Character> allowed) {
+ if (allowed.contains(value)) {
+ return value;
+ }
+ throw new IllegalArgumentException("Illegal argument: " + value);
+ }
+
+ /**
+ * Creates a deck of all allowed cards
+ */
+ public static List<Card> createDeck52() {
+ List<Card> result = new ArrayList<>(52);
+ for (Character suit : SUITS) {
+ for (Character value : VALUES) {
+ result.add(new Card(suit, value));
+ }
+ }
+ if (result.size() != 52) {
+ throw new IllegalStateException();
+ }
+ return result;
+ }
+}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/cards/CardView.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/cards/CardView.java
new file mode 100644
index 0000000..02b52f8
--- /dev/null
+++ b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/cards/CardView.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.androidx.viewpager2.cards;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.example.androidx.viewpager2.R;
+
+/** Inflates and populates a {@link View} representing a {@link Card} */
+public class CardView {
+ private final View mView;
+ private final TextView mTextSuite;
+ private final TextView mTextCorner1;
+ private final TextView mTextCorner2;
+
+ public CardView(LayoutInflater layoutInflater, ViewGroup container) {
+ mView = layoutInflater.inflate(R.layout.item_card_layout, container, false);
+ mTextSuite = mView.findViewById(R.id.label_center);
+ mTextCorner1 = mView.findViewById(R.id.label_top);
+ mTextCorner2 = mView.findViewById(R.id.label_bottom);
+ }
+
+ /**
+ * Updates the view to represent the passed in card
+ */
+ public void bind(Card card) {
+ mTextSuite.setText(Character.toString(card.getSuit()));
+
+ String cornerLabel = card.getCornerLabel();
+ mTextCorner1.setText(cornerLabel);
+ mTextCorner2.setText(cornerLabel);
+ mTextCorner2.setRotation(180);
+ }
+
+ public View getView() {
+ return mView;
+ }
+}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/CardActivity.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/CardActivity.java
deleted file mode 100644
index 7484389..0000000
--- a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/CardActivity.java
+++ /dev/null
@@ -1,49 +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 com.example.androidx.widget.viewpager2;
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.unmodifiableList;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-import com.example.androidx.widget.viewpager2.cards.Card;
-import com.example.androidx.widget.viewpager2.cards.CardDataAdapter;
-
-import java.util.List;
-
-import androidx.widget.ViewPager2;
-
-/** @inheritDoc */
-public class CardActivity extends Activity {
- private static final List<Card> sCards = unmodifiableList(asList(
- new Card('♦', 'A'),
- new Card('♣', 'K'),
- new Card('♥', 'J'),
- new Card('♠', '9'),
- new Card('♦', '2')));
-
- @Override
- public void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- setContentView(R.layout.activity_card_layout);
-
- this.<ViewPager2>findViewById(R.id.view_pager).setAdapter(
- new CardDataAdapter(getLayoutInflater(), sCards));
- }
-}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/Card.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/Card.java
deleted file mode 100644
index 02f3271..0000000
--- a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/Card.java
+++ /dev/null
@@ -1,56 +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 com.example.androidx.widget.viewpager2.cards;
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.unmodifiableSet;
-
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-/**
- * Playing card
- */
-public class Card {
- private static final Set<Character> SUITS = unmodifiableSet(new LinkedHashSet<>(
- asList('♦', /* diamonds*/ '♣', /*, clubs*/ '♥', /* hearts*/ '♠' /*spades*/)));
- private static final Set<Character> VALUES = unmodifiableSet(new LinkedHashSet<>(
- asList('2', '3', '4', '5', '6', '7', '8', '9', 'â’‘', 'J', 'Q', 'K', 'A')));
-
- private final char mSuit;
- private final char mValue;
-
- public Card(char suit, char value) {
- this.mSuit = checkValidValue(suit, SUITS);
- this.mValue = checkValidValue(value, VALUES);
- }
-
- public char getSuit() {
- return mSuit;
- }
-
- public String getCornerLabel() {
- return mValue + "\n" + mSuit;
- }
-
- private static char checkValidValue(char value, Set<Character> allowed) {
- if (allowed.contains(value)) {
- return value;
- }
- throw new IllegalArgumentException("Illegal argument: " + value);
- }
-}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/CardDataAdapter.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/CardDataAdapter.java
deleted file mode 100644
index 7f69e1b..0000000
--- a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/CardDataAdapter.java
+++ /dev/null
@@ -1,56 +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 com.example.androidx.widget.viewpager2.cards;
-
-import android.support.annotation.NonNull;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-
-import com.example.androidx.widget.viewpager2.R;
-
-import java.util.List;
-
-/** @inheritDoc */
-public class CardDataAdapter extends RecyclerView.Adapter<CardViewHolder> {
- private final List<Card> mCards;
- private final LayoutInflater mLayoutInflater;
-
- public CardDataAdapter(LayoutInflater layoutInflater, List<Card> cards) {
- mLayoutInflater = layoutInflater;
- mCards = cards;
- }
-
- /**
- * @inheritDoc
- */
- @NonNull
- public CardViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- return new CardViewHolder(
- mLayoutInflater.inflate(R.layout.item_card_layout, parent, false));
- }
-
- @Override
- public void onBindViewHolder(@NonNull CardViewHolder holder, int position) {
- holder.apply(mCards.get(position));
- }
-
- @Override
- public int getItemCount() {
- return mCards.size();
- }
-}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/CardViewHolder.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/CardViewHolder.java
deleted file mode 100644
index 8fd0477..0000000
--- a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/CardViewHolder.java
+++ /dev/null
@@ -1,49 +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 com.example.androidx.widget.viewpager2.cards;
-
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-import android.widget.TextView;
-
-import com.example.androidx.widget.viewpager2.R;
-
-/** @inheritDoc */
-public class CardViewHolder extends RecyclerView.ViewHolder {
- private final TextView mTextSuite;
- private final TextView mTextCorner1;
- private final TextView mTextCorner2;
-
- public CardViewHolder(View itemView) {
- super(itemView);
- mTextSuite = itemView.findViewById(R.id.label_center);
- mTextCorner1 = itemView.findViewById(R.id.label_top);
- mTextCorner2 = itemView.findViewById(R.id.label_bottom);
- }
-
- /**
- * Updates the view to represent the passed in card
- */
- public void apply(Card card) {
- mTextSuite.setText(Character.toString(card.getSuit()));
-
- String cornerLabel = card.getCornerLabel();
- mTextCorner1.setText(cornerLabel);
- mTextCorner2.setText(cornerLabel);
- mTextCorner2.setRotation(180);
- }
-}
diff --git a/samples/ViewPager2Demos/src/main/res/layout/activity_card_layout.xml b/samples/ViewPager2Demos/src/main/res/layout/activity_card_layout.xml
index 3037029..9d996ab 100644
--- a/samples/ViewPager2Demos/src/main/res/layout/activity_card_layout.xml
+++ b/samples/ViewPager2Demos/src/main/res/layout/activity_card_layout.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<androidx.widget.ViewPager2
+<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/view_pager"
android:layout_width="match_parent"
diff --git a/samples/ViewPager2Demos/src/main/res/layout/item_card_layout.xml b/samples/ViewPager2Demos/src/main/res/layout/item_card_layout.xml
index 90a0404..1ae9295 100644
--- a/samples/ViewPager2Demos/src/main/res/layout/item_card_layout.xml
+++ b/samples/ViewPager2Demos/src/main/res/layout/item_card_layout.xml
@@ -26,6 +26,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|start"
+ android:gravity="center"
android:textAppearance="@android:style/TextAppearance.Medium"/>
<TextView
@@ -40,5 +41,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
+ android:gravity="center"
android:textAppearance="@android:style/TextAppearance.Medium"/>
</FrameLayout>
diff --git a/settings.gradle b/settings.gradle
index 06b1c32..5e1b188 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -127,7 +127,7 @@
//
/////////////////////////////
-includeProject(":support-testutils", "testutils")
+includeProject(":internal-testutils", "testutils")
/////////////////////////////
//
diff --git a/slices/builders/build.gradle b/slices/builders/build.gradle
index 491617a..4b9a250 100644
--- a/slices/builders/build.gradle
+++ b/slices/builders/build.gradle
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryVersions
-import android.support.LibraryGroups
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryVersions
+import androidx.build.LibraryGroups
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderV1Impl.java b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderV1Impl.java
index 4147dc4..84c7325 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderV1Impl.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderV1Impl.java
@@ -140,7 +140,8 @@
getBuilder().addSubSlice(
new Slice.Builder(getBuilder())
.addHints(HINT_SEE_MORE)
- .addAction(intent, new Slice.Builder(getBuilder()).build(), null)
+ .addAction(intent, new Slice.Builder(getBuilder())
+ .addHints(HINT_SEE_MORE).build(), null)
.build());
}
diff --git a/slices/core/build.gradle b/slices/core/build.gradle
index 8087ab4..f1eed8d 100644
--- a/slices/core/build.gradle
+++ b/slices/core/build.gradle
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/slices/view/api/current.txt b/slices/view/api/current.txt
index af2a1be..43e17d3 100644
--- a/slices/view/api/current.txt
+++ b/slices/view/api/current.txt
@@ -44,6 +44,7 @@
method public void setPosition(int, int, int);
field public static final int ACTION_TYPE_BUTTON = 1; // 0x1
field public static final int ACTION_TYPE_CONTENT = 3; // 0x3
+ field public static final int ACTION_TYPE_SEE_MORE = 4; // 0x4
field public static final int ACTION_TYPE_SLIDER = 2; // 0x2
field public static final int ACTION_TYPE_TOGGLE = 0; // 0x0
field public static final int POSITION_CELL = 2; // 0x2
diff --git a/slices/view/build.gradle b/slices/view/build.gradle
index 0d9d277..acea2c6 100644
--- a/slices/view/build.gradle
+++ b/slices/view/build.gradle
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryVersions
-import android.support.LibraryGroups
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryVersions
+import androidx.build.LibraryGroups
plugins {
id("SupportAndroidLibraryPlugin")
@@ -26,7 +26,7 @@
implementation(project(":slices-core"))
implementation(project(":slices-builders"))
implementation(project(":recyclerview-v7"))
- api(ARCH_LIFECYCLE_EXTENSIONS, libs.exclude_annotations_transitive)
+ api(ARCH_LIFECYCLE_LIVEDATA_CORE, libs.exclude_annotations_transitive)
androidTestImplementation(TEST_RUNNER)
androidTestImplementation(ESPRESSO_CORE)
diff --git a/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java b/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java
index cec5ef4..3c5aa5b 100644
--- a/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java
+++ b/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java
@@ -48,7 +48,7 @@
"com.example.androidx.slice.action.TOAST";
public static final String EXTRA_TOAST_MESSAGE = "com.example.androidx.extra.TOAST_MESSAGE";
- public static final String[] URI_PATHS = {"message", "wifi", "note", "ride", "toggle",
+ public static final String[] URI_PATHS = {"message", "wifi", "wifi2", "note", "ride", "toggle",
"toggle2", "contact", "gallery", "weather"};
private final Context mContext;
@@ -78,7 +78,9 @@
case "/message":
return createMessagingSlice(sliceUri);
case "/wifi":
- return createWifiSlice(sliceUri);
+ return createWifiSlice(sliceUri, false /* customSeeMore */);
+ case "/wifi2":
+ return createWifiSlice(sliceUri, true /* customSeeMore */);
case "/note":
return createNoteSlice(sliceUri);
case "/ride":
@@ -283,7 +285,7 @@
.build();
}
- private Slice createWifiSlice(Uri sliceUri) {
+ private Slice createWifiSlice(Uri sliceUri, boolean customSeeMore) {
// Get wifi state
WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
int wifiState = wifiManager.getWifiState();
@@ -305,18 +307,46 @@
break;
}
boolean finalWifiEnabled = wifiEnabled;
- ListBuilder b = new ListBuilder(getContext(), sliceUri);
+ ListBuilder lb = new ListBuilder(getContext(), sliceUri);
SliceAction primaryAction = new SliceAction(getIntent(Settings.ACTION_WIFI_SETTINGS),
Icon.createWithResource(getContext(), R.drawable.ic_wifi), "Wi-fi Settings");
- return b.setColor(0xff4285f4)
- .addRow(new ListBuilder.RowBuilder(b)
- .setTitle("Wi-fi")
- .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_wifi))
- .setSubtitle(state)
- .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED, null),
- "Toggle wifi", finalWifiEnabled))
- .setPrimaryAction(primaryAction))
- .build();
+ lb.setColor(0xff4285f4);
+ lb.addRow(new ListBuilder.RowBuilder(lb)
+ .setTitle("Wi-fi")
+ .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_wifi))
+ .setSubtitle(state)
+ .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED, null),
+ "Toggle wifi", finalWifiEnabled))
+ .setPrimaryAction(primaryAction));
+
+ // Add fake wifi networks
+ int[] wifiIcons = new int[] {R.drawable.ic_wifi_full, R.drawable.ic_wifi_low,
+ R.drawable.ic_wifi_fair};
+ for (int i = 0; i < 10; i++) {
+ final int iconId = wifiIcons[i % wifiIcons.length];
+ Icon icon = Icon.createWithResource(getContext(), iconId);
+ final String networkName = "Network" + i;
+ ListBuilder.RowBuilder rb = new ListBuilder.RowBuilder(lb);
+ rb.setTitleItem(icon)
+ .setTitle("Network" + networkName);
+ boolean locked = i % 3 == 0;
+ if (locked) {
+ rb.addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_lock));
+ }
+ String message = locked ? "Open wifi password dialog" : "Connect to " + networkName;
+ rb.setPrimaryAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, message), icon,
+ message));
+ lb.addRow(rb);
+ }
+ if (customSeeMore) {
+ lb.addSeeMoreRow(new ListBuilder.RowBuilder(lb)
+ .setTitle("See all available networks")
+ .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_right_caret))
+ .setPrimaryAction(primaryAction));
+ } else {
+ lb.addSeeMoreAction(primaryAction.getAction());
+ }
+ return lb.build();
}
private PendingIntent getIntent(String action) {
diff --git a/slices/view/src/androidTest/java/androidx/slice/render/SliceRenderer.java b/slices/view/src/androidTest/java/androidx/slice/render/SliceRenderer.java
index ca968db..1c33115 100644
--- a/slices/view/src/androidTest/java/androidx/slice/render/SliceRenderer.java
+++ b/slices/view/src/androidTest/java/androidx/slice/render/SliceRenderer.java
@@ -127,7 +127,13 @@
}
mDoneLatch = new CountDownLatch(SliceCreator.URI_PATHS.length);
for (String slice : SliceCreator.URI_PATHS) {
- doRender(slice, new File(output, String.format("%s.png", slice)));
+ doRender(slice, new File(output, String.format("%s.png", slice)),
+ true /* scrollable */);
+ if (slice.equals("wifi") || slice.equals("wifi2")) {
+ // Test scrolling
+ doRender(slice, new File(output, String.format("%s-no-scroll.png", slice)),
+ false /* scrollable */);
+ }
}
Log.d(TAG, "Wrote render to " + output.getAbsolutePath());
mContext.runOnUiThread(new Runnable() {
@@ -142,7 +148,7 @@
}
}
- private void doRender(final String slice, final File file) {
+ private void doRender(final String slice, final File file, final boolean scrollable) {
Log.d(TAG, "Rendering " + slice + " to " + file.getAbsolutePath());
final Slice s = mSliceCreator.onBindSlice(SliceCreator.getUri(slice, mContext));
@@ -154,6 +160,7 @@
mSV1.setSlice(s);
mSV2.setSlice(s);
mSV3.setSlice(s);
+ mSV3.setScrollable(scrollable);
mSV1.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
diff --git a/slices/view/src/androidTest/res/drawable/ic_lock.xml b/slices/view/src/androidTest/res/drawable/ic_lock.xml
new file mode 100644
index 0000000..7a79428
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_lock.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ Copyright 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector android:height="16dp" android:viewportHeight="24.0"
+ android:viewportWidth="24.0" android:width="16dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FF000000" android:pathData="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1s3.1,1.39 3.1,3.1v2L8.9,8L8.9,6zM18,20L6,20L6,10h12v10z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_right_caret.xml b/slices/view/src/androidTest/res/drawable/ic_right_caret.xml
new file mode 100644
index 0000000..3310e62
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_right_caret.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_wifi_fair.xml b/slices/view/src/androidTest/res/drawable/ic_wifi_fair.xml
new file mode 100644
index 0000000..4e92a64
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_wifi_fair.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ Copyright 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"
+ android:fillAlpha=".3"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M3.53,10.95l8.46,10.54 0.01,0.01 0.01,-0.01 8.46,-10.54C20.04,10.62 16.81,8 12,8c-4.81,0 -8.04,2.62 -8.47,2.95z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_wifi_full.xml b/slices/view/src/androidTest/res/drawable/ic_wifi_full.xml
new file mode 100644
index 0000000..0b37310
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_wifi_full.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_wifi_low.xml b/slices/view/src/androidTest/res/drawable/ic_wifi_low.xml
new file mode 100644
index 0000000..87c84ce
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_wifi_low.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ Copyright 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"
+ android:fillAlpha=".3"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M6.67,14.86L12,21.49v0.01l0.01,-0.01 5.33,-6.63C17.06,14.65 15.03,13 12,13s-5.06,1.65 -5.33,1.86z"/>
+</vector>
diff --git a/slices/view/src/main/java/androidx/slice/widget/EventInfo.java b/slices/view/src/main/java/androidx/slice/widget/EventInfo.java
index 35786c0..6cdee12 100644
--- a/slices/view/src/main/java/androidx/slice/widget/EventInfo.java
+++ b/slices/view/src/main/java/androidx/slice/widget/EventInfo.java
@@ -55,7 +55,8 @@
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
- ACTION_TYPE_TOGGLE, ACTION_TYPE_BUTTON, ACTION_TYPE_SLIDER, ACTION_TYPE_CONTENT
+ ACTION_TYPE_TOGGLE, ACTION_TYPE_BUTTON, ACTION_TYPE_SLIDER, ACTION_TYPE_CONTENT,
+ ACTION_TYPE_SEE_MORE
})
public @interface SliceActionType{}
@@ -78,6 +79,10 @@
* Indicates the event was a tap on the entire row.
*/
public static final int ACTION_TYPE_CONTENT = 3;
+ /**
+ * Indicates the event was a tap on a see more button.
+ */
+ public static final int ACTION_TYPE_SEE_MORE = 4;
/**
* @hide
@@ -243,6 +248,8 @@
return "SLIDER";
case ACTION_TYPE_CONTENT:
return "CONTENT";
+ case ACTION_TYPE_SEE_MORE:
+ return "SEE MORE";
default:
return "unknown action: " + action;
}
diff --git a/slices/view/src/main/java/androidx/slice/widget/LargeTemplateView.java b/slices/view/src/main/java/androidx/slice/widget/LargeTemplateView.java
index cde7707..0f26308 100644
--- a/slices/view/src/main/java/androidx/slice/widget/LargeTemplateView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/LargeTemplateView.java
@@ -23,6 +23,7 @@
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
+import java.util.ArrayList;
import java.util.List;
import androidx.slice.Slice;
@@ -40,6 +41,8 @@
private Slice mSlice;
private boolean mIsScrollable;
private ListContent mListContent;
+ private List<SliceItem> mDisplayedItems = new ArrayList<>();
+ private int mDisplayedItemsHeight = 0;
public LargeTemplateView(Context context) {
super(context);
@@ -51,8 +54,18 @@
}
@Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ if (mDisplayedItems.size() > 0 && mDisplayedItemsHeight > height) {
+ // Need to resize
+ updateDisplayedItems(height);
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
public int getActualHeight() {
- return mListContent != null ? mListContent.getListHeight() : 0;
+ return mDisplayedItemsHeight;
}
@Override
@@ -93,23 +106,46 @@
private void populate() {
if (mSlice == null) {
+ resetView();
return;
}
mListContent = new ListContent(getContext(), mSlice);
- mAdapter.setSliceItems(mListContent.getRowItems(), mTintColor);
+ updateDisplayedItems(getMeasuredHeight());
}
/**
* Whether or not the content in this template should be scrollable.
*/
public void setScrollable(boolean isScrollable) {
- // TODO -- restrict / enable how much this view can show
mIsScrollable = isScrollable;
+ updateDisplayedItems(getMeasuredHeight());
+ }
+
+ private void updateDisplayedItems(int height) {
+ if (mListContent == null) {
+ return;
+ }
+ if (!mIsScrollable) {
+ // If we're not scrollable we must cap the number of items we're displaying such
+ // that they fit in the available space
+ if (height == 0) {
+ // Not measured, use default
+ mDisplayedItems = mListContent.getItemsForNonScrollingList(-1);
+ } else {
+ mDisplayedItems = mListContent.getItemsForNonScrollingList(height);
+ }
+ } else {
+ mDisplayedItems = mListContent.getRowItems();
+ }
+ mDisplayedItemsHeight = ListContent.getListHeight(getContext(), mDisplayedItems);
+ mAdapter.setSliceItems(mDisplayedItems, mTintColor);
}
@Override
public void resetView() {
mSlice = null;
+ mDisplayedItemsHeight = 0;
+ mDisplayedItems.clear();
mAdapter.setSliceItems(null, -1);
mListContent = null;
}
diff --git a/slices/view/src/main/java/androidx/slice/widget/ListContent.java b/slices/view/src/main/java/androidx/slice/widget/ListContent.java
index d2915cd..2dd6375 100644
--- a/slices/view/src/main/java/androidx/slice/widget/ListContent.java
+++ b/slices/view/src/main/java/androidx/slice/widget/ListContent.java
@@ -19,6 +19,7 @@
import static android.app.slice.Slice.HINT_ACTIONS;
import static android.app.slice.Slice.HINT_HORIZONTAL;
import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.app.slice.Slice.HINT_SEE_MORE;
import static android.app.slice.Slice.HINT_SHORTCUT;
import static android.app.slice.Slice.SUBTYPE_COLOR;
import static android.app.slice.SliceItem.FORMAT_ACTION;
@@ -48,6 +49,7 @@
private SliceItem mHeaderItem;
private SliceItem mColorItem;
+ private SliceItem mSeeMoreItem;
private ArrayList<SliceItem> mRowItems = new ArrayList<>();
private List<SliceItem> mSliceActions;
private Context mContext;
@@ -79,12 +81,13 @@
if (mHeaderItem != null) {
mRowItems.add(mHeaderItem);
}
+ mSeeMoreItem = getSeeMoreItem(slice);
// Filter + create row items
List<SliceItem> children = slice.getItems();
for (int i = 0; i < children.size(); i++) {
final SliceItem child = children.get(i);
final String format = child.getFormat();
- if (!child.hasAnyHints(HINT_ACTIONS)
+ if (!child.hasAnyHints(HINT_ACTIONS, HINT_SEE_MORE)
&& (FORMAT_ACTION.equals(format) || FORMAT_SLICE.equals(format))) {
if (mHeaderItem == null && !child.hasHint(HINT_LIST_ITEM)) {
mHeaderItem = child;
@@ -102,24 +105,70 @@
}
/**
- * @return the total height of all the rows contained in this list.
+ * @return the total height of all the rows contained in the provided list.
*/
- public int getListHeight() {
+ public static int getListHeight(Context context, List<SliceItem> listItems) {
int height = 0;
- for (int i = 0; i < mRowItems.size(); i++) {
- SliceItem item = mRowItems.get(i);
- if (item.hasHint(HINT_HORIZONTAL)) {
- GridContent gc = new GridContent(mContext, item);
- height += gc.getActualHeight();
- } else {
- RowContent rc = new RowContent(mContext, item, i == 0 /* isHeader */);
- height += rc.getActualHeight();
- }
+ for (int i = 0; i < listItems.size(); i++) {
+ height += getHeight(context, listItems.get(i), i == 0 /* isHeader */);
}
return height;
}
/**
+ * Returns a list of items that can be displayed in the provided height. If this list
+ * has a {@link #getSeeMoreItem()} this will be returned in the list if appropriate.
+ *
+ * @param height the height to restrict the items, -1 to use default sizings for non-scrolling
+ * templates.
+ * @return the list of items that can be displayed in the provided height.
+ */
+ @NonNull
+ public List<SliceItem> getItemsForNonScrollingList(int height) {
+ ArrayList<SliceItem> visibleItems = new ArrayList<>();
+ if (mRowItems == null || mRowItems.size() == 0) {
+ return visibleItems;
+ }
+ final int idealItemCount = hasHeader() ? 4 : 3;
+ final int minItemCount = hasHeader() ? 2 : 1;
+ int visibleHeight = 0;
+ // Need to show see more
+ if (mSeeMoreItem != null) {
+ RowContent rc = new RowContent(mContext, mSeeMoreItem, false /* isHeader */);
+ visibleHeight += rc.getActualHeight();
+ }
+ for (int i = 0; i < mRowItems.size(); i++) {
+ int itemHeight = getHeight(mContext, mRowItems.get(i), i == 0 /* isHeader */);
+ if ((height == -1 && i > idealItemCount)
+ || (height > 0 && visibleHeight + itemHeight > height)) {
+ break;
+ } else {
+ visibleHeight += itemHeight;
+ visibleItems.add(mRowItems.get(i));
+ }
+ }
+ if (mSeeMoreItem != null && visibleItems.size() >= minItemCount) {
+ // Only add see more if we're at least showing one item and it's not the header
+ visibleItems.add(mSeeMoreItem);
+ }
+ if (visibleItems.size() == 0) {
+ // Didn't have enough space to show anything; should still show something
+ visibleItems.add(mRowItems.get(0));
+ }
+ return visibleItems;
+ }
+
+ private static int getHeight(Context context, SliceItem item, boolean isHeader) {
+ if (item.hasHint(HINT_HORIZONTAL)) {
+ GridContent gc = new GridContent(context, item);
+ return gc.getActualHeight();
+ } else {
+ RowContent rc = new RowContent(context, item, isHeader);
+ return rc.getActualHeight();
+ }
+ }
+
+ /**
* @return whether this list has content that is valid to display.
*/
public boolean isValid() {
@@ -141,6 +190,11 @@
return mSliceActions;
}
+ @Nullable
+ public SliceItem getSeeMoreItem() {
+ return mSeeMoreItem;
+ }
+
public ArrayList<SliceItem> getRowItems() {
return mRowItems;
}
@@ -163,6 +217,21 @@
return null;
}
+ @Nullable
+ private static SliceItem getSeeMoreItem(@NonNull Slice slice) {
+ SliceItem item = SliceQuery.find(slice, null, HINT_SEE_MORE, null);
+ if (item != null && item.hasHint(HINT_SEE_MORE)) {
+ if (FORMAT_SLICE.equals(item.getFormat())) {
+ List<SliceItem> items = item.getSlice().getItems();
+ if (items.size() == 1 && FORMAT_ACTION.equals(items.get(0).getFormat())) {
+ return items.get(0);
+ }
+ return item;
+ }
+ }
+ return null;
+ }
+
private static boolean isValidHeader(SliceItem sliceItem) {
if (FORMAT_SLICE.equals(sliceItem.getFormat()) && !sliceItem.hasHint(HINT_LIST_ITEM)
&& !sliceItem.hasHint(HINT_ACTIONS)) {
diff --git a/slices/view/src/main/java/androidx/slice/widget/RowContent.java b/slices/view/src/main/java/androidx/slice/widget/RowContent.java
index cec8ddb..083101c 100644
--- a/slices/view/src/main/java/androidx/slice/widget/RowContent.java
+++ b/slices/view/src/main/java/androidx/slice/widget/RowContent.java
@@ -17,6 +17,7 @@
package androidx.slice.widget;
import static android.app.slice.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_SEE_MORE;
import static android.app.slice.Slice.HINT_SHORTCUT;
import static android.app.slice.Slice.HINT_SUMMARY;
import static android.app.slice.Slice.HINT_TITLE;
@@ -31,6 +32,7 @@
import static androidx.slice.core.SliceHints.SUBTYPE_RANGE;
import android.content.Context;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.text.TextUtils;
@@ -52,6 +54,7 @@
private static final String TAG = "RowContent";
private SliceItem mPrimaryAction;
+ private SliceItem mRowSlice;
private SliceItem mStartItem;
private SliceItem mTitleItem;
private SliceItem mSubtitleItem;
@@ -75,6 +78,7 @@
*/
public void reset() {
mPrimaryAction = null;
+ mRowSlice = null;
mStartItem = null;
mTitleItem = null;
mSubtitleItem = null;
@@ -89,6 +93,7 @@
private boolean populate(SliceItem rowSlice, boolean isHeader) {
reset();
mIsHeader = isHeader;
+ mRowSlice = rowSlice;
if (!isValidRow(rowSlice)) {
Log.w(TAG, "Provided SliceItem is invalid for RowContent");
return false;
@@ -173,6 +178,14 @@
}
/**
+ * @return the {@link SliceItem} used to populate this row.
+ */
+ @NonNull
+ public SliceItem getSlice() {
+ return mRowSlice;
+ }
+
+ /**
* @return the {@link SliceItem} representing the range in the row; can be null.
*/
@Nullable
@@ -181,30 +194,32 @@
}
/**
- * @return whether this row has content that is valid to display.
+ * @return the {@link SliceItem} used for the main intent for this row; can be null.
*/
- public boolean isValid() {
- return mStartItem != null
- || mTitleItem != null
- || mSubtitleItem != null
- || mEndItems.size() > 0;
- }
-
@Nullable
public SliceItem getPrimaryAction() {
return mPrimaryAction;
}
+ /**
+ * @return the {@link SliceItem} to display at the start of this row; can be null.
+ */
@Nullable
public SliceItem getStartItem() {
return mIsHeader ? null : mStartItem;
}
+ /**
+ * @return the {@link SliceItem} representing the title text for this row; can be null.
+ */
@Nullable
public SliceItem getTitleItem() {
return mTitleItem;
}
+ /**
+ * @return the {@link SliceItem} representing the subtitle text for this row; can be null.
+ */
@Nullable
public SliceItem getSubtitleItem() {
return mSubtitleItem;
@@ -215,6 +230,9 @@
return mSummaryItem == null ? mSubtitleItem : mSummaryItem;
}
+ /**
+ * @return the list of {@link SliceItem} that can be shown as items at the end of the row.
+ */
public ArrayList<SliceItem> getEndItems() {
return mEndItems;
}
@@ -254,6 +272,26 @@
}
/**
+ * @return whether this row content represents a default see more item.
+ */
+ public boolean isDefaultSeeMore() {
+ return FORMAT_ACTION.equals(mRowSlice.getFormat())
+ && mRowSlice.getSlice().hasHint(HINT_SEE_MORE)
+ && mRowSlice.getSlice().getItems().isEmpty();
+ }
+
+ /**
+ * @return whether this row has content that is valid to display.
+ */
+ public boolean isValid() {
+ return mStartItem != null
+ || mTitleItem != null
+ || mSubtitleItem != null
+ || mEndItems.size() > 0
+ || isDefaultSeeMore();
+ }
+
+ /**
* @return whether this is a valid item to use to populate a row of content.
*/
private static boolean isValidRow(SliceItem rowSlice) {
@@ -270,10 +308,18 @@
return true;
}
}
+ // Special case: default see more just has an action but no other items
+ if (rowSlice.hasHint(HINT_SEE_MORE) && rowItems.isEmpty()) {
+ return true;
+ }
}
return false;
}
+ /**
+ * @return list of {@link SliceItem}s that are valid to display in a row according
+ * to {@link #isValidRowContent(SliceItem, SliceItem)}.
+ */
private static ArrayList<SliceItem> filterInvalidItems(SliceItem rowSlice) {
ArrayList<SliceItem> filteredList = new ArrayList<>();
for (SliceItem i : rowSlice.getSlice().getItems()) {
diff --git a/slices/view/src/main/java/androidx/slice/widget/RowView.java b/slices/view/src/main/java/androidx/slice/widget/RowView.java
index 1aca2fa..8bc93bd 100644
--- a/slices/view/src/main/java/androidx/slice/widget/RowView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/RowView.java
@@ -41,8 +41,10 @@
import android.support.annotation.RestrictTo;
import android.util.Log;
import android.util.TypedValue;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -84,6 +86,7 @@
private LinearLayout mEndContainer;
private SeekBar mSeekBar;
private ProgressBar mProgressBar;
+ private View mSeeMoreView;
private int mRowIndex;
private RowContent mRowContent;
@@ -175,6 +178,11 @@
private void populateViews() {
resetView();
+ if (mRowContent.isDefaultSeeMore()) {
+ showSeeMore();
+ return;
+ }
+
boolean showStart = false;
final SliceItem startItem = mRowContent.getStartItem();
if (startItem != null) {
@@ -456,6 +464,31 @@
return addedView != null;
}
+ private void showSeeMore() {
+ Button b = (Button) LayoutInflater.from(getContext()).inflate(
+ R.layout.abc_slice_row_show_more, this, false);
+ b.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ try {
+ if (mObserver != null) {
+ EventInfo info = new EventInfo(getMode(), EventInfo.ACTION_TYPE_SEE_MORE,
+ EventInfo.ROW_TYPE_LIST, mRowIndex);
+ mObserver.onSliceAction(info, mRowContent.getSlice());
+ }
+ mRowContent.getSlice().getAction().send();
+ } catch (CanceledException e) {
+ Log.w(TAG, "PendingIntent for slice cannot be sent", e);
+ }
+ }
+ });
+ if (mTintColor != -1) {
+ b.setTextColor(mTintColor);
+ }
+ mSeeMoreView = b;
+ addView(mSeeMoreView);
+ }
+
@Override
public void onClick(View view) {
if (mRowAction != null && mRowAction.getActionItem() != null && !mRowAction.isToggle()) {
@@ -496,5 +529,8 @@
mDivider.setVisibility(View.GONE);
mSeekBar.setVisibility(View.GONE);
mProgressBar.setVisibility(View.GONE);
+ if (mSeeMoreView != null) {
+ removeView(mSeeMoreView);
+ }
}
}
diff --git a/slices/view/src/main/java/androidx/slice/widget/SliceView.java b/slices/view/src/main/java/androidx/slice/widget/SliceView.java
index 4a53b9d..df786b3 100644
--- a/slices/view/src/main/java/androidx/slice/widget/SliceView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/SliceView.java
@@ -192,16 +192,17 @@
final int heightAvailable = MeasureSpec.getSize(heightMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int height = heightAvailable;
- if (heightAvailable >= sliceHeight) {
- // Available space is larger than the slice
- if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
- height = sliceHeight;
+ if (heightAvailable >= sliceHeight || heightMode == MeasureSpec.UNSPECIFIED) {
+ // Available space is larger than the slice or we be what we want
+ if (heightMode != MeasureSpec.EXACTLY) {
+ int maxHeight = mIsScrollable ? mMinLargeHeight + actionHeight : sliceHeight;
+ height = Math.min(maxHeight, sliceHeight);
}
} else {
// Not enough space available for slice in current mode
if (getMode() == MODE_LARGE && heightAvailable >= mMinLargeHeight + actionHeight) {
// It's just a slice with scrolling content; cap it to height available.
- height = heightAvailable;
+ height = Math.min(mMinLargeHeight + actionHeight, heightAvailable);
} else if (getMode() == MODE_SHORTCUT) {
// TODO: consider scaling the shortcut to fit if too small
height = mShortcutSize;
diff --git a/slices/view/src/main/res/layout/abc_slice_row_show_more.xml b/slices/view/src/main/res/layout/abc_slice_row_show_more.xml
new file mode 100644
index 0000000..ef65f85
--- /dev/null
+++ b/slices/view/src/main/res/layout/abc_slice_row_show_more.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ style="?android:attr/borderlessButtonStyle"
+ android:text="@string/abc_slice_show_more"/>
\ No newline at end of file
diff --git a/slices/view/src/main/res/values/strings.xml b/slices/view/src/main/res/values/strings.xml
index b72c986..f73c6cc 100644
--- a/slices/view/src/main/res/values/strings.xml
+++ b/slices/view/src/main/res/values/strings.xml
@@ -18,4 +18,6 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Format string for indicating there is more content in a slice view -->
<string name="abc_slice_more_content">+ <xliff:g id="number" example="5">%1$d</xliff:g></string>
+ <!-- String to indicate there is more content to display in a list [CHAR LIMIT=none] -->
+ <string name="abc_slice_show_more">Show more</string>
</resources>
\ No newline at end of file
diff --git a/slidingpanelayout/api/0.0.0.txt b/slidingpanelayout/api/0.0.0.txt
new file mode 100644
index 0000000..07e71d9
--- /dev/null
+++ b/slidingpanelayout/api/0.0.0.txt
@@ -0,0 +1,54 @@
+package android.support.v4.widget {
+
+ public class SlidingPaneLayout extends android.view.ViewGroup {
+ ctor public SlidingPaneLayout(android.content.Context);
+ ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet);
+ ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet, int);
+ method protected boolean canScroll(android.view.View, boolean, int, int, int);
+ method public deprecated boolean canSlide();
+ method public boolean closePane();
+ method public int getCoveredFadeColor();
+ method public int getParallaxDistance();
+ method public int getSliderFadeColor();
+ method public boolean isOpen();
+ method public boolean isSlideable();
+ method public boolean openPane();
+ method public void setCoveredFadeColor(int);
+ method public void setPanelSlideListener(android.support.v4.widget.SlidingPaneLayout.PanelSlideListener);
+ method public void setParallaxDistance(int);
+ method public deprecated void setShadowDrawable(android.graphics.drawable.Drawable);
+ method public void setShadowDrawableLeft(android.graphics.drawable.Drawable);
+ method public void setShadowDrawableRight(android.graphics.drawable.Drawable);
+ method public deprecated void setShadowResource(int);
+ method public void setShadowResourceLeft(int);
+ method public void setShadowResourceRight(int);
+ method public void setSliderFadeColor(int);
+ method public deprecated void smoothSlideClosed();
+ method public deprecated void smoothSlideOpen();
+ }
+
+ public static class SlidingPaneLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public SlidingPaneLayout.LayoutParams();
+ ctor public SlidingPaneLayout.LayoutParams(int, int);
+ ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public SlidingPaneLayout.LayoutParams(android.support.v4.widget.SlidingPaneLayout.LayoutParams);
+ ctor public SlidingPaneLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+ field public float weight;
+ }
+
+ public static abstract interface SlidingPaneLayout.PanelSlideListener {
+ method public abstract void onPanelClosed(android.view.View);
+ method public abstract void onPanelOpened(android.view.View);
+ method public abstract void onPanelSlide(android.view.View, float);
+ }
+
+ public static class SlidingPaneLayout.SimplePanelSlideListener implements android.support.v4.widget.SlidingPaneLayout.PanelSlideListener {
+ ctor public SlidingPaneLayout.SimplePanelSlideListener();
+ method public void onPanelClosed(android.view.View);
+ method public void onPanelOpened(android.view.View);
+ method public void onPanelSlide(android.view.View, float);
+ }
+
+}
+
diff --git a/slidingpanelayout/build.gradle b/slidingpanelayout/build.gradle
index d084e63..4e24b3f 100644
--- a/slidingpanelayout/build.gradle
+++ b/slidingpanelayout/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/swiperefreshlayout/api/0.0.0.txt b/swiperefreshlayout/api/0.0.0.txt
new file mode 100644
index 0000000..ce68f0b
--- /dev/null
+++ b/swiperefreshlayout/api/0.0.0.txt
@@ -0,0 +1,76 @@
+package android.support.v4.widget {
+
+ 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();
+ method public float getArrowHeight();
+ method public float getArrowScale();
+ method public float getArrowWidth();
+ method public int getBackgroundColor();
+ method public float getCenterRadius();
+ method public int[] getColorSchemeColors();
+ method public float getEndTrim();
+ method public int getOpacity();
+ method public float getProgressRotation();
+ method public float getStartTrim();
+ method public android.graphics.Paint.Cap getStrokeCap();
+ method public float getStrokeWidth();
+ method public boolean isRunning();
+ method public void setAlpha(int);
+ method public void setArrowDimensions(float, float);
+ method public void setArrowEnabled(boolean);
+ method public void setArrowScale(float);
+ method public void setBackgroundColor(int);
+ method public void setCenterRadius(float);
+ method public void setColorFilter(android.graphics.ColorFilter);
+ method public void setColorSchemeColors(int...);
+ method public void setProgressRotation(float);
+ method public void setStartEndTrim(float, float);
+ method public void setStrokeCap(android.graphics.Paint.Cap);
+ method public void setStrokeWidth(float);
+ method public void setStyle(int);
+ method public void start();
+ method public void stop();
+ field public static final int DEFAULT = 1; // 0x1
+ field public static final int LARGE = 0; // 0x0
+ }
+
+ 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();
+ method public int getProgressCircleDiameter();
+ method public int getProgressViewEndOffset();
+ method public int getProgressViewStartOffset();
+ method public boolean isRefreshing();
+ method public void onMeasure(int, int);
+ method public deprecated void setColorScheme(int...);
+ method public void setColorSchemeColors(int...);
+ method public void setColorSchemeResources(int...);
+ method public void setDistanceToTriggerSync(int);
+ method public void setOnChildScrollUpCallback(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback);
+ method public void setOnRefreshListener(android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener);
+ method public deprecated void setProgressBackgroundColor(int);
+ method public void setProgressBackgroundColorSchemeColor(int);
+ method public void setProgressBackgroundColorSchemeResource(int);
+ method public void setProgressViewEndTarget(boolean, int);
+ method public void setProgressViewOffset(boolean, int, int);
+ method public void setRefreshing(boolean);
+ method public void setSize(int);
+ field public static final int DEFAULT = 1; // 0x1
+ field public static final int LARGE = 0; // 0x0
+ field protected int mFrom;
+ field protected int mOriginalOffsetTop;
+ }
+
+ public static abstract interface SwipeRefreshLayout.OnChildScrollUpCallback {
+ method public abstract boolean canChildScrollUp(android.support.v4.widget.SwipeRefreshLayout, android.view.View);
+ }
+
+ public static abstract interface SwipeRefreshLayout.OnRefreshListener {
+ method public abstract void onRefresh();
+ }
+
+}
+
diff --git a/swiperefreshlayout/build.gradle b/swiperefreshlayout/build.gradle
index 0479bbe..6654e94 100644
--- a/swiperefreshlayout/build.gradle
+++ b/swiperefreshlayout/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
@@ -18,7 +18,7 @@
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'), {
+ androidTestImplementation project(':internal-testutils'), {
exclude group: 'com.android.support', module: 'swiperefreshlayout'
}
}
diff --git a/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutTest.java b/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
index fe53293..96c2dac 100644
--- a/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
+++ b/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
@@ -39,7 +39,6 @@
import android.support.test.filters.SmallTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
import android.view.View;
import org.junit.Before;
@@ -50,6 +49,8 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import androidx.testutils.PollingCheck;
+
/**
* Tests SwipeRefreshLayout widget.
*/
diff --git a/testutils/build.gradle b/testutils/build.gradle
index d75b6b7..d32244f 100644
--- a/testutils/build.gradle
+++ b/testutils/build.gradle
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/testutils/src/main/AndroidManifest.xml b/testutils/src/main/AndroidManifest.xml
index 4d2fd19..2feb440 100644
--- a/testutils/src/main/AndroidManifest.xml
+++ b/testutils/src/main/AndroidManifest.xml
@@ -14,4 +14,4 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<manifest package="android.support.testutils"/>
+<manifest package="androidx.testutils"/>
diff --git a/testutils/src/main/java/android/support/testutils/AppCompatActivityUtils.java b/testutils/src/main/java/androidx/testutils/AppCompatActivityUtils.java
similarity index 98%
rename from testutils/src/main/java/android/support/testutils/AppCompatActivityUtils.java
rename to testutils/src/main/java/androidx/testutils/AppCompatActivityUtils.java
index 49ccc1b..e36a2ec 100644
--- a/testutils/src/main/java/android/support/testutils/AppCompatActivityUtils.java
+++ b/testutils/src/main/java/androidx/testutils/AppCompatActivityUtils.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.support.testutils;
+package androidx.testutils;
import static org.junit.Assert.assertTrue;
diff --git a/testutils/src/main/java/android/support/testutils/FragmentActivityUtils.java b/testutils/src/main/java/androidx/testutils/FragmentActivityUtils.java
similarity index 98%
rename from testutils/src/main/java/android/support/testutils/FragmentActivityUtils.java
rename to testutils/src/main/java/androidx/testutils/FragmentActivityUtils.java
index 7d12deb..a4b67e7 100644
--- a/testutils/src/main/java/android/support/testutils/FragmentActivityUtils.java
+++ b/testutils/src/main/java/androidx/testutils/FragmentActivityUtils.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.support.testutils;
+package androidx.testutils;
import static org.junit.Assert.assertTrue;
diff --git a/testutils/src/main/java/android/support/testutils/PollingCheck.java b/testutils/src/main/java/androidx/testutils/PollingCheck.java
similarity index 98%
rename from testutils/src/main/java/android/support/testutils/PollingCheck.java
rename to testutils/src/main/java/androidx/testutils/PollingCheck.java
index 8e85896..8fd4852 100644
--- a/testutils/src/main/java/android/support/testutils/PollingCheck.java
+++ b/testutils/src/main/java/androidx/testutils/PollingCheck.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.testutils;
+package androidx.testutils;
import org.junit.Assert;
diff --git a/testutils/src/main/java/android/support/testutils/RecreatedActivity.java b/testutils/src/main/java/androidx/testutils/RecreatedActivity.java
similarity index 97%
rename from testutils/src/main/java/android/support/testutils/RecreatedActivity.java
rename to testutils/src/main/java/androidx/testutils/RecreatedActivity.java
index aaea3a9..8430dca 100644
--- a/testutils/src/main/java/android/support/testutils/RecreatedActivity.java
+++ b/testutils/src/main/java/androidx/testutils/RecreatedActivity.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.testutils;
+package androidx.testutils;
import android.os.Bundle;
import android.support.annotation.Nullable;
diff --git a/testutils/src/main/java/android/support/testutils/RecreatedAppCompatActivity.java b/testutils/src/main/java/androidx/testutils/RecreatedAppCompatActivity.java
similarity index 97%
rename from testutils/src/main/java/android/support/testutils/RecreatedAppCompatActivity.java
rename to testutils/src/main/java/androidx/testutils/RecreatedAppCompatActivity.java
index d5645a3..1a48cf8 100644
--- a/testutils/src/main/java/android/support/testutils/RecreatedAppCompatActivity.java
+++ b/testutils/src/main/java/androidx/testutils/RecreatedAppCompatActivity.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.testutils;
+package androidx.testutils;
import android.os.Bundle;
import android.support.annotation.Nullable;
diff --git a/textclassifier/build.gradle b/textclassifier/build.gradle
index b01cbbf..a6e57de 100644
--- a/textclassifier/build.gradle
+++ b/textclassifier/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/transition/build.gradle b/transition/build.gradle
index d8257ab..c413a73 100644
--- a/transition/build.gradle
+++ b/transition/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/transition/proguard-rules.pro b/transition/proguard-rules.pro
index 6cae5e6..dda2c4e 100644
--- a/transition/proguard-rules.pro
+++ b/transition/proguard-rules.pro
@@ -12,10 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# FragmentTransitionSupport is instantiated in support-fragment via reflection.
--keep public class android.support.transition.FragmentTransitionSupport {
-}
-
# Keep a field in transition that is used to keep a reference to weakly-referenced object
-keepclassmembers class android.support.transition.ChangeBounds$* extends android.animation.AnimatorListenerAdapter {
android.support.transition.ChangeBounds$ViewBounds mViewBounds;
diff --git a/tv-provider/api/current.txt b/tv-provider/api/current.txt
index c486190..ee11d8f 100644
--- a/tv-provider/api/current.txt
+++ b/tv-provider/api/current.txt
@@ -77,10 +77,68 @@
method public static boolean storeChannelLogo(android.content.Context, long, android.graphics.Bitmap);
}
+ public class PreviewChannel {
+ method public static android.support.media.tv.PreviewChannel fromCursor(android.database.Cursor);
+ method public android.content.Intent getAppLinkIntent() throws java.net.URISyntaxException;
+ method public android.net.Uri getAppLinkIntentUri();
+ method public java.lang.CharSequence getDescription();
+ method public java.lang.CharSequence getDisplayName();
+ method public long getId();
+ method public byte[] getInternalProviderDataByteArray();
+ method public java.lang.Long getInternalProviderFlag1();
+ method public java.lang.Long getInternalProviderFlag2();
+ method public java.lang.Long getInternalProviderFlag3();
+ method public java.lang.Long getInternalProviderFlag4();
+ method public java.lang.String getInternalProviderId();
+ method public android.graphics.Bitmap getLogo(android.content.Context);
+ method public java.lang.String getPackageName();
+ method public java.lang.String getType();
+ method public boolean hasAnyUpdatedValues(android.support.media.tv.PreviewChannel);
+ method public boolean isBrowsable();
+ }
+
+ public static final class PreviewChannel.Builder {
+ ctor public PreviewChannel.Builder();
+ ctor public PreviewChannel.Builder(android.support.media.tv.PreviewChannel);
+ method public android.support.media.tv.PreviewChannel build();
+ method public android.support.media.tv.PreviewChannel.Builder setAppLinkIntent(android.content.Intent);
+ method public android.support.media.tv.PreviewChannel.Builder setAppLinkIntentUri(android.net.Uri);
+ method public android.support.media.tv.PreviewChannel.Builder setDescription(java.lang.CharSequence);
+ method public android.support.media.tv.PreviewChannel.Builder setDisplayName(java.lang.CharSequence);
+ method public android.support.media.tv.PreviewChannel.Builder setInternalProviderData(byte[]);
+ method public android.support.media.tv.PreviewChannel.Builder setInternalProviderFlag1(long);
+ method public android.support.media.tv.PreviewChannel.Builder setInternalProviderFlag2(long);
+ method public android.support.media.tv.PreviewChannel.Builder setInternalProviderFlag3(long);
+ method public android.support.media.tv.PreviewChannel.Builder setInternalProviderFlag4(long);
+ method public android.support.media.tv.PreviewChannel.Builder setInternalProviderId(java.lang.String);
+ method public android.support.media.tv.PreviewChannel.Builder setLogo(android.graphics.Bitmap);
+ method public android.support.media.tv.PreviewChannel.Builder setLogo(android.net.Uri);
+ }
+
+ public class PreviewChannelHelper {
+ ctor public PreviewChannelHelper(android.content.Context);
+ ctor public PreviewChannelHelper(android.content.Context, int, int);
+ method public void deletePreviewChannel(long);
+ method public void deletePreviewProgram(long);
+ method protected android.graphics.Bitmap downloadBitmap(android.net.Uri) throws java.io.IOException;
+ method public java.util.List<android.support.media.tv.PreviewChannel> getAllChannels();
+ method public android.support.media.tv.PreviewChannel getPreviewChannel(long);
+ method public android.support.media.tv.PreviewProgram getPreviewProgram(long);
+ method public android.support.media.tv.WatchNextProgram getWatchNextProgram(long);
+ method public long publishChannel(android.support.media.tv.PreviewChannel) throws java.io.IOException;
+ method public long publishDefaultChannel(android.support.media.tv.PreviewChannel) throws java.io.IOException;
+ method public long publishPreviewProgram(android.support.media.tv.PreviewProgram);
+ method public long publishWatchNextProgram(android.support.media.tv.WatchNextProgram);
+ method public void updatePreviewChannel(long, android.support.media.tv.PreviewChannel) throws java.io.IOException;
+ method public void updatePreviewProgram(long, android.support.media.tv.PreviewProgram);
+ method public void updateWatchNextProgram(android.support.media.tv.WatchNextProgram, long);
+ }
+
public final class PreviewProgram {
method public static android.support.media.tv.PreviewProgram fromCursor(android.database.Cursor);
method public long getChannelId();
method public int getWeight();
+ method public boolean hasAnyUpdatedValues(android.support.media.tv.PreviewProgram);
method public android.content.ContentValues toContentValues();
}
@@ -529,6 +587,7 @@
method public static android.support.media.tv.WatchNextProgram fromCursor(android.database.Cursor);
method public long getLastEngagementTimeUtcMillis();
method public int getWatchNextType();
+ method public boolean hasAnyUpdatedValues(android.support.media.tv.WatchNextProgram);
method public android.content.ContentValues toContentValues();
field public static final int WATCH_NEXT_TYPE_UNKNOWN = -1; // 0xffffffff
}
diff --git a/tv-provider/build.gradle b/tv-provider/build.gradle
index a8057c0..eb8cbd5 100644
--- a/tv-provider/build.gradle
+++ b/tv-provider/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
@@ -12,6 +12,7 @@
androidTestImplementation(TEST_RUNNER)
androidTestImplementation(TEST_RULES)
+ androidTestImplementation(MOCKITO_CORE)
}
supportLibrary {
diff --git a/tv-provider/src/androidTest/java/android/support/media/tv/PreviewChannelHelperTest.java b/tv-provider/src/androidTest/java/android/support/media/tv/PreviewChannelHelperTest.java
new file mode 100644
index 0000000..679e0ee
--- /dev/null
+++ b/tv-provider/src/androidTest/java/android/support/media/tv/PreviewChannelHelperTest.java
@@ -0,0 +1,612 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.media.tv;
+
+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.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.tv.TvContentRating;
+import android.net.Uri;
+import android.os.Build;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Test that {@link PreviewChannelHelper} can perform CRUD operations on
+ * {@link PreviewChannel PreviewChannels} and {@link PreviewProgram PreviewPrograms} correctly.
+ * All of the following tests involve the system content provider.
+ */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@RunWith(JUnit4.class)
+public class PreviewChannelHelperTest {
+
+
+ private Context mContext;
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ /**
+ * taken from {@link PreviewProgram}
+ */
+ private static PreviewProgram.Builder createFullyPopulatedPreviewProgram(long channelId) {
+ return new PreviewProgram.Builder()
+ .setTitle("Google")
+ .setInternalProviderId("ID-4321")
+ .setChannelId(channelId)
+ .setWeight(100)
+ .setPreviewVideoUri(Uri.parse("http://example.com/preview-video.mpg"))
+ .setLastPlaybackPositionMillis(0)
+ .setDurationMillis(60 * 1000)
+ .setIntentUri(Uri.parse(new Intent(Intent.ACTION_VIEW).toUri(
+ Intent.URI_INTENT_SCHEME)))
+ .setTransient(false)
+ .setType(TvContractCompat.PreviewPrograms.TYPE_MOVIE)
+ .setPosterArtAspectRatio(TvContractCompat.PreviewPrograms.ASPECT_RATIO_2_3)
+ .setThumbnailAspectRatio(TvContractCompat.PreviewPrograms.ASPECT_RATIO_16_9)
+ .setLogoUri(Uri.parse("http://example.com/program-logo.mpg"))
+ .setAvailability(TvContractCompat.PreviewPrograms.AVAILABILITY_AVAILABLE)
+ .setStartingPrice("12.99 USD")
+ .setOfferPrice("4.99 USD")
+ .setReleaseDate("1997")
+ .setItemCount(3)
+ .setLive(false)
+ .setInteractionType(TvContractCompat.PreviewPrograms.INTERACTION_TYPE_LIKES)
+ .setInteractionCount(10200)
+ .setAuthor("author_name")
+ .setReviewRatingStyle(TvContractCompat.PreviewPrograms.REVIEW_RATING_STYLE_STARS)
+ .setReviewRating("4.5")
+ .setSearchable(false)
+ .setThumbnailUri(Uri.parse("http://example.com/thumbnail.png"))
+ .setAudioLanguages(new String[]{"eng", "kor"})
+ .setCanonicalGenres(new String[]{TvContractCompat.Programs.Genres.MOVIES})
+ .setContentRatings(new TvContentRating[]{
+ TvContentRating.createRating("com.android.tv", "US_TV", "US_TV_Y7")})
+ .setDescription("This is a sample program")
+ .setEpisodeNumber("Pilot", 0)
+ .setEpisodeTitle("Hello World")
+ .setLongDescription("This is a longer description than the previous description")
+ .setPosterArtUri(Uri.parse("http://example.com/poster.png"))
+ .setSeasonNumber("The Final Season", 7)
+ .setSeasonTitle("The Final Season")
+ .setVideoHeight(1080)
+ .setVideoWidth(1920)
+ .setInternalProviderFlag1(0x4)
+ .setInternalProviderFlag2(0x3)
+ .setInternalProviderFlag3(0x2)
+ .setInternalProviderFlag4(0x1)
+ .setBrowsable(true)
+ .setContentId("CID-8642");
+ }
+
+ private static void compareProgram(PreviewProgram programA, PreviewProgram programB) {
+ assertTrue(Arrays.equals(programA.getAudioLanguages(), programB.getAudioLanguages()));
+ assertTrue(Arrays.deepEquals(programA.getCanonicalGenres(), programB.getCanonicalGenres()));
+ assertEquals(programA.getChannelId(), programB.getChannelId());
+ assertTrue(Arrays.deepEquals(programA.getContentRatings(), programB.getContentRatings()));
+ assertEquals(programA.getDescription(), programB.getDescription());
+ assertEquals(programA.getEpisodeNumber(), programB.getEpisodeNumber());
+ assertEquals(programA.getEpisodeTitle(), programB.getEpisodeTitle());
+ assertEquals(programA.getLongDescription(), programB.getLongDescription());
+ assertEquals(programA.getPosterArtUri(), programB.getPosterArtUri());
+ assertEquals(programA.getSeasonNumber(), programB.getSeasonNumber());
+ assertEquals(programA.getThumbnailUri(), programB.getThumbnailUri());
+ assertEquals(programA.getTitle(), programB.getTitle());
+ assertEquals(programA.getVideoHeight(), programB.getVideoHeight());
+ assertEquals(programA.getVideoWidth(), programB.getVideoWidth());
+ assertEquals(programA.isSearchable(), programB.isSearchable());
+ assertEquals(programA.getInternalProviderFlag1(), programB.getInternalProviderFlag1());
+ assertEquals(programA.getInternalProviderFlag2(), programB.getInternalProviderFlag2());
+ assertEquals(programA.getInternalProviderFlag3(), programB.getInternalProviderFlag3());
+ assertEquals(programA.getInternalProviderFlag4(), programB.getInternalProviderFlag4());
+ assertTrue(Objects.equals(programA.getSeasonTitle(), programB.getSeasonTitle()));
+ assertEquals(programA.getInternalProviderId(), programB.getInternalProviderId());
+ assertEquals(programA.getPreviewVideoUri(), programB.getPreviewVideoUri());
+ assertEquals(programA.getLastPlaybackPositionMillis(),
+ programB.getLastPlaybackPositionMillis());
+ assertEquals(programA.getDurationMillis(), programB.getDurationMillis());
+ assertEquals(programA.getIntentUri(), programB.getIntentUri());
+ assertEquals(programA.getWeight(), programB.getWeight());
+ assertEquals(programA.isTransient(), programB.isTransient());
+ assertEquals(programA.getType(), programB.getType());
+ assertEquals(programA.getPosterArtAspectRatio(), programB.getPosterArtAspectRatio());
+ assertEquals(programA.getThumbnailAspectRatio(), programB.getThumbnailAspectRatio());
+ assertEquals(programA.getLogoUri(), programB.getLogoUri());
+ assertEquals(programA.getAvailability(), programB.getAvailability());
+ assertEquals(programA.getStartingPrice(), programB.getStartingPrice());
+ assertEquals(programA.getOfferPrice(), programB.getOfferPrice());
+ assertEquals(programA.getReleaseDate(), programB.getReleaseDate());
+ assertEquals(programA.getItemCount(), programB.getItemCount());
+ assertEquals(programA.isLive(), programB.isLive());
+ assertEquals(programA.getInteractionType(), programB.getInteractionType());
+ assertEquals(programA.getInteractionCount(), programB.getInteractionCount());
+ assertEquals(programA.getAuthor(), programB.getAuthor());
+ assertEquals(programA.getReviewRatingStyle(), programB.getReviewRatingStyle());
+ assertEquals(programA.getReviewRating(), programB.getReviewRating());
+ assertEquals(programA.getContentId(), programB.getContentId());
+ }
+
+ private static WatchNextProgram.Builder createFullyPopulatedWatchNextProgram() {
+ return new WatchNextProgram.Builder()
+ .setTitle("Google")
+ .setInternalProviderId("ID-4321")
+ .setPreviewVideoUri(Uri.parse("http://example.com/preview-video.mpg"))
+ .setLastPlaybackPositionMillis(0)
+ .setDurationMillis(60 * 1000)
+ .setIntentUri(Uri.parse(new Intent(Intent.ACTION_VIEW).toUri(
+ Intent.URI_INTENT_SCHEME)))
+ .setTransient(false)
+ .setType(TvContractCompat.WatchNextPrograms.TYPE_MOVIE)
+ .setWatchNextType(TvContractCompat.WatchNextPrograms.WATCH_NEXT_TYPE_CONTINUE)
+ .setPosterArtAspectRatio(TvContractCompat.WatchNextPrograms.ASPECT_RATIO_2_3)
+ .setThumbnailAspectRatio(TvContractCompat.WatchNextPrograms.ASPECT_RATIO_16_9)
+ .setLogoUri(Uri.parse("http://example.com/program-logo.mpg"))
+ .setAvailability(TvContractCompat.WatchNextPrograms.AVAILABILITY_AVAILABLE)
+ .setStartingPrice("12.99 USD")
+ .setOfferPrice("4.99 USD")
+ .setReleaseDate("1997")
+ .setItemCount(3)
+ .setLive(false)
+ .setInteractionType(TvContractCompat.WatchNextPrograms.INTERACTION_TYPE_LIKES)
+ .setInteractionCount(10200)
+ .setAuthor("author_name")
+ .setReviewRatingStyle(TvContractCompat.WatchNextPrograms.REVIEW_RATING_STYLE_STARS)
+ .setReviewRating("4.5")
+ .setSearchable(false)
+ .setThumbnailUri(Uri.parse("http://example.com/thumbnail.png"))
+ .setAudioLanguages(new String[]{"eng", "kor"})
+ .setCanonicalGenres(new String[]{TvContractCompat.Programs.Genres.MOVIES})
+ .setContentRatings(new TvContentRating[]{
+ TvContentRating.createRating("com.android.tv", "US_TV", "US_TV_Y7")})
+ .setDescription("This is a sample program")
+ .setEpisodeNumber("Pilot", 0)
+ .setEpisodeTitle("Hello World")
+ .setLongDescription("This is a longer description than the previous description")
+ .setPosterArtUri(Uri.parse("http://example.com/poster.png"))
+ .setSeasonNumber("The Final Season", 7)
+ .setSeasonTitle("The Final Season")
+ .setVideoHeight(1080)
+ .setVideoWidth(1920)
+ .setInternalProviderFlag1(0x4)
+ .setInternalProviderFlag2(0x3)
+ .setInternalProviderFlag3(0x2)
+ .setInternalProviderFlag4(0x1)
+ .setBrowsable(true)
+ .setContentId("CID-8442");
+ }
+
+ private static void compareProgram(WatchNextProgram programA, WatchNextProgram programB) {
+ assertTrue(Arrays.equals(programA.getAudioLanguages(), programB.getAudioLanguages()));
+ assertTrue(Arrays.deepEquals(programA.getCanonicalGenres(), programB.getCanonicalGenres()));
+ assertTrue(Arrays.deepEquals(programA.getContentRatings(), programB.getContentRatings()));
+ assertEquals(programA.getDescription(), programB.getDescription());
+ assertEquals(programA.getEpisodeNumber(), programB.getEpisodeNumber());
+ assertEquals(programA.getEpisodeTitle(), programB.getEpisodeTitle());
+ assertEquals(programA.getLongDescription(), programB.getLongDescription());
+ assertEquals(programA.getPosterArtUri(), programB.getPosterArtUri());
+ assertEquals(programA.getSeasonNumber(), programB.getSeasonNumber());
+ assertEquals(programA.getThumbnailUri(), programB.getThumbnailUri());
+ assertEquals(programA.getTitle(), programB.getTitle());
+ assertEquals(programA.getVideoHeight(), programB.getVideoHeight());
+ assertEquals(programA.getVideoWidth(), programB.getVideoWidth());
+ assertEquals(programA.isSearchable(), programB.isSearchable());
+ assertEquals(programA.getInternalProviderFlag1(), programB.getInternalProviderFlag1());
+ assertEquals(programA.getInternalProviderFlag2(), programB.getInternalProviderFlag2());
+ assertEquals(programA.getInternalProviderFlag3(), programB.getInternalProviderFlag3());
+ assertEquals(programA.getInternalProviderFlag4(), programB.getInternalProviderFlag4());
+ assertTrue(Objects.equals(programA.getSeasonTitle(), programB.getSeasonTitle()));
+ assertEquals(programA.getInternalProviderId(), programB.getInternalProviderId());
+ assertEquals(programA.getPreviewVideoUri(), programB.getPreviewVideoUri());
+ assertEquals(programA.getLastPlaybackPositionMillis(),
+ programB.getLastPlaybackPositionMillis());
+ assertEquals(programA.getDurationMillis(), programB.getDurationMillis());
+ assertEquals(programA.getIntentUri(), programB.getIntentUri());
+ assertEquals(programA.isTransient(), programB.isTransient());
+ assertEquals(programA.getType(), programB.getType());
+ assertEquals(programA.getWatchNextType(), programB.getWatchNextType());
+ assertEquals(programA.getPosterArtAspectRatio(), programB.getPosterArtAspectRatio());
+ assertEquals(programA.getThumbnailAspectRatio(), programB.getThumbnailAspectRatio());
+ assertEquals(programA.getLogoUri(), programB.getLogoUri());
+ assertEquals(programA.getAvailability(), programB.getAvailability());
+ assertEquals(programA.getStartingPrice(), programB.getStartingPrice());
+ assertEquals(programA.getOfferPrice(), programB.getOfferPrice());
+ assertEquals(programA.getReleaseDate(), programB.getReleaseDate());
+ assertEquals(programA.getItemCount(), programB.getItemCount());
+ assertEquals(programA.isLive(), programB.isLive());
+ assertEquals(programA.getInteractionType(), programB.getInteractionType());
+ assertEquals(programA.getInteractionCount(), programB.getInteractionCount());
+ assertEquals(programA.getAuthor(), programB.getAuthor());
+ assertEquals(programA.getReviewRatingStyle(), programB.getReviewRatingStyle());
+ assertEquals(programA.getReviewRating(), programB.getReviewRating());
+ assertEquals(programA.getContentId(), programB.getContentId());
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+
+ }
+
+ @After
+ public void tearDown() {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ mContext.getContentResolver().delete(
+ TvContractCompat.Channels.CONTENT_URI, null, null);
+ mContext = null;
+ }
+
+ /**
+ * Test CR of CRUD
+ * Test that the PreviewChannelHelper can correctly create and read preview channels.
+ */
+ @Test
+ public void testPreviewChannelCreation() throws IOException {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+ PreviewChannel.Builder builder = createFullyPopulatedPreviewChannel();
+ long channelId = helper.publishDefaultChannel(builder.build());
+ PreviewChannel channelFromTvProvider = getPreviewChannel(helper, channelId);
+ assertTrue(channelsEqual(builder.build(), channelFromTvProvider));
+ }
+
+ @Test
+ public void testLogoRequiredForChannelCreation() throws IOException {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+ PreviewChannel.Builder builder = createFullyPopulatedPreviewChannel();
+ builder.setLogo(Uri.parse("bogus"));
+ thrown.expect(IOException.class);
+ helper.publishDefaultChannel(builder.build());
+ List<PreviewChannel> channels = helper.getAllChannels();
+ assertEquals(0, channels.size());
+ }
+
+ /**
+ * Test CR of CRUD
+ * Test that the PreviewChannelHelper can correctly create and read preview channels, when
+ * internalProviderId is null.
+ */
+ @Test
+ public void testPreviewChannelCreationWithNullProviderId() throws IOException {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ PreviewChannel.Builder builder = createFullyPopulatedPreviewChannel();
+ builder.setInternalProviderId(null);
+ PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+ long channelId = helper.publishChannel(builder.build());
+ PreviewChannel channelFromTvProvider = getPreviewChannel(helper, channelId);
+ assertTrue(channelsEqual(builder.build(), channelFromTvProvider));
+ }
+
+ /**
+ * All this method is actually doing is
+ * <pre>
+ *
+ * PreviewChannel channelFromTvProvider = helper.getPreviewChannel(channelId);
+ * </pre>
+ * However, due to a known issue, when logo is persisted, the file status is not consistent
+ * between openInputStream and openOutputStream. So as a workaround, a wait period is applied
+ * to make sure that the logo file is written into the disk.
+ */
+ private PreviewChannel getPreviewChannel(PreviewChannelHelper helper,
+ long channelId) {
+ boolean logoReady = false;
+ PreviewChannel channel = null;
+ while (!logoReady) {
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ }
+ channel = helper.getPreviewChannel(channelId);
+ logoReady = null != channel.getLogo(mContext);
+ }
+ return channel;
+ }
+
+ /**
+ * Test CR of CRUD
+ * Test that all published preview channels can be read at once.
+ */
+ @Test
+ public void testAllPublishedChannelsRead() throws IOException {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+ PreviewChannel.Builder builder = createFullyPopulatedPreviewChannel();
+ builder.setInternalProviderId("1");
+ helper.publishChannel(builder.build());
+ builder.setInternalProviderId("11");
+ helper.publishChannel(builder.build());
+ builder.setInternalProviderId("111");
+ helper.publishChannel(builder.build());
+ builder.setInternalProviderId("1111");
+ helper.publishChannel(builder.build());
+ List<PreviewChannel> allChannels = helper.getAllChannels();
+ assertEquals(4, allChannels.size());
+ }
+
+ /**
+ * Test UR of CRUD
+ * Test that the PreviewChannelHelper can correctly update and read preview channels.
+ */
+ @Test
+ public void testPreviewChannelUpdate() throws IOException {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+ PreviewChannel.Builder builder = createFullyPopulatedPreviewChannel();
+ long channelId = helper.publishChannel(builder.build());
+ PreviewChannel channelFromTvProvider = getPreviewChannel(helper, channelId);
+ PreviewChannel channel = builder.build();
+ assertTrue(channelsEqual(channel, channelFromTvProvider));
+
+ PreviewChannel patch = new PreviewChannel.Builder()
+ .setDisplayName(channel.getDisplayName())
+ .setAppLinkIntentUri(channel.getAppLinkIntentUri())
+ .setDescription("Patch description").build();
+ helper.updatePreviewChannel(channelId, patch);
+ channelFromTvProvider = helper.getPreviewChannel(channelId);
+ assertFalse(channelsEqual(channel, channelFromTvProvider));
+ assertEquals(channelFromTvProvider.getDescription(), "Patch description");
+ }
+
+ /**
+ * Tests that data is not being updated unnecessarily
+ */
+ @Test
+ public void testDefensiveUpdatePreviewChannel() throws IOException {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ final int[] channelUpdateCount = {0};
+ PreviewChannelHelper helper = new PreviewChannelHelper(mContext) {
+ @Override
+ protected void updatePreviewChannelInternal(long channelId, PreviewChannel channel) {
+ channelUpdateCount[0]++;
+ }
+ };
+ PreviewChannel.Builder builder = createFullyPopulatedPreviewChannel();
+ long channelId = helper.publishChannel(builder.build());
+ PreviewChannel fromProvider = helper.getPreviewChannel(channelId);
+ channelsEqual(builder.build(), fromProvider);
+ helper.updatePreviewChannel(channelId, builder.build());
+ assertEquals(0, channelUpdateCount[0]);
+
+ final Uri uri = Uri.parse(new Intent(Intent.ACTION_VIEW).toUri(Intent.URI_INTENT_SCHEME));
+ PreviewChannel channel = new PreviewChannel.Builder()
+ .setDisplayName("Test Display Name Udpate")
+ .setDescription("Test Preview Channel Description")
+ .setAppLinkIntentUri(uri).build();
+
+ helper.updatePreviewChannel(channelId, channel);
+ assertEquals(1, channelUpdateCount[0]);
+ }
+
+ @Test
+ public void testPreviewResolverChannelDeletion() throws IOException {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+ PreviewChannel.Builder builder = createFullyPopulatedPreviewChannel();
+ long channelId = helper.publishChannel(builder.build());
+ PreviewChannel channelFromTvProvider = getPreviewChannel(helper, channelId);
+ assertTrue(channelsEqual(builder.build(), channelFromTvProvider));
+
+ helper.deletePreviewChannel(channelId);
+ channelFromTvProvider = helper.getPreviewChannel(channelId);
+ assertNull(channelFromTvProvider);
+ }
+
+ @Test
+ public void testPreviewProgramCreation() throws IOException {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+ PreviewChannel.Builder channelBuilder = createFullyPopulatedPreviewChannel();
+ long channelId = helper.publishChannel(channelBuilder.build());
+ PreviewProgram program = createFullyPopulatedPreviewProgram(channelId).build();
+ long programId = helper.publishPreviewProgram(program);
+ PreviewProgram programFromProvider = helper.getPreviewProgram(programId);
+ compareProgram(program, programFromProvider);
+ }
+
+ @Test
+ public void testPreviewProgramUpdate() throws IOException {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+ PreviewChannel.Builder channelBuilder = createFullyPopulatedPreviewChannel();
+ long channelId = helper.publishChannel(channelBuilder.build());
+ PreviewProgram.Builder programBuilder = createFullyPopulatedPreviewProgram(channelId);
+ long programId = helper.publishPreviewProgram(programBuilder.build());
+
+ programBuilder.setReleaseDate("2000");
+
+ helper.updatePreviewProgram(programId, programBuilder.build());
+ PreviewProgram programFromProvider = helper.getPreviewProgram(programId);
+ compareProgram(programBuilder.build(), programFromProvider);
+ }
+
+ /**
+ * Tests that data is not being updated unnecessarily
+ */
+ @Test
+ public void testDefensivePreviewProgramUpdateRequests() throws IOException {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ final int[] programUpdateCount = {0};
+ PreviewChannelHelper helper = new PreviewChannelHelper(mContext) {
+
+ @Override
+ public void updatePreviewProgramInternal(long programId, PreviewProgram upgrade) {
+ programUpdateCount[0]++;
+ }
+ };
+ PreviewChannel.Builder channelBuilder = createFullyPopulatedPreviewChannel();
+ long channelId = helper.publishChannel(channelBuilder.build());
+ PreviewProgram.Builder programBuilder = createFullyPopulatedPreviewProgram(channelId);
+ long programId = helper.publishPreviewProgram(programBuilder.build());
+ PreviewProgram programFromProvider = helper.getPreviewProgram(programId);
+ compareProgram(programBuilder.build(), programFromProvider);
+ helper.updatePreviewProgram(programId, programBuilder.build());
+ assertEquals(0, programUpdateCount[0]);
+ programBuilder.setDurationMillis(61 * 1000);
+ helper.updatePreviewProgram(programId, programBuilder.build());
+ assertEquals(1, programUpdateCount[0]);
+ }
+
+ @Test
+ public void testDeletePreviewProgram() throws IOException {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+ PreviewChannel.Builder channelBuilder = createFullyPopulatedPreviewChannel();
+ long channelId = helper.publishChannel(channelBuilder.build());
+ PreviewProgram.Builder programBuilder = createFullyPopulatedPreviewProgram(channelId);
+ long programId = helper.publishPreviewProgram(programBuilder.build());
+
+ helper.deletePreviewProgram(programId);
+ PreviewProgram programFromProvider = helper.getPreviewProgram(programId);
+ assertNull(programFromProvider);
+ }
+
+ @Test
+ public void testWatchNextProgramCreation() {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+ WatchNextProgram program = createFullyPopulatedWatchNextProgram().build();
+ long programId = helper.publishWatchNextProgram(program);
+ WatchNextProgram programFromProvider = helper.getWatchNextProgram(programId);
+ compareProgram(program, programFromProvider);
+ }
+
+ @Test
+ public void testUpdateWatchNextProgram() {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+ WatchNextProgram.Builder builder = createFullyPopulatedWatchNextProgram();
+ long programId = helper.publishWatchNextProgram(builder.build());
+ builder.setOfferPrice("10.99 USD");
+ helper.updateWatchNextProgram(builder.build(), programId);
+
+ WatchNextProgram fromProvider = helper.getWatchNextProgram(programId);
+ compareProgram(builder.build(), fromProvider);
+ }
+
+ /**
+ * Tests that data is not being updated unnecessarily
+ */
+ @Test
+ public void testDefensiveUpdateWatchNextProgram() {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ final int[] programUpdateCount = {0};
+ PreviewChannelHelper helper = new PreviewChannelHelper(mContext) {
+ @Override
+ protected void updateWatchNextProgram(long programId, WatchNextProgram upgrade) {
+ programUpdateCount[0]++;
+ }
+ };
+ WatchNextProgram.Builder builder = createFullyPopulatedWatchNextProgram();
+ long programId = helper.publishWatchNextProgram(builder.build());
+ WatchNextProgram fromProvider = helper.getWatchNextProgram(programId);
+ compareProgram(builder.build(), fromProvider);
+ helper.updateWatchNextProgram(builder.build(), programId);
+ assertEquals(0, programUpdateCount[0]);
+ builder.setReleaseDate("2000");
+ helper.updateWatchNextProgram(builder.build(), programId);
+ assertEquals(1, programUpdateCount[0]);
+ }
+
+ private boolean channelsEqual(PreviewChannel channelA, PreviewChannel channelB) {
+ boolean result = channelA.getDisplayName().equals(channelB.getDisplayName())
+ && channelA.getType().equals(channelB.getType())
+ && channelA.getAppLinkIntentUri().equals(channelB.getAppLinkIntentUri())
+ && channelA.getDescription().equals(channelB.getDescription())
+ && channelA.getPackageName().equals(channelB.getPackageName())
+ && channelA.getInternalProviderFlag1() == channelB.getInternalProviderFlag1()
+ && channelA.getInternalProviderFlag2() == channelB.getInternalProviderFlag2()
+ && channelA.getInternalProviderFlag3() == channelB.getInternalProviderFlag3()
+ && channelA.getInternalProviderFlag4() == channelB.getInternalProviderFlag4()
+ && (channelA.getInternalProviderId() == null
+ && channelB.getInternalProviderId() == null
+ || channelA.getInternalProviderId().equals(channelB.getInternalProviderId()))
+ && (null != channelA.getLogo(mContext) && null != channelB.getLogo(
+ mContext))
+ && Arrays.equals(channelA.getInternalProviderDataByteArray(),
+ channelB.getInternalProviderDataByteArray());
+ return result;
+ }
+
+ public PreviewChannel.Builder createFullyPopulatedPreviewChannel() {
+ Bitmap logo = BitmapFactory.decodeResource(mContext.getResources(),
+ android.support.media.tv.test.R.drawable.test_icon);
+ assertNotNull(logo);
+ return new PreviewChannel.Builder()
+ .setAppLinkIntent(new Intent())
+ .setDescription("Test Preview Channel Description")
+ .setDisplayName("Test Display Name")
+ .setPackageName("android.support.media.tv.test")
+ .setInternalProviderFlag1(0x1)
+ .setInternalProviderFlag2(0x2)
+ .setInternalProviderFlag3(0x3)
+ .setInternalProviderFlag4(0x4)
+ .setInternalProviderId("Test Internal provider id")
+ .setInternalProviderData("Test byte array".getBytes())
+ .setLogo(logo);
+ }
+}
diff --git a/tv-provider/src/androidTest/java/android/support/media/tv/PreviewChannelTest.java b/tv-provider/src/androidTest/java/android/support/media/tv/PreviewChannelTest.java
new file mode 100644
index 0000000..ef5e22e
--- /dev/null
+++ b/tv-provider/src/androidTest/java/android/support/media/tv/PreviewChannelTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.media.tv;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.MatrixCursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Build;
+import android.support.media.tv.TvContractCompat.Channels;
+import android.support.media.tv.test.R;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+
+import junit.framework.TestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+
+/**
+ * Tests that PreviewChannels can be created correctly. Additional test, the ones involving the
+ * System Content Provider, are inside {@link PreviewChannelHelperTest}
+ */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@RunWith(JUnit4.class)
+public class PreviewChannelTest extends TestCase {
+
+ private static final String TAG = "PreviewChannelTest";
+ private Context mContext;
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ mContext = InstrumentationRegistry.getContext();
+ }
+
+ @After
+ public void tearDown() {
+ if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+ return;
+ }
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.delete(Channels.CONTENT_URI, null, null);
+ mContext = null;
+ }
+
+ @Test
+ public void testEmptyPreviewChannel() throws Exception {
+ PreviewChannel.Builder builder = new PreviewChannel.Builder();
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Need channel name. "
+ + "Use method setDisplayName(String) to set it.");
+ PreviewChannel emptyChannel = builder.build();
+ }
+
+ @Test
+ public void testPartiallyPopulatedPreviewChannel() {
+ final String displayName = "Google";
+ final String description = "This is a test preview channel";
+ final Uri uri = Uri.parse(new Intent(Intent.ACTION_VIEW).toUri(Intent.URI_INTENT_SCHEME));
+
+ PreviewChannel channel = new PreviewChannel.Builder()
+ .setDisplayName(displayName)
+ .setDescription(description)
+ .setAppLinkIntentUri(uri)
+ .setLogo(createLogo()).build();
+
+ assertEquals(displayName, channel.getDisplayName());
+ assertEquals(description, channel.getDescription());
+ assertEquals(uri, channel.getAppLinkIntentUri());
+ assertNotNull(channel.getLogo(mContext));
+ assertNull(channel.getPackageName());
+ assertNull(channel.getInternalProviderDataByteArray());
+ assertNull(channel.getInternalProviderFlag1());
+ assertNull(channel.getInternalProviderFlag2());
+ assertNull(channel.getInternalProviderFlag3());
+ assertNull(channel.getInternalProviderFlag4());
+ assertNull(channel.getInternalProviderId());
+ assertFalse(channel.isBrowsable());
+ }
+
+ @Test
+ public void testFullyPopulatedPreviewChannel() {
+ //test cloning and database I/O
+ PreviewChannel channel = createFullyPopulatedPreviewChannel();
+ PreviewChannel clonedChannelFromCursor = PreviewChannel.fromCursor(
+ getPreviewChannelCursor(channel.toContentValues()));
+ assertTrue(channelsEqual(channel, clonedChannelFromCursor));
+
+ PreviewChannel clonedChannelFromBuilder = new PreviewChannel.Builder(channel).build();
+ assertTrue(channelsEqual(channel, clonedChannelFromBuilder));
+ }
+
+ @Test
+ public void testChannelEquals() {
+ assertEquals(createFullyPopulatedPreviewChannel(), createFullyPopulatedPreviewChannel());
+ }
+
+ private boolean channelsEqual(PreviewChannel channelA, PreviewChannel channelB) {
+ boolean result = channelA.getDisplayName().equals(channelB.getDisplayName())
+ && channelA.getType().equals(channelB.getType())
+ && channelA.getAppLinkIntentUri().equals(channelB.getAppLinkIntentUri())
+ && channelA.getDescription().equals(channelB.getDescription())
+ && channelA.getPackageName().equals(channelB.getPackageName())
+ && channelA.getInternalProviderFlag1() == channelB.getInternalProviderFlag1()
+ && channelA.getInternalProviderFlag2() == channelB.getInternalProviderFlag2()
+ && channelA.getInternalProviderFlag3() == channelB.getInternalProviderFlag3()
+ && channelA.getInternalProviderFlag4() == channelB.getInternalProviderFlag4()
+ && channelA.getInternalProviderId().equals(channelB.getInternalProviderId())
+ && Arrays.equals(channelA.getInternalProviderDataByteArray(),
+ channelB.getInternalProviderDataByteArray());
+ return result;
+ }
+
+ private PreviewChannel createFullyPopulatedPreviewChannel() {
+ return new PreviewChannel.Builder()
+ .setAppLinkIntent(new Intent())
+ .setDescription("Test Preview Channel Description")
+ .setDisplayName("Test Display Name")
+ .setPackageName("android.support.media.tv.test")
+ .setInternalProviderFlag1(0x1)
+ .setInternalProviderFlag2(0x2)
+ .setInternalProviderFlag3(0x3)
+ .setInternalProviderFlag4(0x4)
+ .setInternalProviderId("Test Internal provider id")
+ .setLogo(createLogo()).build();
+ }
+
+ private Bitmap createLogo() {
+ Bitmap logo = BitmapFactory.decodeResource(mContext.getResources(),
+ R.drawable.test_icon);
+ assertNotNull(logo);
+ return logo;
+ }
+
+ private MatrixCursor getPreviewChannelCursor(ContentValues contentValues) {
+ MatrixCursor cursor = new MatrixCursor(PreviewChannel.Columns.PROJECTION);
+ MatrixCursor.RowBuilder rowBuilder = cursor.newRow();
+ for (String col : PreviewChannel.Columns.PROJECTION) {
+ rowBuilder.add(col, contentValues.get(col));
+ }
+ cursor.moveToFirst();
+ return cursor;
+ }
+}
diff --git a/tv-provider/src/main/java/android/support/media/tv/PreviewChannel.java b/tv-provider/src/main/java/android/support/media/tv/PreviewChannel.java
new file mode 100644
index 0000000..79a65f9
--- /dev/null
+++ b/tv-provider/src/main/java/android/support/media/tv/PreviewChannel.java
@@ -0,0 +1,565 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.media.tv;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.annotation.TargetApi;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.tv.TvContract;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.WorkerThread;
+import android.support.media.tv.TvContractCompat.Channels;
+import android.support.media.tv.TvContractCompat.Channels.Type;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Since API 26, all TV apps may create preview channels and publish them to the home screen.
+ * We call these App Channels (as distinct from the Live Channels row on the home screen). To help
+ * you create App Channels, the support library provides a number of classes prefixed by the word
+ * Preview-.
+ *
+ * This is a convenience class for mapping your app's content into a
+ * {@link TvContractCompat TvProvider Channel} for publication. Use the provided {@link Builder}
+ * for creating your preview channel object. Once you create a preview channel, you can
+ * use {@link PreviewChannelHelper} to publish it and add {@link PreviewProgram programs} to it.
+ */
+@TargetApi(26)
+public class PreviewChannel {
+
+ private static final String TAG = "PreviewChannel";
+ private static final long INVALID_CHANNEL_ID = -1;
+ private static final int IS_BROWSABLE = 1;
+
+ private ContentValues mValues;
+ private volatile Bitmap mLogoImage;
+
+ private Uri mLogoUri;
+ private boolean mLogoChanged;
+
+ /**
+ * Logo is fetched when it is explicitly asked for. mLogoFetched prevents repeated calls in
+ * case there is no logo in fact.
+ */
+ private volatile boolean mLogoFetched;
+
+ private PreviewChannel(Builder builder) {
+ mValues = builder.mValues;
+ mLogoImage = builder.mLogoBitmap;
+ mLogoUri = builder.mLogoUri;
+ mLogoChanged = (mLogoImage != null || mLogoUri != null);
+ }
+
+ /**
+ * Used by {@link PreviewChannelHelper} to transduce a TvProvider channel row into a
+ * PreviewChannel Java object. You never need to use this method unless you want to convert
+ * database rows to PreviewChannel objects yourself.
+ * <p/>
+ * This method assumes the cursor was obtained using {@link android.support.media.tv
+ * .PreviewChannel.Columns#PROJECTION}. This way, all indices are known
+ * beforehand.
+ *
+ * @param cursor a cursor row from the TvProvider
+ * @return a PreviewChannel whose values come from the cursor row
+ */
+ public static PreviewChannel fromCursor(Cursor cursor) {
+ Builder builder = new Builder();
+ builder.setId(cursor.getInt(Columns.COL_ID));
+ builder.setPackageName(cursor.getString(Columns.COL_PACKAGE_NAME));
+ builder.setType(cursor.getString(Columns.COL_TYPE));
+ builder.setDisplayName(cursor.getString(Columns.COL_DISPLAY_NAME));
+ builder.setDescription(cursor.getString(Columns.COL_DESCRIPTION));
+ builder.setAppLinkIntentUri(Uri.parse(cursor.getString(Columns.COL_APP_LINK_INTENT_URI)));
+ builder.setInternalProviderId(cursor.getString(Columns.COL_INTERNAL_PROVIDER_ID));
+ builder.setInternalProviderData(cursor.getBlob(Columns.COL_INTERNAL_PROVIDER_DATA));
+ builder.setInternalProviderFlag1(cursor.getLong(Columns.COL_INTERNAL_PROVIDER_FLAG1));
+ builder.setInternalProviderFlag2(cursor.getLong(Columns.COL_INTERNAL_PROVIDER_FLAG2));
+ builder.setInternalProviderFlag3(cursor.getLong(Columns.COL_INTERNAL_PROVIDER_FLAG3));
+ builder.setInternalProviderFlag4(cursor.getLong(Columns.COL_INTERNAL_PROVIDER_FLAG4));
+ return builder.build();
+ }
+
+ /**
+ * @return the ID the system assigns to this preview channel upon publication.
+ */
+ public long getId() {
+ Long l = mValues.getAsLong(Channels._ID);
+ return l == null ? INVALID_CHANNEL_ID : l;
+ }
+
+ /**
+ * @return package name of the app that created this channel
+ */
+ public String getPackageName() {
+ return mValues.getAsString(Channels.COLUMN_PACKAGE_NAME);
+ }
+
+ /**
+ * @return what type of channel this is. For preview channels, the type is always
+ * TvContractCompat.Channels.TYPE_PREVIEW
+ */
+ @Type
+ public String getType() {
+ return mValues.getAsString(Channels.COLUMN_TYPE);
+ }
+
+ /**
+ * @return The name users see when this channel appears on the home screen
+ */
+ public CharSequence getDisplayName() {
+ return mValues.getAsString(Channels.COLUMN_DISPLAY_NAME);
+ }
+
+ /**
+ * @return The value of {@link Channels#COLUMN_DESCRIPTION} for the channel. A short text
+ * explaining what this channel contains.
+ */
+ public CharSequence getDescription() {
+ return mValues.getAsString(Channels.COLUMN_DESCRIPTION);
+ }
+
+ /**
+ * @return The value of {@link Channels#COLUMN_APP_LINK_INTENT_URI} for the channel.
+ */
+ public Uri getAppLinkIntentUri() {
+ String uri = mValues.getAsString(Channels.COLUMN_APP_LINK_INTENT_URI);
+ return uri == null ? null : Uri.parse(uri);
+ }
+
+ /**
+ * @return The value of {@link Channels#COLUMN_APP_LINK_INTENT_URI} for the program.
+ */
+ public Intent getAppLinkIntent() throws URISyntaxException {
+ String uri = mValues.getAsString(Channels.COLUMN_APP_LINK_INTENT_URI);
+ return uri == null ? null : Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME);
+ }
+
+ /**
+ * This method should be called on a worker thread since decoding Bitmap is an expensive
+ * operation and therefore should not be performed on the main thread.
+ *
+ * @return The logo associated with this preview channel
+ */
+ @WorkerThread
+ public Bitmap getLogo(Context context) {
+ if (!mLogoFetched && mLogoImage == null) {
+ try {
+ mLogoImage = BitmapFactory.decodeStream(
+ context.getContentResolver().openInputStream(
+ TvContract.buildChannelLogoUri(getId())
+ ));
+ } catch (FileNotFoundException | SQLiteException e) {
+ Log.e(TAG, "Logo for preview channel (ID:" + getId() + ") not found.", e);
+ }
+ mLogoFetched = true;
+ }
+ return mLogoImage;
+ }
+
+ /**
+ * @hide
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ boolean isLogoChanged() {
+ return mLogoChanged;
+ }
+
+ /**
+ * @hide
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ Uri getLogoUri() {
+ return mLogoUri;
+ }
+
+ /**
+ * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_DATA} for the channel.
+ */
+ public byte[] getInternalProviderDataByteArray() {
+ return mValues.getAsByteArray(Channels.COLUMN_INTERNAL_PROVIDER_DATA);
+ }
+
+ /**
+ * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG1} for the channel.
+ */
+ public Long getInternalProviderFlag1() {
+ return mValues.getAsLong(Channels.COLUMN_INTERNAL_PROVIDER_FLAG1);
+ }
+
+ /**
+ * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG2} for the channel.
+ */
+ public Long getInternalProviderFlag2() {
+ return mValues.getAsLong(Channels.COLUMN_INTERNAL_PROVIDER_FLAG2);
+ }
+
+ /**
+ * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG3} for the channel.
+ */
+ public Long getInternalProviderFlag3() {
+ return mValues.getAsLong(Channels.COLUMN_INTERNAL_PROVIDER_FLAG3);
+ }
+
+ /**
+ * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG4} for the channel.
+ */
+ public Long getInternalProviderFlag4() {
+ return mValues.getAsLong(Channels.COLUMN_INTERNAL_PROVIDER_FLAG4);
+ }
+
+ /**
+ * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_ID} for the channel.
+ */
+ public String getInternalProviderId() {
+ return mValues.getAsString(Channels.COLUMN_INTERNAL_PROVIDER_ID);
+ }
+
+ /**
+ * @return The value of {@link Channels#COLUMN_BROWSABLE} for the channel. A preview channel
+ * is BROWABLE when it is visible on the TV home screen.
+ */
+ public boolean isBrowsable() {
+ Integer i = mValues.getAsInteger(Channels.COLUMN_BROWSABLE);
+ return i != null && i == IS_BROWSABLE;
+ }
+
+ @Override
+ public int hashCode() {
+ return mValues.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof PreviewChannel)) {
+ return false;
+ }
+ return mValues.equals(((PreviewChannel) other).mValues);
+ }
+
+ /**
+ * Indicates whether some other PreviewChannel has any set attribute that is different from
+ * this PreviewChannel's respective attributes. An attribute is considered "set" if its key
+ * is present in the ContentValues vector.
+ */
+ public boolean hasAnyUpdatedValues(PreviewChannel update) {
+ Set<String> updateKeys = update.mValues.keySet();
+ for (String key : updateKeys) {
+ Object updateValue = update.mValues.get(key);
+ Object currValue = mValues.get(key);
+ if (!Objects.deepEquals(updateValue, currValue)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "Channel{" + mValues.toString() + "}";
+ }
+
+ /**
+ * Used by {@link PreviewChannelHelper} to communicate PreviewChannel CRUD operations
+ * to the TvProvider. You never need to use this method unless you want to communicate to the
+ * TvProvider directly.
+ *
+ * @hide
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ public ContentValues toContentValues() {
+ ContentValues values = new ContentValues(mValues);
+ return values;
+ }
+
+ /**
+ * @hide
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ public static class Columns {
+ public static final String[] PROJECTION = {
+ Channels._ID,
+ Channels.COLUMN_PACKAGE_NAME,
+ Channels.COLUMN_TYPE,
+ Channels.COLUMN_DISPLAY_NAME,
+ Channels.COLUMN_DESCRIPTION,
+ Channels.COLUMN_APP_LINK_INTENT_URI,
+ Channels.COLUMN_INTERNAL_PROVIDER_ID,
+ Channels.COLUMN_INTERNAL_PROVIDER_DATA,
+ Channels.COLUMN_INTERNAL_PROVIDER_FLAG1,
+ Channels.COLUMN_INTERNAL_PROVIDER_FLAG2,
+ Channels.COLUMN_INTERNAL_PROVIDER_FLAG3,
+ Channels.COLUMN_INTERNAL_PROVIDER_FLAG4
+ };
+
+ public static final int COL_ID = 0;
+ public static final int COL_PACKAGE_NAME = 1;
+ public static final int COL_TYPE = 2;
+ public static final int COL_DISPLAY_NAME = 3;
+ public static final int COL_DESCRIPTION = 4;
+ public static final int COL_APP_LINK_INTENT_URI = 5;
+ public static final int COL_INTERNAL_PROVIDER_ID = 6;
+ public static final int COL_INTERNAL_PROVIDER_DATA = 7;
+ public static final int COL_INTERNAL_PROVIDER_FLAG1 = 8;
+ public static final int COL_INTERNAL_PROVIDER_FLAG2 = 9;
+ public static final int COL_INTERNAL_PROVIDER_FLAG3 = 10;
+ public static final int COL_INTERNAL_PROVIDER_FLAG4 = 11;
+ }
+
+ /**
+ * This builder makes it easy to create a PreviewChannel object by allowing you to chain
+ * setters. Even though this builder provides a no-arg constructor, certain fields are
+ * required or the {@link #build()} method will throw an exception. The required fields are
+ * displayName and appLinkIntentUri; use the respective methods to set them.
+ */
+ public static final class Builder {
+ private ContentValues mValues;
+ private Bitmap mLogoBitmap;
+ private Uri mLogoUri;
+
+ public Builder() {
+ mValues = new ContentValues();
+ }
+
+ public Builder(PreviewChannel other) {
+ mValues = new ContentValues(other.mValues);
+ }
+
+ private Builder setId(long id) {
+ mValues.put(Channels._ID, id);
+ return this;
+ }
+
+ /**
+ * Sets the package name of the Channel.
+ *
+ * @param packageName The value of {@link Channels#COLUMN_PACKAGE_NAME} for the channel.
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ * @hide
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ Builder setPackageName(String packageName) {
+ mValues.put(Channels.COLUMN_PACKAGE_NAME, packageName);
+ return this;
+ }
+
+ // Private because this is always the same: setType(TvContractCompat.Channels.TYPE_PREVIEW)
+ private Builder setType(@Type String type) {
+ mValues.put(Channels.COLUMN_TYPE, type);
+ return this;
+ }
+
+ /**
+ * This is the name user sees when your channel appears on their TV home screen. For
+ * example "New Arrivals." This field is required.
+ *
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ * @see TvContractCompat.Channels#COLUMN_DISPLAY_NAME
+ */
+ public Builder setDisplayName(CharSequence displayName) {
+ mValues.put(Channels.COLUMN_DISPLAY_NAME, displayName.toString());
+ return this;
+ }
+
+ /**
+ * It's good practice to include a general description of the programs in this channel.
+ *
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ * @see TvContractCompat.Channels#COLUMN_DESCRIPTION
+ */
+ public Builder setDescription(CharSequence description) {
+ mValues.put(Channels.COLUMN_DESCRIPTION, description.toString());
+ return this;
+ }
+
+ /**
+ * When user clicks on this channel's logo, the system will send an Intent for your app to
+ * open an Activity with contents relevant to this channel. Hence, the Intent data you
+ * provide here must point to content relevant to this channel.
+ *
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ */
+ public Builder setAppLinkIntent(Intent appLinkIntent) {
+ return setAppLinkIntentUri(Uri.parse(appLinkIntent.toUri(Intent.URI_INTENT_SCHEME)));
+ }
+
+ /**
+ * When user clicks on this channel's logo, the system will send an Intent for your app to
+ * open an Activity with contents relevant to this channel. Hence, the Uri you provide here
+ * must point to content relevant to this channel.
+ *
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ * @see TvContractCompat.Channels#COLUMN_APP_LINK_INTENT_URI
+ */
+ public Builder setAppLinkIntentUri(Uri appLinkIntentUri) {
+ mValues.put(Channels.COLUMN_APP_LINK_INTENT_URI,
+ null == appLinkIntentUri ? null : appLinkIntentUri.toString());
+ return this;
+ }
+
+ /**
+ * It is expected that your app or your server has its own internal representation
+ * (i.e. data structure) of channels. It is highly recommended that you store your
+ * app/server's channel ID here; so that you may easily relate this published preview
+ * channel with the corresponding channel from your server.
+ *
+ * The {@link PreviewChannelHelper#publishChannel(PreviewChannel) publish} method check this
+ * field to verify whether a preview channel being published would result in a duplicate.
+ * :
+ *
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ * @see TvContractCompat.Channels#COLUMN_INTERNAL_PROVIDER_ID
+ */
+ public Builder setInternalProviderId(String internalProviderId) {
+ mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_ID, internalProviderId);
+ return this;
+ }
+
+ /**
+ * This is one of the optional fields that your app may set. Use these fields at your
+ * discretion to help you remember important information about this channel.
+ *
+ * For example, if this channel needs a byte array that is expensive for your app to
+ * construct, you may choose to save it here.
+ *
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ * @see TvContractCompat.Channels#COLUMN_INTERNAL_PROVIDER_DATA
+ */
+ public Builder setInternalProviderData(byte[] internalProviderData) {
+ mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_DATA, internalProviderData);
+ return this;
+ }
+
+ /**
+ * This is one of the optional fields that your app may set. Use these fields at your
+ * discretion to help you remember important information about this channel.
+ *
+ * For example, you may use this flag to track additional data about this particular
+ * channel.
+ *
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ * @see TvContractCompat.Channels#COLUMN_INTERNAL_PROVIDER_FLAG1
+ */
+ public Builder setInternalProviderFlag1(long flag) {
+ mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG1, flag);
+ return this;
+ }
+
+ /**
+ * This is one of the optional fields that your app may set. Use these fields at your
+ * discretion to help you remember important information about this channel.
+ *
+ * For example, you may use this flag to track additional data about this particular
+ * channel.
+ *
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ * @see TvContractCompat.Channels#COLUMN_INTERNAL_PROVIDER_FLAG2
+ */
+ public Builder setInternalProviderFlag2(long flag) {
+ mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG2, flag);
+ return this;
+ }
+
+ /**
+ * This is one of the optional fields that your app may set. Use these fields at your
+ * discretion to help you remember important information about this channel.
+ *
+ * For example, you may use this flag to track additional data about this particular
+ * channel.
+ *
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ * @see TvContractCompat.Channels#COLUMN_INTERNAL_PROVIDER_FLAG3
+ */
+ public Builder setInternalProviderFlag3(long flag) {
+ mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG3, flag);
+ return this;
+ }
+
+ /**
+ * This is one of the optional fields that your app may set. Use these fields at your
+ * discretion to help you remember important information about this channel.
+ *
+ * For example, you may use this flag to track additional data about this particular
+ * channel.
+ *
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ * @see TvContractCompat.Channels#COLUMN_INTERNAL_PROVIDER_FLAG4
+ */
+ public Builder setInternalProviderFlag4(long flag) {
+ mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG4, flag);
+ return this;
+ }
+
+ /**
+ * A logo visually identifies your channel. Hence, you should consider adding a unique logo
+ * to every channel you create, so user can quickly identify your channel.
+ *
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ */
+ public Builder setLogo(@NonNull Bitmap logoImage) {
+ mLogoBitmap = logoImage;
+ mLogoUri = null;
+ return this;
+ }
+
+ /**
+ * A logo visually identifies your channel. Hence, you should consider adding a unique logo
+ * to every channel you create, so user can quickly identify your channel.
+ *
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ */
+ public Builder setLogo(@NonNull Uri logoUri) {
+ mLogoUri = logoUri;
+ mLogoBitmap = null;
+ return this;
+ }
+
+ /**
+ * Takes the values of the Builder object and creates a PreviewChannel object.
+ *
+ * @return PreviewChannel object with values from the Builder.
+ */
+ public PreviewChannel build() {
+ setType(Channels.TYPE_PREVIEW);
+
+ if (TextUtils.isEmpty(mValues.getAsString(Channels.COLUMN_DISPLAY_NAME))) {
+ throw new IllegalStateException("Need channel name."
+ + " Use method setDisplayName(String) to set it.");
+ }
+
+ if (TextUtils.isEmpty(mValues.getAsString(Channels.COLUMN_APP_LINK_INTENT_URI))) {
+ throw new IllegalStateException("Need app link intent uri for channel."
+ + " Use method setAppLinkIntent or setAppLinkIntentUri to set it.");
+ }
+
+ PreviewChannel previewChannel = new PreviewChannel(this);
+ return previewChannel;
+ }
+ }
+}
diff --git a/tv-provider/src/main/java/android/support/media/tv/PreviewChannelHelper.java b/tv-provider/src/main/java/android/support/media/tv/PreviewChannelHelper.java
new file mode 100644
index 0000000..05fa9f5
--- /dev/null
+++ b/tv-provider/src/main/java/android/support/media/tv/PreviewChannelHelper.java
@@ -0,0 +1,475 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.media.tv;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.annotation.TargetApi;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.WorkerThread;
+import android.text.format.DateUtils;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * From a user's perspective, the TV home screen has two types of channels: the single Live
+ * Channels row versus the App preview Channels. This class is concerned with App Channels; or more
+ * precisely: <i>your</i> app's preview Channels. In API 26+, all TV apps are allowed to create
+ * multiple channels and publish those Channels to the home screen.
+ * <p>
+ * This class provides convenience methods to help you publish, update and delete channels; add,
+ * update or remove programs in a channel. You do not need to know anything about Content
+ * Providers, Content Resolvers, Cursors or such to publish your channels. This class abstracts
+ * away all database interactions for you.
+ * <p>
+ * To make it easy for you to distinguish classes that help you build App Channels, the support
+ * library uses the prefix Preview- to denote the classes that pertain to app Channels. Hence,
+ * the classes {@link PreviewChannel} and {@link PreviewProgram} help your app add channels to the
+ * TV home page.
+ *
+ * All calls to methods in the class should be made on worker threads.
+ */
+
+@TargetApi(26)
+@WorkerThread
+public class PreviewChannelHelper {
+
+ private static final String TAG = "PreviewChannelHelper";
+ private static final int DEFAULT_URL_CONNNECTION_TIMEOUT_MILLIS =
+ (int) (3 * DateUtils.SECOND_IN_MILLIS);
+ private static final int DEFAULT_READ_TIMEOUT_MILLIS = (int) (10 * DateUtils.SECOND_IN_MILLIS);
+ private static final int INVALID_CONTENT_ID = -1;
+ private final int mUrlConnectionTimeoutMillis;
+ private final int mUrlReadTimeoutMillis;
+ private final Context mContext;
+
+ public PreviewChannelHelper(Context context) {
+ this(context, DEFAULT_URL_CONNNECTION_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS);
+ }
+
+ /**
+ * @param urlConnectionTimeoutMillis see {@link URLConnection#setConnectTimeout(int)}
+ * @param urlReadTimeoutMillis see {@link URLConnection#setReadTimeout(int)}
+ */
+ public PreviewChannelHelper(Context context, int urlConnectionTimeoutMillis,
+ int urlReadTimeoutMillis) {
+ mContext = context;
+ mUrlConnectionTimeoutMillis = urlConnectionTimeoutMillis;
+ mUrlReadTimeoutMillis = urlReadTimeoutMillis;
+ }
+
+ /**
+ * Publishing a channel to the TV home screen is a two step process: first, you add the
+ * channel to the TV content provider; second, you make the channel browsable (i.e. visible).
+ * {@link #publishChannel(PreviewChannel) This method} adds the channel to the
+ * TV content provider for you and returns a channelId. Next you must use the channelId
+ * to make the channel browsable.
+ * </br>
+ * There are two ways you can make a channel browsable:
+ * </br>
+ * a) For your first channel, simply ask the system to make the channel browsable:
+ * TvContractCompat.requestChannelBrowsable(context,channelId)
+ * </br>
+ * b) For any additional channel beyond the first channel, you must get permission
+ * from the user. So if this channel is not your first channel, you must request user
+ * permission through the following intent. So take the channelId returned by
+ * {@link #publishChannel(PreviewChannel) this method} and do the following
+ * inside an Activity or Fragment:
+ * </br>
+ * <pre>
+ * intent = new Intent(TvContractCompat.ACTION_REQUEST_CHANNEL_BROWSABLE);
+ * intent.putExtra(TvContractCompat.EXTRA_CHANNEL_ID, channelId);
+ * startActivityForResult(intent, REQUEST_CHANNEL_BROWSABLE);
+ * </pre>
+ *
+ * <p>
+ * Creating a PreviewChannel, you may pass to the builder a
+ * {@link PreviewChannel.Builder#setLogo(Uri) url as your logo}. In such case,
+ * {@link #updatePreviewChannel(long, PreviewChannel)} will load the logo over the network. To
+ * use your own networking code, override {@link #downloadBitmap(Uri)}.
+ *
+ * @return channelId or -1 if insertion fails. This is the id the system assigns to your
+ * published channel. You can use it later to get a reference to this published PreviewChannel.
+ */
+ public long publishChannel(@NonNull PreviewChannel channel) throws IOException {
+ try {
+ Uri channelUri = mContext.getContentResolver().insert(
+ TvContractCompat.Channels.CONTENT_URI,
+ channel.toContentValues());
+ if (null == channelUri || channelUri.equals(Uri.EMPTY)) {
+ throw new NullPointerException("Channel insertion failed");
+ }
+ long channelId = ContentUris.parseId(channelUri);
+ boolean logoAdded = addChannelLogo(channelId, channel);
+ // Rollback channel insertion if logo could not be added.
+ if (!logoAdded) {
+ deletePreviewChannel(channelId);
+ throw new IOException("Failed to add logo, so channel (ID="
+ + channelId + ") was not created");
+ }
+ return channelId;
+ } catch (SecurityException e) {
+ Log.e(TAG, "Your app's ability to insert data into the TvProvider"
+ + " may have been revoked.", e);
+ }
+ return INVALID_CONTENT_ID;
+ }
+
+ /**
+ * This is a convenience method that simply publishes your first channel for you. After calling
+ * {@link #publishChannel(PreviewChannel)} to add the channel to the TvProvider, it
+ * calls {@link TvContractCompat#requestChannelBrowsable(Context, long)} to make the channel
+ * visible.
+ * <p>
+ * Only use this method to publish your first channel as you do not need user permission to
+ * make your first channel browsable (i.e. visible on home screen). For additional channels,
+ * see the documentations for {@link #publishChannel(PreviewChannel)}.
+ *
+ * <p>
+ * Creating a PreviewChannel, you may pass to the builder a
+ * {@link PreviewChannel.Builder#setLogo(Uri) url as your logo}. In such case,
+ * {@link #updatePreviewChannel(long, PreviewChannel)} will load the logo over the network. To
+ * use your own networking code, override {@link #downloadBitmap(Uri)}.
+ *
+ * @return channelId: This is the id the system assigns to your published channel. You can
+ * use it later to get a reference to this published PreviewChannel.
+ */
+ public long publishDefaultChannel(@NonNull PreviewChannel channel)
+ throws IOException {
+ long channelId = publishChannel(channel);
+ TvContractCompat.requestChannelBrowsable(mContext, channelId);
+ return channelId;
+ }
+
+ /**
+ * The TvProvider does not allow select queries. Hence, unless you are querying for a
+ * {@link #getPreviewChannel(long) single PreviewChannel by id}, you must get all of
+ * your channels at once and then use the returned list as necessary.
+ */
+ public List<PreviewChannel> getAllChannels() {
+ Cursor cursor = mContext.getContentResolver()
+ .query(
+ TvContractCompat.Channels.CONTENT_URI,
+ PreviewChannel.Columns.PROJECTION,
+ null,
+ null,
+ null);
+
+ List<PreviewChannel> channels = new ArrayList<>();
+ if (cursor != null && cursor.moveToFirst()) {
+ do {
+ channels.add(PreviewChannel.fromCursor(cursor));
+ } while (cursor.moveToNext());
+ }
+ return channels;
+ }
+
+ /**
+ * Retrieves a single preview channel from the TvProvider. When you publish a preview channel,
+ * the TvProvider assigns an ID to it. That's the channelId to use here.
+ *
+ * @param channelId ID of preview channel in TvProvider
+ * @return PreviewChannel or null if not found
+ */
+ public PreviewChannel getPreviewChannel(long channelId) {
+ PreviewChannel channel = null;
+ Uri channelUri = TvContractCompat.buildChannelUri(channelId);
+ Cursor cursor = mContext.getContentResolver()
+ .query(channelUri, PreviewChannel.Columns.PROJECTION, null, null, null);
+ if (cursor != null && cursor.moveToFirst()) {
+ channel = PreviewChannel.fromCursor(cursor);
+ }
+ return channel;
+ }
+
+ /**
+ * To update a preview channel, you need to use the {@link PreviewChannel.Builder} to set the
+ * attributes you wish to change. Then simply pass in the built channel and the channelId of the
+ * preview channel. (The channelId is the ID you received when you originally
+ * {@link #publishChannel(PreviewChannel) published} the preview channel.)
+ * <p>
+ * Creating a PreviewChannel, you may pass to the builder a
+ * {@link PreviewChannel.Builder#setLogo(Uri) url as your logo}. In such case,
+ * {@link #updatePreviewChannel(long, PreviewChannel)} will load the logo over the network. To
+ * use your own networking code, override {@link #downloadBitmap(Uri)}.
+ */
+ public void updatePreviewChannel(long channelId,
+ @NonNull PreviewChannel update) throws IOException {
+ // To avoid possibly expensive no-op updates, first check that the current content that's
+ // in the database is different from the new content to be added.
+ PreviewChannel curr = getPreviewChannel(channelId);
+ if (curr != null && curr.hasAnyUpdatedValues(update)) {
+ updatePreviewChannelInternal(channelId, update);
+ }
+ if (update.isLogoChanged()) {
+ boolean logoAdded = addChannelLogo(channelId, update);
+ if (!logoAdded) {
+ throw new IOException("Fail to update channel (ID=" + channelId + ") logo.");
+ }
+ }
+ }
+
+ /**
+ * Inner methods that does the actual work of updating a Preview Channel. The method is
+ * extracted to make {@link #updatePreviewChannel(long, PreviewChannel)} testable.
+ *
+ * @hide
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ protected void updatePreviewChannelInternal(long channelId, @NonNull PreviewChannel upgrade) {
+ mContext.getContentResolver().update(
+ TvContractCompat.buildChannelUri(channelId),
+ upgrade.toContentValues(),
+ null,
+ null);
+ }
+
+ /**
+ * Internally, a logo is added to a channel after the channel has been added to the TvProvider.
+ * This private method is called by one of the publish methods, to add a logo to the TvProvider
+ * and associate the logo to the given channel identified by channelId. Because each channel
+ * must have a logo, a NullPointerException is thrown if the channel being published has no
+ * associated logo to publish with it.
+ */
+ private boolean addChannelLogo(long channelId, @NonNull PreviewChannel channel) {
+ boolean result = false;
+ if (!channel.isLogoChanged()) {
+ return result;
+ }
+ Bitmap logo = channel.getLogo(mContext);
+ if (logo == null) {
+ logo = getLogoFromUri(channel.getLogoUri());
+ }
+ Uri logoUri = TvContractCompat.buildChannelLogoUri(channelId);
+ try (OutputStream outputStream = mContext.getContentResolver().openOutputStream(
+ logoUri)) {
+ result = logo.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
+ outputStream.flush();
+ } catch (SQLiteException | IOException | NullPointerException e) {
+ Log.i(TAG, "Failed to add logo to the published channel (ID= " + channelId + ")", e);
+ }
+ return result;
+ }
+
+ /**
+ * Handles the case where the Bitmap must be fetched from a known uri. First the
+ * method checks if the Uri is local. If not, the method makes a connection to fetch the Bitmap
+ * data from its remote location. To use your own networking implementation, simply override
+ * {@link #downloadBitmap(Uri)}
+ */
+ private Bitmap getLogoFromUri(@NonNull Uri logoUri) {
+ String scheme = logoUri.normalizeScheme().getScheme();
+ InputStream inputStream = null;
+ Bitmap logoImage = null;
+
+ try {
+ if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)
+ || ContentResolver.SCHEME_FILE.equals(scheme)
+ || ContentResolver.SCHEME_CONTENT.equals(scheme)) {
+ // for local resource
+ inputStream = mContext.getContentResolver().openInputStream(logoUri);
+ logoImage = BitmapFactory.decodeStream(inputStream);
+ } else {
+ logoImage = downloadBitmap(logoUri);
+ }
+
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to get logo from the URI: " + logoUri, e);
+ } finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ // Do nothing
+ }
+ }
+ }
+ return logoImage;
+ }
+
+ /**
+ * Downloads a Bitmap from a remote server. It is declared protected to allow you
+ * to override it to use your own networking implementation if you so wish.
+ */
+ protected Bitmap downloadBitmap(@NonNull Uri logoUri) throws IOException {
+ URLConnection urlConnection = null;
+ InputStream inputStream = null;
+ Bitmap logoImage = null;
+ try {
+ // for remote resource
+ urlConnection = new URL(logoUri.toString()).openConnection();
+ urlConnection.setConnectTimeout(mUrlConnectionTimeoutMillis);
+ urlConnection.setReadTimeout(mUrlReadTimeoutMillis);
+ inputStream = urlConnection.getInputStream();
+ logoImage = BitmapFactory.decodeStream(inputStream);
+ } finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ // Do nothing
+ }
+ }
+ if (urlConnection instanceof HttpURLConnection) {
+ ((HttpURLConnection) urlConnection).disconnect();
+ }
+ }
+ return logoImage;
+ }
+
+ /**
+ * Removes a preview channel from the system's content provider (aka TvProvider).
+ */
+ public void deletePreviewChannel(long channelId) {
+ mContext.getContentResolver().delete(
+ TvContractCompat.buildChannelUri(channelId),
+ null,
+ null);
+ }
+
+ /**
+ * Adds programs to a preview channel.
+ */
+ public long publishPreviewProgram(@NonNull PreviewProgram program) {
+ try {
+ Uri programUri = mContext.getContentResolver().insert(
+ TvContractCompat.PreviewPrograms.CONTENT_URI,
+ program.toContentValues());
+ long programId = ContentUris.parseId(programUri);
+ return programId;
+ } catch (SecurityException e) {
+ Log.e(TAG, "Your app's ability to insert data into the TvProvider"
+ + " may have been revoked.", e);
+ }
+ return INVALID_CONTENT_ID;
+ }
+
+ /**
+ * Retrieves a single preview program from the system content provider (aka TvProvider).
+ */
+ public PreviewProgram getPreviewProgram(long programId) {
+ PreviewProgram program = null;
+ Uri programUri = TvContractCompat.buildPreviewProgramUri(programId);
+ Cursor cursor = mContext.getContentResolver().query(programUri, null, null, null, null);
+ if (cursor != null && cursor.moveToFirst()) {
+ program = PreviewProgram.fromCursor(cursor);
+ }
+ return program;
+ }
+
+ /**
+ * Updates programs in a preview channel.
+ */
+ public void updatePreviewProgram(long programId, @NonNull PreviewProgram update) {
+ // To avoid possibly expensive no-op updates, first check that the current content that's
+ // in the database is different from the new content to be added.
+ PreviewProgram curr = getPreviewProgram(programId);
+ if (curr != null && curr.hasAnyUpdatedValues(update)) {
+ updatePreviewProgramInternal(programId, update);
+ }
+ }
+
+ /**
+ * Inner methods that does the actual work of updating a Preview Program. The method is
+ * extracted to make {@link #updatePreviewProgram(long, PreviewProgram)} testable.
+ *
+ * @hide
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ void updatePreviewProgramInternal(long programId, @NonNull PreviewProgram upgrade) {
+ mContext.getContentResolver().update(
+ TvContractCompat.buildPreviewProgramUri(programId),
+ upgrade.toContentValues(), null, null);
+ }
+
+ /**
+ * Removes programs from a preview channel.
+ */
+ public void deletePreviewProgram(long programId) {
+ mContext.getContentResolver().delete(
+ TvContractCompat.buildPreviewProgramUri(programId), null, null);
+ }
+
+ /**
+ * Adds a program to the Watch Next channel
+ */
+ public long publishWatchNextProgram(@NonNull WatchNextProgram program) {
+ try {
+ Uri programUri = mContext.getContentResolver().insert(
+ TvContractCompat.WatchNextPrograms.CONTENT_URI, program.toContentValues());
+ return ContentUris.parseId(programUri);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Your app's ability to insert data into the TvProvider"
+ + " may have been revoked.", e);
+ }
+ return INVALID_CONTENT_ID;
+ }
+
+ /**
+ * Retrieves a single WatchNext program from the system content provider (aka TvProvider).
+ */
+ public WatchNextProgram getWatchNextProgram(long programId) {
+ WatchNextProgram program = null;
+ Uri programUri = TvContractCompat.buildWatchNextProgramUri(programId);
+ Cursor cursor = mContext.getContentResolver().query(programUri, null, null, null, null);
+ if (cursor != null && cursor.moveToFirst()) {
+ program = WatchNextProgram.fromCursor(cursor);
+ }
+ return program;
+ }
+
+ /**
+ * Updates a WatchNext program.
+ */
+ public void updateWatchNextProgram(@NonNull WatchNextProgram upgrade, long programId) {
+ // To avoid possibly expensive no-op updates, first check that the current content that's in
+ // the database is different from the new content to be added.
+ WatchNextProgram curr = getWatchNextProgram(programId);
+ if (curr != null && curr.hasAnyUpdatedValues(upgrade)) {
+ updateWatchNextProgram(programId, upgrade);
+ }
+ }
+
+ /**
+ * Inner methods that does the actual work of updating a Watch Next Program. The method is
+ * extracted to make {@link #updateWatchNextProgram(WatchNextProgram, long)} testable.
+ *
+ * @hide
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ void updateWatchNextProgram(long programId, @NonNull WatchNextProgram upgrade) {
+ mContext.getContentResolver().update(
+ TvContractCompat.buildWatchNextProgramUri(programId),
+ upgrade.toContentValues(), null, null);
+ }
+}
diff --git a/tv-provider/src/main/java/android/support/media/tv/PreviewProgram.java b/tv-provider/src/main/java/android/support/media/tv/PreviewProgram.java
index 2536f75..f44e18f 100644
--- a/tv-provider/src/main/java/android/support/media/tv/PreviewProgram.java
+++ b/tv-provider/src/main/java/android/support/media/tv/PreviewProgram.java
@@ -23,6 +23,9 @@
import android.support.annotation.RestrictTo;
import android.support.media.tv.TvContractCompat.PreviewPrograms;
+import java.util.Objects;
+import java.util.Set;
+
/**
* A convenience class to access {@link PreviewPrograms} entries in the system content
* provider.
@@ -108,6 +111,23 @@
return mValues.equals(((PreviewProgram) other).mValues);
}
+ /**
+ * Indicates whether some other PreviewProgram has any set attribute that is different from
+ * this PreviewProgram's respective attributes. An attribute is considered "set" if its key
+ * is present in the ContentValues vector.
+ */
+ public boolean hasAnyUpdatedValues(PreviewProgram update) {
+ Set<String> updateKeys = update.mValues.keySet();
+ for (String key : updateKeys) {
+ Object updateValue = update.mValues.get(key);
+ Object currValue = mValues.get(key);
+ if (!Objects.deepEquals(updateValue, currValue)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public String toString() {
return "PreviewProgram{" + mValues.toString() + "}";
@@ -164,7 +184,7 @@
}
private static String[] getProjection() {
- String[] oColumns = new String[] {
+ String[] oColumns = new String[]{
PreviewPrograms.COLUMN_CHANNEL_ID,
PreviewPrograms.COLUMN_WEIGHT,
};
@@ -184,6 +204,7 @@
/**
* Creates a new Builder object with values copied from another Program.
+ *
* @param other The Program you're copying from.
*/
public Builder(PreviewProgram other) {
diff --git a/tv-provider/src/main/java/android/support/media/tv/WatchNextProgram.java b/tv-provider/src/main/java/android/support/media/tv/WatchNextProgram.java
index e5d12b2..cb317b7 100644
--- a/tv-provider/src/main/java/android/support/media/tv/WatchNextProgram.java
+++ b/tv-provider/src/main/java/android/support/media/tv/WatchNextProgram.java
@@ -26,6 +26,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+import java.util.Set;
/**
* A convenience class to access {@link WatchNextPrograms} entries in the system content
@@ -94,7 +96,8 @@
})
@Retention(RetentionPolicy.SOURCE)
@RestrictTo(LIBRARY_GROUP)
- public @interface WatchNextType {}
+ public @interface WatchNextType {
+ }
/**
* The unknown watch next type. Use this type when the actual type is not known.
@@ -131,6 +134,23 @@
return mValues.equals(((WatchNextProgram) other).mValues);
}
+ /**
+ * Indicates whether some other WatchNextProgram has any set attribute that is different from
+ * this WatchNextProgram's respective attributes. An attribute is considered "set" if its key
+ * is present in the ContentValues vector.
+ */
+ public boolean hasAnyUpdatedValues(WatchNextProgram update) {
+ Set<String> updateKeys = update.mValues.keySet();
+ for (String key : updateKeys) {
+ Object updateValue = update.mValues.get(key);
+ Object currValue = mValues.get(key);
+ if (!Objects.deepEquals(updateValue, currValue)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public String toString() {
return "WatchNextProgram{" + mValues.toString() + "}";
@@ -188,7 +208,7 @@
}
private static String[] getProjection() {
- String[] oColumns = new String[] {
+ String[] oColumns = new String[]{
WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE,
WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS,
};
@@ -208,6 +228,7 @@
/**
* Creates a new Builder object with values copied from another Program.
+ *
* @param other The Program you're copying from.
*/
public Builder(WatchNextProgram other) {
@@ -235,7 +256,8 @@
* Sets the time when the program is going to begin in milliseconds since the epoch.
*
* @param lastEngagementTimeUtcMillis The value of
- * {@link WatchNextPrograms#COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS} for the program.
+ * {@link WatchNextPrograms#COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS}
+ * for the program.
* @return This Builder object to allow for chaining of calls to builder methods.
*/
public Builder setLastEngagementTimeUtcMillis(long lastEngagementTimeUtcMillis) {
diff --git a/v13/build.gradle b/v13/build.gradle
index 82a48bd..cb9cdbf 100644
--- a/v13/build.gradle
+++ b/v13/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/v14/preference/build.gradle b/v14/preference/build.gradle
index 86036bd..43f6e36 100644
--- a/v14/preference/build.gradle
+++ b/v14/preference/build.gradle
@@ -14,8 +14,8 @@
* limitations under the License
*/
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/v4/build.gradle b/v4/build.gradle
index 8725a46..640c5fe 100644
--- a/v4/build.gradle
+++ b/v4/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/v7/appcompat/build.gradle b/v7/appcompat/build.gradle
index 799b7b3..2f50fff 100644
--- a/v7/appcompat/build.gradle
+++ b/v7/appcompat/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
@@ -17,7 +17,7 @@
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'), {
+ androidTestImplementation project(':internal-testutils'), {
exclude group: 'com.android.support', module: 'appcompat-v7'
}
}
@@ -36,6 +36,10 @@
additionalParameters "--no-version-vectors"
noCompress 'ttf'
}
+
+ buildTypes.all {
+ consumerProguardFiles("proguard-rules.pro")
+ }
}
supportLibrary {
diff --git a/v7/appcompat/proguard-rules.pro b/v7/appcompat/proguard-rules.pro
new file mode 100644
index 0000000..98c23e5
--- /dev/null
+++ b/v7/appcompat/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Ensure that reflectively-loaded inflater is not obfuscated. This can be
+# removed when we stop supporting AAPT1 builds.
+-keepnames class android.support.v7.app.AppCompatViewInflater
diff --git a/v7/appcompat/res/values-land/dimens.xml b/v7/appcompat/res/values-land/dimens.xml
deleted file mode 100644
index f0b6892..0000000
--- a/v7/appcompat/res/values-land/dimens.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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>
- <!-- Size of the indeterminate Progress Bar -->
- <dimen name="abc_action_bar_progress_bar_size">32dp</dimen>
-
-</resources>
\ No newline at end of file
diff --git a/v7/appcompat/src/androidTest/java/android/support/v7/app/NightModeTestCase.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/NightModeTestCase.java
index d42174f..7f636bd 100644
--- a/v7/appcompat/src/androidTest/java/android/support/v7/app/NightModeTestCase.java
+++ b/v7/appcompat/src/androidTest/java/android/support/v7/app/NightModeTestCase.java
@@ -30,8 +30,6 @@
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.AppCompatActivityUtils;
-import android.support.testutils.RecreatedAppCompatActivity;
import android.support.v4.content.ContextCompat;
import android.support.v7.appcompat.test.R;
@@ -43,6 +41,9 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import androidx.testutils.AppCompatActivityUtils;
+import androidx.testutils.RecreatedAppCompatActivity;
+
@LargeTest
@RunWith(AndroidJUnit4.class)
public class NightModeTestCase {
diff --git a/v7/appcompat/src/androidTest/java/android/support/v7/testutils/BaseTestActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/testutils/BaseTestActivity.java
index e4dbf26..c880768 100644
--- a/v7/appcompat/src/androidTest/java/android/support/v7/testutils/BaseTestActivity.java
+++ b/v7/appcompat/src/androidTest/java/android/support/v7/testutils/BaseTestActivity.java
@@ -19,7 +19,6 @@
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.testutils.RecreatedAppCompatActivity;
import android.support.v7.app.AppCompatCallback;
import android.support.v7.appcompat.test.R;
import android.support.v7.view.ActionMode;
@@ -28,6 +27,8 @@
import android.view.MenuItem;
import android.view.WindowManager;
+import androidx.testutils.RecreatedAppCompatActivity;
+
public abstract class BaseTestActivity extends RecreatedAppCompatActivity {
private Menu mMenu;
diff --git a/v7/appcompat/src/androidTest/java/android/support/v7/widget/PopupMenuTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/PopupMenuTest.java
index cae216d..c1326ac 100644
--- a/v7/appcompat/src/androidTest/java/android/support/v7/widget/PopupMenuTest.java
+++ b/v7/appcompat/src/androidTest/java/android/support/v7/widget/PopupMenuTest.java
@@ -56,7 +56,6 @@
import android.support.test.filters.SdkSuppress;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.appcompat.test.R;
import android.text.TextUtils;
@@ -80,6 +79,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import androidx.testutils.PollingCheck;
+
@RunWith(AndroidJUnit4.class)
public class PopupMenuTest {
@Rule
diff --git a/v7/appcompat/src/androidTest/java/android/support/v7/widget/SearchView_CursorTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/SearchView_CursorTest.java
index ea919e8..7d61d54 100644
--- a/v7/appcompat/src/androidTest/java/android/support/v7/widget/SearchView_CursorTest.java
+++ b/v7/appcompat/src/androidTest/java/android/support/v7/widget/SearchView_CursorTest.java
@@ -36,7 +36,6 @@
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v7.appcompat.test.R;
@@ -50,6 +49,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import androidx.testutils.PollingCheck;
+
/**
* Test {@link SearchView} with {@link Cursor}-backed suggestions adapter.
*/
diff --git a/v7/appcompat/src/main/java/android/support/v7/app/WindowDecorActionBar.java b/v7/appcompat/src/main/java/android/support/v7/app/WindowDecorActionBar.java
index 1c17922..db8c1a2 100644
--- a/v7/appcompat/src/main/java/android/support/v7/app/WindowDecorActionBar.java
+++ b/v7/appcompat/src/main/java/android/support/v7/app/WindowDecorActionBar.java
@@ -239,7 +239,7 @@
return ((Toolbar) view).getWrapper();
} else {
throw new IllegalStateException("Can't make a decor toolbar out of " +
- view != null ? view.getClass().getSimpleName() : "null");
+ (view != null ? view.getClass().getSimpleName() : "null"));
}
}
diff --git a/v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuItemView.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuItemView.java
index 0b5cb48..8e58754 100644
--- a/v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuItemView.java
+++ b/v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuItemView.java
@@ -196,9 +196,8 @@
if (checkable) {
compoundButton.setChecked(mItemData.isChecked());
- final int newVisibility = checkable ? VISIBLE : GONE;
- if (compoundButton.getVisibility() != newVisibility) {
- compoundButton.setVisibility(newVisibility);
+ if (compoundButton.getVisibility() != VISIBLE) {
+ compoundButton.setVisibility(VISIBLE);
}
// Make sure the other compound button isn't visible
diff --git a/v7/cardview/build.gradle b/v7/cardview/build.gradle
index 88ce452..cb597ad 100644
--- a/v7/cardview/build.gradle
+++ b/v7/cardview/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/v7/gridlayout/build.gradle b/v7/gridlayout/build.gradle
index 329cb00..85021b1 100644
--- a/v7/gridlayout/build.gradle
+++ b/v7/gridlayout/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/v7/mediarouter/build.gradle b/v7/mediarouter/build.gradle
index f28938b..3d19227 100644
--- a/v7/mediarouter/build.gradle
+++ b/v7/mediarouter/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/v7/palette/build.gradle b/v7/palette/build.gradle
index 8829dcb..9c91601 100644
--- a/v7/palette/build.gradle
+++ b/v7/palette/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/v7/preference/build.gradle b/v7/preference/build.gradle
index 7707883..a0c9bd9 100644
--- a/v7/preference/build.gradle
+++ b/v7/preference/build.gradle
@@ -14,9 +14,9 @@
* limitations under the License
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/v7/preference/lint-baseline.xml b/v7/preference/lint-baseline.xml
index a069f13..884c7da 100644
--- a/v7/preference/lint-baseline.xml
+++ b/v7/preference/lint-baseline.xml
@@ -3,39 +3,6 @@
<issue
id="NewApi"
- message="`@android:id/icon_frame` requires API level 24 (current min is 14)"
- errorLine1=" android:id="@android:id/icon_frame""
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/layout-v7/expand_button.xml"
- line="31"
- column="9"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`?android:attr/textAppearanceListItemSecondary` requires API level 21 (current min is 14)"
- errorLine1=" android:textAppearance="?android:attr/textAppearanceListItemSecondary""
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/layout-v7/expand_button.xml"
- line="69"
- column="13"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Using theme references in XML drawables requires API level 21 (current min is 14)"
- errorLine1=" android:tint="?android:attr/colorAccent">"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/drawable/ic_arrow_down_24dp.xml"
- line="22"
- column="9"/>
- </issue>
-
- <issue
- id="NewApi"
message="`@android:id/list_container` requires API level 24 (current min is 14)"
errorLine1=" android:id="@android:id/list_container""
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -62,17 +29,6 @@
errorLine1=" android:layout_width="0dp""
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="res/layout-v11/preference_dropdown.xml"
- line="30"
- column="9"/>
- </issue>
-
- <issue
- id="Suspicious0dp"
- message="Suspicious size: this will make the view invisible, should be used with `layout_weight`"
- errorLine1=" android:layout_width="0dp""
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
file="res/layout-v17/preference_dropdown_material.xml"
line="32"
column="9"/>
diff --git a/v7/preference/res/values/attrs.xml b/v7/preference/res/values/attrs.xml
index bb52593..332a3df 100644
--- a/v7/preference/res/values/attrs.xml
+++ b/v7/preference/res/values/attrs.xml
@@ -176,6 +176,9 @@
<attr name="iconSpaceReserved" format="boolean" />
<attr name="android:iconSpaceReserved" />
+ <!-- Whether the Preference is visible. By default, this is set to true. -->
+ <attr name="isPreferenceVisible" format="boolean" />
+
</declare-styleable>
<!-- Base attributes available to CheckBoxPreference. -->
diff --git a/v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferenceVisibilityTest.java b/v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferenceVisibilityTest.java
new file mode 100644
index 0000000..9000f15
--- /dev/null
+++ b/v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferenceVisibilityTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.preference.tests;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.preference.test.R;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test for {@link android.support.v7.preference.Preference} visibility set with XML.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PreferenceVisibilityTest {
+
+ @Test
+ @UiThreadTest
+ public void testPreferencesAreCreatedWithTheVisibilitySetInXml() {
+ final Context context = InstrumentationRegistry.getTargetContext();
+ final PreferenceManager manager = new PreferenceManager(context);
+ final PreferenceScreen screen = manager.inflateFromResource(context,
+ R.layout.test_visibility,
+ null);
+
+ // Preference without visibility set should be visible
+ assertTrue(screen.getPreference(0).isVisible());
+ // Preference with visibility set to true should be visible
+ assertTrue(screen.getPreference(1).isVisible());
+ // Preference with visibility set to false should not be invisible
+ assertFalse(screen.getPreference(2).isVisible());
+ }
+}
diff --git a/v7/preference/src/androidTest/res/layout/test_visibility.xml b/v7/preference/src/androidTest/res/layout/test_visibility.xml
new file mode 100644
index 0000000..5623cd1
--- /dev/null
+++ b/v7/preference/src/androidTest/res/layout/test_visibility.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent">
+
+ <Preference android:summary="This preference is visible by default" />
+
+ <Preference
+ android:summary="This preference is forced to be visible"
+ app:isPreferenceVisible="true" />
+
+ <Preference
+ android:summary="This preference is invisible"
+ app:isPreferenceVisible="false" />
+</PreferenceScreen>
diff --git a/v7/preference/src/main/java/android/support/v7/preference/Preference.java b/v7/preference/src/main/java/android/support/v7/preference/Preference.java
index 88262cd..79fbceb 100644
--- a/v7/preference/src/main/java/android/support/v7/preference/Preference.java
+++ b/v7/preference/src/main/java/android/support/v7/preference/Preference.java
@@ -323,6 +323,9 @@
mIconSpaceReserved = TypedArrayUtils.getBoolean(a, R.styleable.Preference_iconSpaceReserved,
R.styleable.Preference_android_iconSpaceReserved, false);
+ mVisible = TypedArrayUtils.getBoolean(a, R.styleable.Preference_isPreferenceVisible,
+ R.styleable.Preference_isPreferenceVisible, true);
+
a.recycle();
}
@@ -871,6 +874,8 @@
* {@link PreferenceFragmentCompat#findPreference(CharSequence)}.
*
* @param visible Set false if this preference should be hidden from the list.
+ *
+ * @attr ref R.styleable#Preference_isPreferenceVisible
*/
public final void setVisible(boolean visible) {
if (mVisible != visible) {
diff --git a/v7/recyclerview/build.gradle b/v7/recyclerview/build.gradle
index e58e5b1..5f7630c 100644
--- a/v7/recyclerview/build.gradle
+++ b/v7/recyclerview/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
@@ -18,7 +18,7 @@
androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation(JUNIT)
androidTestImplementation(KOTLIN_STDLIB)
- androidTestImplementation(project(":support-testutils"))
+ androidTestImplementation(project(":internal-testutils"))
testImplementation(JUNIT)
testImplementation(MOCKITO_CORE)
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
index e47a480..cf6e228 100644
--- a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
@@ -36,7 +36,6 @@
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.util.Log;
@@ -63,6 +62,8 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import androidx.testutils.PollingCheck;
+
abstract public class BaseRecyclerViewInstrumentationTest {
private static final String TAG = "RecyclerViewTest";
@@ -80,7 +81,8 @@
Thread mInstrumentationThread;
@Rule
- public ActivityTestRule<TestActivity> mActivityRule = new ActivityTestRule(TestActivity.class);
+ public ActivityTestRule<TestActivity> mActivityRule =
+ new ActivityTestRule<>(TestActivity.class);
public BaseRecyclerViewInstrumentationTest() {
this(false);
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/helper/ItemTouchHelperTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/helper/ItemTouchHelperTest.java
index 99d1066..6d73fbc 100644
--- a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/helper/ItemTouchHelperTest.java
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/helper/ItemTouchHelperTest.java
@@ -32,7 +32,6 @@
import android.support.test.filters.SdkSuppress;
import android.support.test.filters.Suppress;
import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
import android.support.v4.util.Pair;
import android.support.v7.util.TouchUtils;
import android.support.v7.widget.BaseRecyclerViewInstrumentationTest;
@@ -47,6 +46,8 @@
import java.util.ArrayList;
import java.util.List;
+import androidx.testutils.PollingCheck;
+
@LargeTest
@RunWith(AndroidJUnit4.class)
public class ItemTouchHelperTest extends BaseRecyclerViewInstrumentationTest {
diff --git a/viewpager/api/0.0.0.txt b/viewpager/api/0.0.0.txt
new file mode 100644
index 0000000..31baf49
--- /dev/null
+++ b/viewpager/api/0.0.0.txt
@@ -0,0 +1,125 @@
+package android.support.v4.view {
+
+ public abstract class PagerAdapter {
+ ctor public PagerAdapter();
+ method public void destroyItem(android.view.ViewGroup, int, java.lang.Object);
+ method public deprecated void destroyItem(android.view.View, int, java.lang.Object);
+ method public void finishUpdate(android.view.ViewGroup);
+ method public deprecated void finishUpdate(android.view.View);
+ method public abstract int getCount();
+ method public int getItemPosition(java.lang.Object);
+ method public java.lang.CharSequence getPageTitle(int);
+ method public float getPageWidth(int);
+ method public java.lang.Object instantiateItem(android.view.ViewGroup, int);
+ method public deprecated java.lang.Object instantiateItem(android.view.View, int);
+ method public abstract boolean isViewFromObject(android.view.View, java.lang.Object);
+ method public void notifyDataSetChanged();
+ method public void registerDataSetObserver(android.database.DataSetObserver);
+ method public void restoreState(android.os.Parcelable, java.lang.ClassLoader);
+ method public android.os.Parcelable saveState();
+ method public void setPrimaryItem(android.view.ViewGroup, int, java.lang.Object);
+ method public deprecated void setPrimaryItem(android.view.View, int, java.lang.Object);
+ method public void startUpdate(android.view.ViewGroup);
+ method public deprecated void startUpdate(android.view.View);
+ method public void unregisterDataSetObserver(android.database.DataSetObserver);
+ field public static final int POSITION_NONE = -2; // 0xfffffffe
+ field public static final int POSITION_UNCHANGED = -1; // 0xffffffff
+ }
+
+ public class PagerTabStrip extends android.support.v4.view.PagerTitleStrip {
+ ctor public PagerTabStrip(android.content.Context);
+ ctor public PagerTabStrip(android.content.Context, android.util.AttributeSet);
+ method public boolean getDrawFullUnderline();
+ method public int getTabIndicatorColor();
+ method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public void setDrawFullUnderline(boolean);
+ method public void setTabIndicatorColor(int);
+ method public void setTabIndicatorColorResource(int);
+ }
+
+ public class PagerTitleStrip extends android.view.ViewGroup {
+ ctor public PagerTitleStrip(android.content.Context);
+ ctor public PagerTitleStrip(android.content.Context, android.util.AttributeSet);
+ method public int getTextSpacing();
+ method public void setGravity(int);
+ method public void setNonPrimaryAlpha(float);
+ method public void setTextColor(int);
+ method public void setTextSize(int, float);
+ method public void setTextSpacing(int);
+ }
+
+ public class ViewPager extends android.view.ViewGroup {
+ ctor public ViewPager(android.content.Context);
+ ctor public ViewPager(android.content.Context, android.util.AttributeSet);
+ method public void addOnAdapterChangeListener(android.support.v4.view.ViewPager.OnAdapterChangeListener);
+ method public void addOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+ method public boolean arrowScroll(int);
+ method public boolean beginFakeDrag();
+ method protected boolean canScroll(android.view.View, boolean, int, int, int);
+ method public void clearOnPageChangeListeners();
+ method public void endFakeDrag();
+ method public boolean executeKeyEvent(android.view.KeyEvent);
+ method public void fakeDragBy(float);
+ method public android.support.v4.view.PagerAdapter getAdapter();
+ method public int getCurrentItem();
+ method public int getOffscreenPageLimit();
+ method public int getPageMargin();
+ method public boolean isFakeDragging();
+ method protected void onPageScrolled(int, float, int);
+ method public void onRestoreInstanceState(android.os.Parcelable);
+ method public android.os.Parcelable onSaveInstanceState();
+ method public void removeOnAdapterChangeListener(android.support.v4.view.ViewPager.OnAdapterChangeListener);
+ method public void removeOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+ method public void setAdapter(android.support.v4.view.PagerAdapter);
+ method public void setCurrentItem(int);
+ method public void setCurrentItem(int, boolean);
+ method public void setOffscreenPageLimit(int);
+ method public deprecated void setOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+ method public void setPageMargin(int);
+ method public void setPageMarginDrawable(android.graphics.drawable.Drawable);
+ method public void setPageMarginDrawable(int);
+ method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer);
+ method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer, int);
+ field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
+ field public static final int SCROLL_STATE_IDLE = 0; // 0x0
+ field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
+ }
+
+ public static abstract class ViewPager.DecorView implements java.lang.annotation.Annotation {
+ }
+
+ public static class ViewPager.LayoutParams extends android.view.ViewGroup.LayoutParams {
+ ctor public ViewPager.LayoutParams();
+ ctor public ViewPager.LayoutParams(android.content.Context, android.util.AttributeSet);
+ field public int gravity;
+ field public boolean isDecor;
+ }
+
+ public static abstract interface ViewPager.OnAdapterChangeListener {
+ method public abstract void onAdapterChanged(android.support.v4.view.ViewPager, android.support.v4.view.PagerAdapter, android.support.v4.view.PagerAdapter);
+ }
+
+ public static abstract interface ViewPager.OnPageChangeListener {
+ method public abstract void onPageScrollStateChanged(int);
+ method public abstract void onPageScrolled(int, float, int);
+ method public abstract void onPageSelected(int);
+ }
+
+ public static abstract interface ViewPager.PageTransformer {
+ method public abstract void transformPage(android.view.View, float);
+ }
+
+ public static class ViewPager.SavedState extends android.support.v4.view.AbsSavedState {
+ ctor public ViewPager.SavedState(android.os.Parcelable);
+ field public static final android.os.Parcelable.Creator<android.support.v4.view.ViewPager.SavedState> CREATOR;
+ }
+
+ public static class ViewPager.SimpleOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
+ ctor public ViewPager.SimpleOnPageChangeListener();
+ method public void onPageScrollStateChanged(int);
+ method public void onPageScrolled(int, float, int);
+ method public void onPageSelected(int);
+ }
+
+}
+
diff --git a/viewpager/build.gradle b/viewpager/build.gradle
index fdf3b29..5da06de 100644
--- a/viewpager/build.gradle
+++ b/viewpager/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/viewpager2/build.gradle b/viewpager2/build.gradle
index a4eb3ad..d645f3c 100644
--- a/viewpager2/build.gradle
+++ b/viewpager2/build.gradle
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
}
dependencies {
- api(project(":support-core-utils"))
+ api(project(":support-fragment"))
api(project(":recyclerview-v7"))
androidTestImplementation(TEST_RUNNER)
diff --git a/viewpager2/src/androidTest/AndroidManifest.xml b/viewpager2/src/androidTest/AndroidManifest.xml
index ac723e6..22028ad 100755
--- a/viewpager2/src/androidTest/AndroidManifest.xml
+++ b/viewpager2/src/androidTest/AndroidManifest.xml
@@ -15,10 +15,10 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.widget.viewpager2.test">
+ package="androidx.viewpager2.test">
<uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
<application android:supportsRtl="true">
- <activity android:name="androidx.widget.viewpager2.tests.TestActivity"/>
+ <activity android:name="androidx.viewpager2.widget.tests.TestActivity"/>
</application>
</manifest>
\ No newline at end of file
diff --git a/viewpager2/src/androidTest/java/androidx/widget/viewpager2/tests/TestActivity.java b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/tests/TestActivity.java
similarity index 81%
rename from viewpager2/src/androidTest/java/androidx/widget/viewpager2/tests/TestActivity.java
rename to viewpager2/src/androidTest/java/androidx/viewpager2/widget/tests/TestActivity.java
index 351ad9a..f94d9d6 100644
--- a/viewpager2/src/androidTest/java/androidx/widget/viewpager2/tests/TestActivity.java
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/tests/TestActivity.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package androidx.widget.viewpager2.tests;
+package androidx.viewpager2.widget.tests;
-import android.app.Activity;
import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
-import androidx.widget.viewpager2.test.R;
+import androidx.viewpager2.test.R;
-public class TestActivity extends Activity {
+public class TestActivity extends FragmentActivity {
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/tests/ViewPager2Tests.java b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/tests/ViewPager2Tests.java
new file mode 100644
index 0000000..119256d
--- /dev/null
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/tests/ViewPager2Tests.java
@@ -0,0 +1,571 @@
+/*
+ * 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 androidx.viewpager2.widget.tests;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
+import static android.view.View.OVER_SCROLL_NEVER;
+
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.ViewActions;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.app.Fragment;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.Adapter;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import androidx.viewpager2.test.R;
+import androidx.viewpager2.widget.ViewPager2;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewPager2Tests {
+ private static final Random RANDOM = new Random();
+ private static final int[] sColors = {
+ Color.parseColor("#BBA9FF00"),
+ Color.parseColor("#BB00E87E"),
+ Color.parseColor("#BB00C7FF"),
+ Color.parseColor("#BBB30CE8"),
+ Color.parseColor("#BBFF00D0")};
+
+ @Rule
+ public final ActivityTestRule<TestActivity> mActivityTestRule;
+ @Rule
+ public ExpectedException mExpectedException = ExpectedException.none();
+
+ private ViewPager2 mViewPager;
+
+ // allows to wait until swipe operation is finished (Smooth Scroller done)
+ private CountDownLatch mStableAfterSwipe;
+
+ public ViewPager2Tests() {
+ mActivityTestRule = new ActivityTestRule<>(TestActivity.class);
+ }
+
+ @Before
+ public void setUp() {
+ mViewPager = mActivityTestRule.getActivity().findViewById(R.id.view_pager);
+
+ mViewPager.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+ // coming to idle from another state (dragging or setting) means we're stable now
+ if (newState == SCROLL_STATE_IDLE) {
+ mStableAfterSwipe.countDown();
+ }
+ }
+ });
+
+ final long seed = RANDOM.nextLong();
+ RANDOM.setSeed(seed);
+ Log.i(getClass().getName(), "Random seed: " + seed);
+ }
+
+ public static class PageFragment extends Fragment {
+ private static final String KEY_VALUE = "value";
+
+ public interface EventListener {
+ void onEvent(PageFragment fragment);
+
+ EventListener NO_OP = new EventListener() {
+ @Override
+ public void onEvent(PageFragment fragment) {
+ // do nothing
+ }
+ };
+ }
+
+ private EventListener mOnAttachListener = EventListener.NO_OP;
+ private EventListener mOnDestroyListener = EventListener.NO_OP;
+
+ private int mPosition;
+ private int mValue;
+
+ public static PageFragment create(int position, int value) {
+ PageFragment result = new PageFragment();
+ Bundle args = new Bundle(1);
+ args.putInt(KEY_VALUE, value);
+ result.setArguments(args);
+ result.mPosition = position;
+ return result;
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mOnAttachListener.onEvent(this);
+ }
+
+ @NonNull
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.item_test_layout, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ Bundle data = savedInstanceState != null ? savedInstanceState : getArguments();
+ setValue(data.getInt(KEY_VALUE));
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mOnDestroyListener.onEvent(this);
+ }
+
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ outState.putInt(KEY_VALUE, mValue);
+ }
+
+ public void setValue(int value) {
+ mValue = value;
+ TextView textView = getView().findViewById(R.id.text_view);
+ applyViewValue(textView, mValue);
+ }
+ }
+
+ private static void applyViewValue(TextView textView, int value) {
+ textView.setText(String.valueOf(value));
+ textView.setBackgroundColor(getColor(value));
+ }
+
+ private static int getColor(int value) {
+ return sColors[value % sColors.length];
+ }
+
+ @Test
+ public void fragmentAdapter_fullPass() throws Throwable {
+ testFragmentLifecycle(8, Arrays.asList(1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1, 0));
+ }
+
+ @Test
+ public void fragmentAdapter_random() throws Throwable {
+ final int totalPages = 10;
+ final int sequenceLength = 50;
+ testFragmentLifecycle_random(totalPages, sequenceLength, PageMutator.NO_OP);
+ }
+
+ @Test
+ public void fragmentAdapter_random_withMutations() throws Throwable {
+ final int totalPages = 10;
+ final int sequenceLength = 50;
+ testFragmentLifecycle_random(totalPages, sequenceLength, PageMutator.RANDOM);
+ }
+
+ private void testFragmentLifecycle_random(int totalPages, int sequenceLength,
+ PageMutator pageMutator) throws Throwable {
+ List<Integer> pageSequence = generateRandomPageSequence(totalPages, sequenceLength);
+
+ Log.i(getClass().getName(),
+ String.format("Testing with a sequence [%s]", TextUtils.join(", ", pageSequence)));
+
+ testFragmentLifecycle(totalPages, pageSequence, pageMutator);
+ }
+
+ @NonNull
+ private List<Integer> generateRandomPageSequence(int totalPages, int sequenceLength) {
+ List<Integer> pageSequence = new ArrayList<>(sequenceLength);
+
+ int pageIx = 0;
+ Double goRightProbability = null;
+ while (pageSequence.size() != sequenceLength) {
+ boolean goRight;
+ if (pageIx == 0) {
+ goRight = true;
+ goRightProbability = 0.7;
+ } else if (pageIx == totalPages - 1) { // last page
+ goRight = false;
+ goRightProbability = 0.3;
+ } else {
+ goRight = RANDOM.nextDouble() < goRightProbability;
+ }
+
+ pageSequence.add(goRight ? ++pageIx : --pageIx);
+ }
+
+ return pageSequence;
+ }
+
+ /**
+ * Test added when caught a bug: after the last swipe: actual=6, expected=4
+ * <p>
+ * Bug was caused by an invalid test assumption (new Fragment value can be inferred from number
+ * of instances created) - invalid in a case when we sometimes create Fragments off-screen and
+ * end up scrapping them.
+ **/
+ @Test
+ public void fragmentAdapter_regression1() throws Throwable {
+ testFragmentLifecycle(10, Arrays.asList(1, 2, 3, 2, 1, 2, 3, 4));
+ }
+
+ /**
+ * Test added when caught a bug: after the last swipe: actual=4, expected=5
+ * <p>
+ * Bug was caused by mSavedStates.add(position, ...) instead of mSavedStates.set(position, ...)
+ **/
+ @Test
+ public void fragmentAdapter_regression2() throws Throwable {
+ testFragmentLifecycle(10, Arrays.asList(1, 2, 3, 4, 3, 2, 1, 2, 3, 4, 5));
+ }
+
+ /**
+ * Test added when caught a bug: after the last swipe: ArrayIndexOutOfBoundsException: length=5;
+ * index=-1 at androidx.viewpager2.widget.tests.ViewPager2Tests$PageFragment.onCreateView
+ * <p>
+ * Bug was caused by always saving states of unattached fragments as null (even if there was a
+ * valid previously saved state)
+ */
+ @Test
+ public void fragmentAdapter_regression3() throws Throwable {
+ testFragmentLifecycle(10, Arrays.asList(1, 2, 3, 2, 1, 2, 3, 2, 1, 0));
+ }
+
+ /** Goes left on left edge / right on right edge */
+ @Test
+ public void fragmentAdapter_edges() throws Throwable {
+ testFragmentLifecycle(4, Arrays.asList(0, 0, 1, 2, 3, 3, 3, 2, 1, 0, 0, 0));
+ }
+
+ private interface PageMutator {
+ void mutate(PageFragment fragment);
+
+ PageMutator NO_OP = new PageMutator() {
+ @Override
+ public void mutate(PageFragment fragment) {
+ // do nothing
+ }
+ };
+
+ /** At random modifies the page under Fragment */
+ PageMutator RANDOM = new PageMutator() {
+ @Override
+ public void mutate(PageFragment fragment) {
+ Random random = ViewPager2Tests.RANDOM;
+ if (random.nextDouble() < 0.125) {
+ int delta = (1 + random.nextInt(5)) * sColors.length;
+ fragment.setValue(fragment.mValue + delta);
+ }
+ }
+ };
+ }
+
+ /** @see this#testFragmentLifecycle(int, List, PageMutator) */
+ private void testFragmentLifecycle(final int totalPages, List<Integer> pageSequence)
+ throws Throwable {
+ testFragmentLifecycle(totalPages, pageSequence, PageMutator.NO_OP);
+ }
+
+ /**
+ * Verifies:
+ * <ul>
+ * <li>page content / background
+ * <li>maximum number of Fragments held in memory
+ * <li>Fragment state saving / restoring
+ * </ul>
+ */
+ private void testFragmentLifecycle(final int totalPages, List<Integer> pageSequence,
+ final PageMutator pageMutator) throws Throwable {
+ final AtomicInteger attachCount = new AtomicInteger(0);
+ final AtomicInteger destroyCount = new AtomicInteger(0);
+ final boolean[] wasEverAttached = new boolean[totalPages];
+ final PageFragment[] fragments = new PageFragment[totalPages];
+
+ final int[] expectedValues = new int[totalPages];
+ for (int i = 0; i < totalPages; i++) {
+ expectedValues[i] = i;
+ }
+
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mViewPager.setAdapter(mActivityTestRule.getActivity().getSupportFragmentManager(),
+ new ViewPager2.FragmentProvider() {
+ @Override
+ public Fragment getItem(final int position) {
+ // if the fragment was attached in the past, it means we have
+ // provided it with the correct value already; give a dummy one
+ // to prove state save / restore functionality works
+ int value = wasEverAttached[position] ? -1 : position;
+ PageFragment fragment = PageFragment.create(position, value);
+
+ fragment.mOnAttachListener = new PageFragment.EventListener() {
+ @Override
+ public void onEvent(PageFragment fragment) {
+ attachCount.incrementAndGet();
+ wasEverAttached[fragment.mPosition] = true;
+ }
+ };
+
+ fragment.mOnDestroyListener = new PageFragment.EventListener() {
+ @Override
+ public void onEvent(PageFragment fragment) {
+ destroyCount.incrementAndGet();
+ }
+ };
+
+ fragments[position] = fragment;
+ return fragment;
+ }
+
+ @Override
+ public int getCount() {
+ return totalPages;
+ }
+ }, ViewPager2.FragmentRetentionPolicy.SAVE_STATE);
+ }
+ });
+
+ final AtomicInteger currentPage = new AtomicInteger(0);
+ verifyView(expectedValues[currentPage.get()]);
+ for (int nextPage : pageSequence) {
+ swipe(currentPage.get(), nextPage, totalPages);
+ currentPage.set(nextPage);
+ verifyView(expectedValues[currentPage.get()]);
+
+ // TODO: validate Fragments that are instantiated, but not attached. No destruction
+ // steps are done to them - they're just left to the Garbage Collector. Maybe
+ // WeakReferences could help, but the GC behaviour is not predictable. Alternatively,
+ // we could only create Fragments onAttach, but there is a potential performance
+ // trade-off.
+ assertThat(attachCount.get() - destroyCount.get(), isBetween(1, 4));
+
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final int page = currentPage.get();
+ PageFragment fragment = fragments[page];
+ pageMutator.mutate(fragment);
+ expectedValues[page] = fragment.mValue;
+ }
+ });
+ }
+ }
+
+ private void swipe(int currentPageIx, int nextPageIx, int totalPages)
+ throws InterruptedException {
+ if (nextPageIx >= totalPages) {
+ throw new IllegalArgumentException("Invalid nextPageIx: >= totalPages.");
+ }
+
+ if (currentPageIx == nextPageIx) { // dedicated for testing edge behaviour
+ if (nextPageIx == 0) {
+ swipeRight(); // bounce off the left edge
+ return;
+ }
+ if (nextPageIx == totalPages - 1) { // bounce off the right edge
+ swipeLeft();
+ return;
+ }
+ throw new IllegalArgumentException(
+ "Invalid sequence. Not on an edge, and currentPageIx/nextPageIx pages same.");
+ }
+
+ if (Math.abs(nextPageIx - currentPageIx) > 1) {
+ throw new IllegalArgumentException(
+ "Specified nextPageIx not adjacent to the current page.");
+ }
+
+ if (nextPageIx > currentPageIx) {
+ swipeLeft();
+ } else {
+ swipeRight();
+ }
+ }
+
+ private Matcher<Integer> isBetween(int min, int max) {
+ return allOf(greaterThanOrEqualTo(min), lessThanOrEqualTo(max));
+ }
+
+ @Test
+ public void viewAdapter_rendersAndHandlesSwiping() throws Throwable {
+ final int totalPages = 8;
+
+ if (Build.VERSION.SDK_INT < 16) { // TODO(b/71500143): remove temporary workaround
+ RecyclerView mRecyclerView = (RecyclerView) mViewPager.getChildAt(0);
+ mRecyclerView.setOverScrollMode(OVER_SCROLL_NEVER);
+ }
+
+ onView(withId(mViewPager.getId())).check(matches(isDisplayed()));
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mViewPager.setAdapter(
+ new Adapter<ViewHolder>() {
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+ int viewType) {
+ return new ViewHolder(
+ mActivityTestRule.getActivity().getLayoutInflater().inflate(
+ R.layout.item_test_layout, parent, false)) {
+ };
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ TextView view = (TextView) holder.itemView;
+ applyViewValue(view, position);
+ }
+
+ @Override
+ public int getItemCount() {
+ return totalPages;
+ }
+ });
+ }
+ });
+
+ List<Integer> pageSequence = Arrays.asList(0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 6, 5, 4, 3, 2,
+ 1, 0, 0, 0);
+ verifyView(0);
+ int currentPage = 0;
+ for (int nextPage : pageSequence) {
+ swipe(currentPage, nextPage, totalPages);
+ currentPage = nextPage;
+ verifyView(currentPage);
+ }
+ }
+
+ private void verifyView(int pageNumber) {
+ onView(allOf(withId(R.id.text_view), isDisplayed())).check(
+ matches(allOf(withText(String.valueOf(pageNumber)),
+ new BackgroundColorMatcher(getColor(pageNumber)))));
+ }
+
+ private static class BackgroundColorMatcher extends BaseMatcher<View> {
+ private final int mColor;
+
+ BackgroundColorMatcher(int color) {
+ mColor = color;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("should have background color: ").appendValue(mColor);
+ }
+
+ @Override
+ public boolean matches(Object item) {
+ ColorDrawable background = (ColorDrawable) ((View) item).getBackground();
+ return background.getColor() == mColor;
+ }
+ }
+
+ private void swipeLeft() throws InterruptedException {
+ performSwipe(ViewActions.swipeLeft());
+ }
+
+ private void swipeRight() throws InterruptedException {
+ performSwipe(ViewActions.swipeRight());
+ }
+
+ private void performSwipe(ViewAction swipeAction) throws InterruptedException {
+ mStableAfterSwipe = new CountDownLatch(1);
+ onView(allOf(isDisplayed(), withId(R.id.text_view))).perform(swipeAction);
+ mStableAfterSwipe.await(1, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void itemViewSizeMatchParentEnforced() {
+ mExpectedException.expect(IllegalStateException.class);
+ mExpectedException.expectMessage(
+ "Item's root view must fill the whole ViewPager2 (use match_parent)");
+
+ ViewPager2 viewPager = new ViewPager2(InstrumentationRegistry.getContext());
+ viewPager.setAdapter(new Adapter<ViewHolder>() {
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = new View(parent.getContext());
+ view.setLayoutParams(new ViewGroup.LayoutParams(50, 50)); // arbitrary fixed size
+ return new ViewHolder(view) {
+ };
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ // do nothing
+ }
+
+ @Override
+ public int getItemCount() {
+ return 1;
+ }
+ });
+
+ viewPager.measure(0, 0); // equivalent of unspecified
+ }
+
+ @Test
+ public void childrenNotAllowed() throws Exception {
+ mExpectedException.expect(IllegalStateException.class);
+ mExpectedException.expectMessage("ViewPager2 does not support direct child views");
+
+ Context context = InstrumentationRegistry.getContext();
+ ViewPager2 viewPager = new ViewPager2(context);
+ viewPager.addView(new View(context));
+ }
+
+ // TODO: verify correct padding behavior
+ // TODO: add test for screen orientation change
+ // TODO: port some of the fragment adapter tests as view adapter tests
+}
diff --git a/viewpager2/src/androidTest/java/androidx/widget/viewpager2/tests/ViewPager2Tests.java b/viewpager2/src/androidTest/java/androidx/widget/viewpager2/tests/ViewPager2Tests.java
deleted file mode 100644
index 45b42aa..0000000
--- a/viewpager2/src/androidTest/java/androidx/widget/viewpager2/tests/ViewPager2Tests.java
+++ /dev/null
@@ -1,214 +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 androidx.widget.viewpager2.tests;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
-import static android.support.v7.widget.RecyclerView.SCROLL_STATE_SETTLING;
-import static android.view.View.OVER_SCROLL_NEVER;
-
-import static org.hamcrest.CoreMatchers.allOf;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.espresso.IdlingRegistry;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.action.ViewActions;
-import android.support.test.espresso.idling.CountingIdlingResource;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.Adapter;
-import android.support.v7.widget.RecyclerView.ViewHolder;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-
-import androidx.widget.ViewPager2;
-import androidx.widget.viewpager2.test.R;
-
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class ViewPager2Tests {
- private static final int[] sColors = {
- Color.parseColor("#BBA9FF00"),
- Color.parseColor("#BB00E87E"),
- Color.parseColor("#BB00C7FF"),
- Color.parseColor("#BBB30CE8"),
- Color.parseColor("#BBFF00D0")};
-
- @Rule
- public final ActivityTestRule<TestActivity> mActivityTestRule;
- @Rule
- public ExpectedException mExpectedException = ExpectedException.none();
-
- private ViewPager2 mViewPager;
- private CountingIdlingResource mIdlingResource;
-
- public ViewPager2Tests() {
- mActivityTestRule = new ActivityTestRule<>(TestActivity.class);
- }
-
- @Before
- public void setUp() {
- mViewPager = mActivityTestRule.getActivity().findViewById(R.id.view_pager);
-
- mIdlingResource = new CountingIdlingResource(getClass().getSimpleName() + "IdlingResource");
- mViewPager.addOnScrollListener(new RecyclerView.OnScrollListener() {
- @Override
- public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
- if (newState == SCROLL_STATE_IDLE && !mIdlingResource.isIdleNow()) {
- mIdlingResource.decrement();
- } else if (newState == SCROLL_STATE_SETTLING && mIdlingResource.isIdleNow()) {
- mIdlingResource.increment();
- }
- }
- });
- IdlingRegistry.getInstance().register(mIdlingResource);
- }
-
- @After
- public void tearDown() {
- IdlingRegistry.getInstance().unregister(mIdlingResource);
- }
-
- @Test
- public void rendersAndHandlesSwiping() throws Throwable {
- final int pageCount = sColors.length;
-
- if (Build.VERSION.SDK_INT < 16) { // TODO(b/71500143): remove temporary workaround
- RecyclerView mRecyclerView = (RecyclerView) mViewPager.getChildAt(0);
- mRecyclerView.setOverScrollMode(OVER_SCROLL_NEVER);
- }
-
- onView(withId(mViewPager.getId())).check(matches(isDisplayed()));
- mActivityTestRule.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mViewPager.setAdapter(
- new Adapter<ViewHolder>() {
- @NonNull
- @Override
- public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
- int viewType) {
- return new ViewHolder(
- mActivityTestRule.getActivity().getLayoutInflater().inflate(
- R.layout.item_test_layout, parent, false)) {
- };
- }
-
- @Override
- public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
- TextView view = (TextView) holder.itemView;
- view.setText(String.valueOf(position));
- view.setBackgroundColor(sColors[position]);
- }
-
- @Override
- public int getItemCount() {
- return pageCount;
- }
- });
- }
- });
-
- final int pageIxFirst = 0;
- final int pageIxLast = pageCount - 1;
- final int swipeCount = pageCount + 1; // two swipes beyond edge to test 'edge behavior'
- int pageNumber = pageIxFirst;
- for (int i = 0; i < swipeCount; i++, pageNumber = Math.min(pageIxLast, ++pageNumber)) {
- verifyView(pageNumber);
- performSwipe(ViewActions.swipeLeft());
- }
- assertThat(pageNumber, equalTo(pageIxLast));
- for (int i = 0; i < swipeCount; i++, pageNumber = Math.max(pageIxFirst, --pageNumber)) {
- verifyView(pageNumber);
- performSwipe(ViewActions.swipeRight());
- }
- assertThat(pageNumber, equalTo(pageIxFirst));
- }
-
- private void verifyView(int pageNumber) {
- onView(allOf(withId(R.id.text_view), isDisplayed())).check(
- matches(withText(String.valueOf(pageNumber))));
- }
-
- private void performSwipe(ViewAction swipeAction) throws InterruptedException {
- onView(allOf(isDisplayed(), withId(R.id.text_view))).perform(swipeAction);
- }
-
- @Test
- public void itemViewSizeMatchParentEnforced() {
- mExpectedException.expect(IllegalStateException.class);
- mExpectedException.expectMessage(
- "Item's root view must fill the whole ViewPager2 (use match_parent)");
-
- ViewPager2 viewPager = new ViewPager2(InstrumentationRegistry.getContext());
- viewPager.setAdapter(new Adapter<ViewHolder>() {
- @NonNull
- @Override
- public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- View view = new View(parent.getContext());
- view.setLayoutParams(new ViewGroup.LayoutParams(50, 50)); // arbitrary fixed size
- return new ViewHolder(view) {
- };
- }
-
- @Override
- public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
- // do nothing
- }
-
- @Override
- public int getItemCount() {
- return 1;
- }
- });
-
- viewPager.measure(0, 0); // equivalent of unspecified
- }
-
- @Test
- public void childrenNotAllowed() throws Exception {
- mExpectedException.expect(IllegalStateException.class);
- mExpectedException.expectMessage("ViewPager2 does not support direct child views");
-
- Context context = InstrumentationRegistry.getContext();
- ViewPager2 viewPager = new ViewPager2(context);
- viewPager.addView(new View(context));
- }
-
- // TODO: verify correct padding behavior
- // TODO: add test for screen orientation change
-}
diff --git a/viewpager2/src/androidTest/res/layout/activity_test_layout.xml b/viewpager2/src/androidTest/res/layout/activity_test_layout.xml
index 3037029..9d996ab 100644
--- a/viewpager2/src/androidTest/res/layout/activity_test_layout.xml
+++ b/viewpager2/src/androidTest/res/layout/activity_test_layout.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<androidx.widget.ViewPager2
+<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/view_pager"
android:layout_width="match_parent"
diff --git a/viewpager2/src/main/AndroidManifest.xml b/viewpager2/src/main/AndroidManifest.xml
index ebddd6c..cc03d91 100644
--- a/viewpager2/src/main/AndroidManifest.xml
+++ b/viewpager2/src/main/AndroidManifest.xml
@@ -14,4 +14,4 @@
limitations under the License.
-->
-<manifest package="androidx.widget.viewpager2"/>
\ No newline at end of file
+<manifest package="androidx.viewpager2"/>
\ No newline at end of file
diff --git a/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java b/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
new file mode 100644
index 0000000..ba40912
--- /dev/null
+++ b/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
@@ -0,0 +1,358 @@
+/*
+ * 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 androidx.viewpager2.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.support.annotation.RestrictTo;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.app.FragmentStatePagerAdapter;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.PagerSnapHelper;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.Adapter;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import java.lang.annotation.Retention;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Work in progress: go/viewpager2
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public class ViewPager2 extends ViewGroup {
+ // reused in layout(...)
+ private final Rect mTmpContainerRect = new Rect();
+ private final Rect mTmpChildRect = new Rect();
+
+ private RecyclerView mRecyclerView;
+
+ public ViewPager2(Context context) {
+ super(context);
+ initialize(context);
+ }
+
+ public ViewPager2(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ViewPager2(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initialize(context);
+ }
+
+ @RequiresApi(21)
+ public ViewPager2(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ // TODO(b/70663531): handle attrs, defStyleAttr, defStyleRes
+ super(context, attrs, defStyleAttr, defStyleRes);
+ initialize(context);
+ }
+
+ private void initialize(Context context) {
+ mRecyclerView = new RecyclerView(context);
+
+ LinearLayoutManager layoutManager = new LinearLayoutManager(context);
+ // TODO(b/69103581): add support for vertical layout
+ // TODO(b/69398856): add support for RTL
+ layoutManager.setOrientation(RecyclerView.HORIZONTAL);
+ mRecyclerView.setLayoutManager(layoutManager);
+
+ mRecyclerView.setLayoutParams(
+ new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+
+ // TODO(b/70666992): add automated test for orientation change
+ new PagerSnapHelper().attachToRecyclerView(mRecyclerView);
+
+ attachViewToParent(mRecyclerView, 0, mRecyclerView.getLayoutParams());
+ }
+
+ /**
+ * TODO(b/70663708): decide on an Adapter class. Here supporting RecyclerView.Adapter.
+ *
+ * @see RecyclerView#setAdapter(Adapter)
+ */
+ public <VH extends ViewHolder> void setAdapter(final Adapter<VH> adapter) {
+ mRecyclerView.setAdapter(new Adapter<VH>() {
+ private final Adapter<VH> mAdapter = adapter;
+
+ @NonNull
+ @Override
+ public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ VH viewHolder = mAdapter.onCreateViewHolder(parent, viewType);
+
+ LayoutParams layoutParams = viewHolder.itemView.getLayoutParams();
+ if (layoutParams.width != LayoutParams.MATCH_PARENT
+ || layoutParams.height != LayoutParams.MATCH_PARENT) {
+ // TODO(b/70666614): decide if throw an exception or wrap in FrameLayout
+ // ourselves; consider accepting exact size equal to parent's exact size
+ throw new IllegalStateException(String.format(
+ "Item's root view must fill the whole %s (use match_parent)",
+ ViewPager2.this.getClass().getSimpleName()));
+ }
+
+ return viewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull VH holder, int position) {
+ mAdapter.onBindViewHolder(holder, position);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mAdapter.getItemCount();
+ }
+ });
+ }
+
+ /**
+ * TODO(b/70663708): decide on an Adapter class. Here supporting {@link Fragment}s.
+ *
+ * @param fragmentRetentionPolicy allows for future parameterization of Fragment memory
+ * strategy, similar to what {@link FragmentPagerAdapter} and
+ * {@link FragmentStatePagerAdapter} provide.
+ */
+ public void setAdapter(FragmentManager fragmentManager, FragmentProvider fragmentProvider,
+ @FragmentRetentionPolicy int fragmentRetentionPolicy) {
+ if (fragmentRetentionPolicy != FragmentRetentionPolicy.SAVE_STATE) {
+ throw new IllegalArgumentException("Currently only SAVE_STATE policy is supported");
+ }
+
+ mRecyclerView.setAdapter(new FragmentStateAdapter(fragmentManager, fragmentProvider));
+ }
+
+ /**
+ * Similar in behavior to {@link FragmentStatePagerAdapter}
+ * <p>
+ * Lifecycle within {@link RecyclerView}:
+ * <ul>
+ * <li>{@link RecyclerView.ViewHolder} initially an empty {@link FrameLayout}, serves as a
+ * re-usable container for a {@link Fragment} in later stages.
+ * <li>{@link RecyclerView.Adapter#onBindViewHolder} we ask for a {@link Fragment} for the
+ * position. If we already have the fragment, or have previously saved its state, we use those.
+ * <li>{@link RecyclerView.Adapter#onAttachedToWindow} we attach the {@link Fragment} to a
+ * container.
+ * <li>{@link RecyclerView.Adapter#onViewRecycled} and
+ * {@link RecyclerView.Adapter#onFailedToRecycleView} we remove, save state, destroy the
+ * {@link Fragment}.
+ * </ul>
+ */
+ private static class FragmentStateAdapter extends RecyclerView.Adapter<FragmentViewHolder> {
+ private final List<Fragment.SavedState> mSavedStates = new ArrayList<>();
+ // TODO: handle current item's menuVisibility userVisibleHint as FragmentStatePagerAdapter
+
+ private final FragmentManager mFragmentManager;
+ private final FragmentProvider mFragmentProvider;
+
+ private FragmentStateAdapter(FragmentManager fragmentManager,
+ FragmentProvider fragmentProvider) {
+ this.mFragmentManager = fragmentManager;
+ this.mFragmentProvider = fragmentProvider;
+ }
+
+ @NonNull
+ @Override
+ public FragmentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return FragmentViewHolder.create(parent);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull FragmentViewHolder holder, int position) {
+ if (ViewCompat.isAttachedToWindow(holder.getContainer())) {
+ // this should never happen; if it does, it breaks our assumption that attaching
+ // a Fragment can reliably happen inside onViewAttachedToWindow
+ throw new IllegalStateException(
+ String.format("View %s unexpectedly attached to a window.",
+ holder.getContainer()));
+ }
+
+ holder.mFragment = getFragment(position);
+ }
+
+ private Fragment getFragment(int position) {
+ Fragment fragment = mFragmentProvider.getItem(position);
+ if (mSavedStates.size() > position) {
+ Fragment.SavedState savedState = mSavedStates.get(position);
+ if (savedState != null) {
+ fragment.setInitialSavedState(savedState);
+ }
+ }
+ return fragment;
+ }
+
+ @Override
+ public void onViewAttachedToWindow(@NonNull FragmentViewHolder holder) {
+ if (holder.mFragment.isAdded()) {
+ return;
+ }
+ mFragmentManager.beginTransaction().add(holder.getContainer().getId(),
+ holder.mFragment).commitNowAllowingStateLoss();
+ }
+
+ @Override
+ public int getItemCount() {
+ return mFragmentProvider.getCount();
+ }
+
+ @Override
+ public void onViewRecycled(@NonNull FragmentViewHolder holder) {
+ removeFragment(holder);
+ }
+
+ @Override
+ public boolean onFailedToRecycleView(@NonNull FragmentViewHolder holder) {
+ // This happens when a ViewHolder is in a transient state (e.g. during custom
+ // animation). We don't have sufficient information on how to clear up what lead to
+ // the transient state, so we are throwing away the ViewHolder to stay on the
+ // conservative side.
+ removeFragment(holder);
+ return false; // don't recycle the view
+ }
+
+ private void removeFragment(@NonNull FragmentViewHolder holder) {
+ if (holder.mFragment == null) {
+ return; // fresh ViewHolder, nothing to do
+ }
+
+ int position = holder.getAdapterPosition();
+
+ if (holder.mFragment.isAdded()) {
+ while (mSavedStates.size() <= position) {
+ mSavedStates.add(null);
+ }
+ mSavedStates.set(position,
+ mFragmentManager.saveFragmentInstanceState(holder.mFragment));
+ }
+
+ mFragmentManager.beginTransaction().remove(
+ holder.mFragment).commitNowAllowingStateLoss();
+ holder.mFragment = null;
+ }
+ }
+
+ private static class FragmentViewHolder extends RecyclerView.ViewHolder {
+ private Fragment mFragment;
+
+ private FragmentViewHolder(FrameLayout container) {
+ super(container);
+ }
+
+ static FragmentViewHolder create(ViewGroup parent) {
+ FrameLayout container = new FrameLayout(parent.getContext());
+ container.setLayoutParams(
+ new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ container.setId(ViewCompat.generateViewId());
+ return new FragmentViewHolder(container);
+ }
+
+ FrameLayout getContainer() {
+ return (FrameLayout) itemView;
+ }
+ }
+
+ /**
+ * Provides {@link Fragment}s for pages
+ */
+ public interface FragmentProvider {
+ /**
+ * Return the Fragment associated with a specified position.
+ */
+ Fragment getItem(int position);
+
+ /**
+ * Return the number of pages available.
+ */
+ int getCount();
+ }
+
+ @Retention(CLASS)
+ @IntDef({FragmentRetentionPolicy.SAVE_STATE})
+ public @interface FragmentRetentionPolicy {
+ /** Approach similar to {@link FragmentStatePagerAdapter} */
+ int SAVE_STATE = 0;
+ }
+
+ @Override
+ public void onViewAdded(View child) {
+ // TODO(b/70666620): consider adding a support for Decor views
+ throw new IllegalStateException(
+ getClass().getSimpleName() + " does not support direct child views");
+ }
+
+ /** @see RecyclerView#addOnScrollListener(RecyclerView.OnScrollListener) */
+ public void addOnScrollListener(RecyclerView.OnScrollListener listener) {
+ mRecyclerView.addOnScrollListener(listener);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // TODO(b/70666622): consider margin support
+ // TODO(b/70666626): consider delegating all this to RecyclerView
+ // TODO(b/70666625): write automated tests for this
+
+ measureChild(mRecyclerView, widthMeasureSpec, heightMeasureSpec);
+ int width = mRecyclerView.getMeasuredWidth();
+ int height = mRecyclerView.getMeasuredHeight();
+ int childState = mRecyclerView.getMeasuredState();
+
+ width += getPaddingLeft() + getPaddingRight();
+ height += getPaddingTop() + getPaddingBottom();
+
+ width = Math.max(width, getSuggestedMinimumWidth());
+ height = Math.max(height, getSuggestedMinimumHeight());
+
+ setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, childState),
+ resolveSizeAndState(height, heightMeasureSpec,
+ childState << MEASURED_HEIGHT_STATE_SHIFT));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ int width = mRecyclerView.getMeasuredWidth();
+ int height = mRecyclerView.getMeasuredHeight();
+
+ // TODO(b/70666626): consider delegating padding handling to the RecyclerView to avoid
+ // an unnatural page transition effect: http://shortn/_Vnug3yZpQT
+ mTmpContainerRect.left = getPaddingLeft();
+ mTmpContainerRect.right = r - l - getPaddingRight();
+ mTmpContainerRect.top = getPaddingTop();
+ mTmpContainerRect.bottom = b - t - getPaddingBottom();
+
+ Gravity.apply(Gravity.TOP | Gravity.START, width, height, mTmpContainerRect, mTmpChildRect);
+ mRecyclerView.layout(mTmpChildRect.left, mTmpChildRect.top, mTmpChildRect.right,
+ mTmpChildRect.bottom);
+ }
+}
diff --git a/viewpager2/src/main/java/androidx/widget/ViewPager2.java b/viewpager2/src/main/java/androidx/widget/ViewPager2.java
deleted file mode 100644
index 9ebdea1..0000000
--- a/viewpager2/src/main/java/androidx/widget/ViewPager2.java
+++ /dev/null
@@ -1,176 +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 androidx.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RestrictTo;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.PagerSnapHelper;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.Adapter;
-import android.support.v7.widget.RecyclerView.ViewHolder;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-
-/**
- * Work in progress: go/viewpager2
- *
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class ViewPager2 extends ViewGroup {
- // reused in layout(...)
- private final Rect mTmpContainerRect = new Rect();
- private final Rect mTmpChildRect = new Rect();
-
- private RecyclerView mRecyclerView;
-
- public ViewPager2(Context context) {
- super(context);
- initialize(context);
- }
-
- public ViewPager2(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ViewPager2(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- initialize(context);
- }
-
- @RequiresApi(21)
- public ViewPager2(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- // TODO(b/70663531): handle attrs, defStyleAttr, defStyleRes
- super(context, attrs, defStyleAttr, defStyleRes);
- initialize(context);
- }
-
- private void initialize(Context context) {
- mRecyclerView = new RecyclerView(context);
-
- LinearLayoutManager layoutManager = new LinearLayoutManager(context);
- // TODO(b/69103581): add support for vertical layout
- // TODO(b/69398856): add support for RTL
- layoutManager.setOrientation(RecyclerView.HORIZONTAL);
- mRecyclerView.setLayoutManager(layoutManager);
-
- mRecyclerView.setLayoutParams(
- new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
-
- // TODO(b/70666992): add automated test for orientation change
- new PagerSnapHelper().attachToRecyclerView(mRecyclerView);
-
- attachViewToParent(mRecyclerView, 0, mRecyclerView.getLayoutParams());
- }
-
- /**
- * TODO(b/70663708): decide on an Adapter class (for now reusing RecyclerView.Adapter)
- *
- * @see RecyclerView#setAdapter(Adapter)
- */
- public <VH extends ViewHolder> void setAdapter(final Adapter<VH> adapter) {
- mRecyclerView.setAdapter(new Adapter<VH>() {
- private final Adapter<VH> mAdapter = adapter;
-
- @NonNull
- @Override
- public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- VH viewHolder = mAdapter.onCreateViewHolder(parent, viewType);
-
- LayoutParams layoutParams = viewHolder.itemView.getLayoutParams();
- if ((layoutParams.width | layoutParams.height) != LayoutParams.MATCH_PARENT) {
- // TODO(b/70666614): decide if throw an exception or wrap in FrameLayout
- // ourselves; consider accepting exact size equal to parent's exact size
- throw new IllegalStateException(String.format(
- "Item's root view must fill the whole %s (use match_parent)",
- ViewPager2.this.getClass().getSimpleName()));
- }
-
- return viewHolder;
- }
-
- @Override
- public void onBindViewHolder(@NonNull VH holder, int position) {
- mAdapter.onBindViewHolder(holder, position);
- }
-
- @Override
- public int getItemCount() {
- return mAdapter.getItemCount();
- }
- });
- }
-
- @Override
- public void onViewAdded(View child) {
- // TODO(b/70666620): consider adding a support for Decor views
- throw new IllegalStateException(
- getClass().getSimpleName() + " does not support direct child views");
- }
-
- /** @see RecyclerView#addOnScrollListener(RecyclerView.OnScrollListener) */
- public void addOnScrollListener(RecyclerView.OnScrollListener listener) {
- mRecyclerView.addOnScrollListener(listener);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // TODO(b/70666622): consider margin support
- // TODO(b/70666626): consider delegating all this to RecyclerView
- // TODO(b/70666625): write automated tests for this
-
- measureChild(mRecyclerView, widthMeasureSpec, heightMeasureSpec);
- int width = mRecyclerView.getMeasuredWidth();
- int height = mRecyclerView.getMeasuredHeight();
- int childState = mRecyclerView.getMeasuredState();
-
- width += getPaddingLeft() + getPaddingRight();
- height += getPaddingTop() + getPaddingBottom();
-
- width = Math.max(width, getSuggestedMinimumWidth());
- height = Math.max(height, getSuggestedMinimumHeight());
-
- setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, childState),
- resolveSizeAndState(height, heightMeasureSpec,
- childState << MEASURED_HEIGHT_STATE_SHIFT));
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int width = mRecyclerView.getMeasuredWidth();
- int height = mRecyclerView.getMeasuredHeight();
-
- // TODO(b/70666626): consider delegating padding handling to the RecyclerView to avoid
- // an unnatural page transition effect: http://shortn/_Vnug3yZpQT
- mTmpContainerRect.left = getPaddingLeft();
- mTmpContainerRect.right = r - l - getPaddingRight();
- mTmpContainerRect.top = getPaddingTop();
- mTmpContainerRect.bottom = b - t - getPaddingBottom();
-
- Gravity.apply(Gravity.TOP | Gravity.START, width, height, mTmpContainerRect, mTmpChildRect);
- mRecyclerView.layout(mTmpChildRect.left, mTmpChildRect.top, mTmpChildRect.right,
- mTmpChildRect.bottom);
- }
-}
diff --git a/wear/build.gradle b/wear/build.gradle
index 2b832e7..ffc7990 100644
--- a/wear/build.gradle
+++ b/wear/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/webkit-codegen/build.gradle b/webkit-codegen/build.gradle
index 92090e1..891382b 100644
--- a/webkit-codegen/build.gradle
+++ b/webkit-codegen/build.gradle
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
apply plugin: 'maven'
apply plugin: 'application'
diff --git a/webkit/api/current.txt b/webkit/api/current.txt
index b0d66d6..2a39d42 100644
--- a/webkit/api/current.txt
+++ b/webkit/api/current.txt
@@ -1,7 +1,19 @@
package androidx.webkit {
+ public class WebSettingsCompat {
+ method public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
+ method public static boolean getOffscreenPreRaster(android.webkit.WebSettings);
+ method public static boolean getSafeBrowsingEnabled(android.webkit.WebSettings);
+ method public static void setDisabledActionModeMenuItems(android.webkit.WebSettings, int);
+ method public static void setOffscreenPreRaster(android.webkit.WebSettings, boolean);
+ method public static void setSafeBrowsingEnabled(android.webkit.WebSettings, boolean);
+ }
+
public class WebViewCompat {
+ method public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
method public static void postVisualStateCallback(android.webkit.WebView, long, androidx.webkit.WebViewCompat.VisualStateCallback);
+ method public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String>, android.webkit.ValueCallback<java.lang.Boolean>);
+ method public static void startSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
}
public static abstract interface WebViewCompat.VisualStateCallback {
diff --git a/webkit/build.gradle b/webkit/build.gradle
index 6e099e1..b74fa88 100644
--- a/webkit/build.gradle
+++ b/webkit/build.gradle
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
plugins {
id("SupportAndroidLibraryPlugin")
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java b/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java
new file mode 100644
index 0000000..1e5c152
--- /dev/null
+++ b/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Build;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.webkit.WebSettings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class WebSettingsCompatTest {
+ WebViewOnUiThread mWebViewOnUiThread;
+
+ @Before
+ public void setUp() {
+ mWebViewOnUiThread = new androidx.webkit.WebViewOnUiThread();
+ }
+
+ @Test
+ public void testOffscreenPreRaster() {
+ // TODO(gsennton) activate this test for pre-M devices when we can pre-install a WebView APK
+ // containing support for the WebView Support Library, see b/73454652.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;
+
+ assertFalse(WebSettingsCompat.getOffscreenPreRaster(mWebViewOnUiThread.getSettings()));
+
+ WebSettingsCompat.setOffscreenPreRaster(mWebViewOnUiThread.getSettings(), true);
+ assertTrue(WebSettingsCompat.getOffscreenPreRaster(mWebViewOnUiThread.getSettings()));
+ }
+
+ @Test
+ public void testEnableSafeBrowsing() throws Throwable {
+ // TODO(gsennton) activate this test for old devices when we can pre-install a WebView APK
+ // containing support for the WebView Support Library, see b/73454652.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
+
+ WebSettingsCompat.setSafeBrowsingEnabled(mWebViewOnUiThread.getSettings(), false);
+ assertFalse(WebSettingsCompat.getSafeBrowsingEnabled(mWebViewOnUiThread.getSettings()));
+ }
+
+ @Test
+ public void testDisabledActionModeMenuItems() throws Throwable {
+ // TODO(gsennton) activate this test for old devices when we can pre-install a WebView APK
+ // containing support for the WebView Support Library, see b/73454652.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return;
+
+ assertEquals(WebSettings.MENU_ITEM_NONE,
+ WebSettingsCompat.getDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings()));
+
+ WebSettingsCompat.setDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings(),
+ WebSettings.MENU_ITEM_SHARE);
+ assertEquals(WebSettings.MENU_ITEM_SHARE,
+ WebSettingsCompat.getDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings()));
+
+ WebSettingsCompat.setDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings(),
+ WebSettings.MENU_ITEM_PROCESS_TEXT | WebSettings.MENU_ITEM_WEB_SEARCH);
+ assertEquals(WebSettings.MENU_ITEM_PROCESS_TEXT | WebSettings.MENU_ITEM_WEB_SEARCH,
+ WebSettingsCompat.getDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings()));
+ }
+}
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java b/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
index 8b38d99..a9ffead 100644
--- a/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
+++ b/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
@@ -17,20 +17,38 @@
package androidx.webkit;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.os.Build;
+import android.os.Looper;
+import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.v4.os.BuildCompat;
+import android.webkit.SafeBrowsingResponse;
+import android.webkit.ValueCallback;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+@MediumTest
@RunWith(AndroidJUnit4.class)
public class WebViewCompatTest {
WebViewOnUiThread mWebViewOnUiThread;
@@ -42,7 +60,6 @@
mWebViewOnUiThread = new androidx.webkit.WebViewOnUiThread();
}
- @MediumTest
@Test
public void testVisualStateCallbackCalled() throws Exception {
// TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
@@ -65,7 +82,6 @@
assertTrue(callbackLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
}
- @MediumTest
@Test
public void testCheckThread() {
try {
@@ -80,4 +96,142 @@
}
fail("Calling a WebViewCompat method on the wrong thread must cause a run-time exception");
}
+
+ private static class MockContext extends ContextWrapper {
+ private boolean mGetApplicationContextWasCalled;
+
+ MockContext(Context context) {
+ super(context);
+ }
+
+ public Context getApplicationContext() {
+ mGetApplicationContextWasCalled = true;
+ return super.getApplicationContext();
+ }
+
+ public boolean wasGetApplicationContextCalled() {
+ return mGetApplicationContextWasCalled;
+ }
+ }
+
+ @Test
+ public void testStartSafeBrowsingUseApplicationContext() throws Exception {
+ // TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
+ // containing support for the WebView Support Library, see b/73454652.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return;
+
+ final MockContext ctx =
+ new MockContext(InstrumentationRegistry.getTargetContext().getApplicationContext());
+ final CountDownLatch resultLatch = new CountDownLatch(1);
+ WebViewCompat.startSafeBrowsing(ctx, new ValueCallback<Boolean>() {
+ @Override
+ public void onReceiveValue(Boolean value) {
+ assertTrue(ctx.wasGetApplicationContextCalled());
+ resultLatch.countDown();
+ return;
+ }
+ });
+ assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testStartSafeBrowsingWithNullCallbackDoesntCrash() throws Exception {
+ // TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
+ // containing support for the WebView Support Library, see b/73454652.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return;
+
+ WebViewCompat.startSafeBrowsing(InstrumentationRegistry.getTargetContext(), null);
+ }
+
+ @Test
+ public void testStartSafeBrowsingInvokesCallback() throws Exception {
+ // TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
+ // containing support for the WebView Support Library, see b/73454652.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return;
+
+ final CountDownLatch resultLatch = new CountDownLatch(1);
+ WebViewCompat.startSafeBrowsing(
+ InstrumentationRegistry.getTargetContext().getApplicationContext(),
+ new ValueCallback<Boolean>() {
+ @Override
+ public void onReceiveValue(Boolean value) {
+ assertTrue(Looper.getMainLooper().isCurrentThread());
+ resultLatch.countDown();
+ return;
+ }
+ });
+ assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testSetSafeBrowsingWhitelistWithMalformedList() throws Exception {
+ // TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
+ // containing support for the WebView Support Library, see b/73454652.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return;
+
+ List whitelist = new ArrayList<String>();
+ // Protocols are not supported in the whitelist
+ whitelist.add("http://google.com");
+ final CountDownLatch resultLatch = new CountDownLatch(1);
+ WebViewCompat.setSafeBrowsingWhitelist(whitelist, new ValueCallback<Boolean>() {
+ @Override
+ public void onReceiveValue(Boolean success) {
+ assertFalse(success);
+ resultLatch.countDown();
+ }
+ });
+ assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testSetSafeBrowsingWhitelistWithValidList() throws Exception {
+ // TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
+ // containing support for the WebView Support Library, see b/73454652.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return;
+
+ List whitelist = new ArrayList<String>();
+ whitelist.add("safe-browsing");
+ final CountDownLatch resultLatch = new CountDownLatch(1);
+ WebViewCompat.setSafeBrowsingWhitelist(whitelist, new ValueCallback<Boolean>() {
+ @Override
+ public void onReceiveValue(Boolean success) {
+ assertTrue(success);
+ resultLatch.countDown();
+ }
+ });
+ assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+
+ final CountDownLatch resultLatch2 = new CountDownLatch(1);
+ mWebViewOnUiThread.setWebViewClient(new WebViewClient() {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ resultLatch2.countDown();
+ }
+
+ @Override
+ public void onSafeBrowsingHit(WebView view, WebResourceRequest request, int threatType,
+ SafeBrowsingResponse callback) {
+ Assert.fail("Should not invoke onSafeBrowsingHit");
+ }
+ });
+
+ mWebViewOnUiThread.loadUrl("chrome://safe-browsing/match?type=malware");
+
+ // Wait until page load has completed
+ assertTrue(resultLatch2.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testGetSafeBrowsingPrivacyPolicyUrl() throws Exception {
+ // TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
+ // containing support for the WebView Support Library, see b/73454652.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return;
+
+ assertNotNull(WebViewCompat.getSafeBrowsingPrivacyPolicyUrl());
+ try {
+ new URL(WebViewCompat.getSafeBrowsingPrivacyPolicyUrl().toString());
+ } catch (MalformedURLException e) {
+ Assert.fail("The privacy policy URL should be a well-formed URL");
+ }
+ }
}
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java b/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
index 6219bd3..9b4c9e9 100644
--- a/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
+++ b/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
@@ -17,7 +17,9 @@
package androidx.webkit;
import android.support.test.InstrumentationRegistry;
+import android.webkit.WebSettings;
import android.webkit.WebView;
+import android.webkit.WebViewClient;
public class WebViewOnUiThread {
private WebView mWebView;
@@ -40,6 +42,15 @@
});
}
+ public void setWebViewClient(final WebViewClient webviewClient) {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mWebView.setWebViewClient(webviewClient);
+ }
+ });
+ }
+
public void postVisualStateCallbackCompat(final long requestId,
final WebViewCompat.VisualStateCallback callback) {
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@@ -50,7 +61,36 @@
});
}
+ public WebSettings getSettings() {
+ return getValue(new ValueGetter<WebSettings>() {
+ @Override
+ public WebSettings capture() {
+ return mWebView.getSettings();
+ }
+ });
+ }
+
public WebView getWebViewOnCurrentThread() {
return mWebView;
}
+
+ private <T> T getValue(ValueGetter<T> getter) {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(getter);
+ return getter.getValue();
+ }
+
+ private abstract class ValueGetter<T> implements Runnable {
+ private T mValue;
+
+ @Override
+ public void run() {
+ mValue = capture();
+ }
+
+ protected abstract T capture();
+
+ public T getValue() {
+ return mValue;
+ }
+ }
}
diff --git a/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java b/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
new file mode 100644
index 0000000..c73cda6
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit;
+
+import android.os.Build;
+import android.webkit.WebSettings;
+
+import androidx.webkit.internal.WebSettingsAdapter;
+import androidx.webkit.internal.WebViewGlueCommunicator;
+
+/**
+ * Compatibility version of {@link android.webkit.WebSettings}
+ */
+public class WebSettingsCompat {
+ private WebSettingsCompat() {}
+
+ // TODO(gsennton): add feature detection
+
+ /**
+ * Sets whether this WebView should raster tiles when it is
+ * offscreen but attached to a window. Turning this on can avoid
+ * rendering artifacts when animating an offscreen WebView on-screen.
+ * Offscreen WebViews in this mode use more memory. The default value is
+ * false.<br>
+ * Please follow these guidelines to limit memory usage:
+ * <ul>
+ * <li> WebView size should be not be larger than the device screen size.
+ * <li> Limit use of this mode to a small number of WebViews. Use it for
+ * visible WebViews and WebViews about to be animated to visible.
+ * </ul>
+ */
+ public static void setOffscreenPreRaster(WebSettings webSettings, boolean enabled) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ webSettings.setOffscreenPreRaster(enabled);
+ } else {
+ getAdapter(webSettings).setOffscreenPreRaster(enabled);
+ }
+ }
+
+ /**
+ * Gets whether this WebView should raster tiles when it is
+ * offscreen but attached to a window.
+ * @return {@code true} if this WebView will raster tiles when it is
+ * offscreen but attached to a window.
+ */
+ public static boolean getOffscreenPreRaster(WebSettings webSettings) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ return webSettings.getOffscreenPreRaster();
+ } else {
+ return getAdapter(webSettings).getOffscreenPreRaster();
+ }
+ }
+
+ /**
+ * Sets whether Safe Browsing is enabled. Safe Browsing allows WebView to
+ * protect against malware and phishing attacks by verifying the links.
+ *
+ * <p>
+ * Safe Browsing can be disabled for all WebViews using a manifest tag (read <a
+ * href="{@docRoot}reference/android/webkit/WebView.html">general Safe Browsing info</a>). The
+ * manifest tag has a lower precedence than this API.
+ *
+ * <p>
+ * Safe Browsing is enabled by default for devices which support it.
+ *
+ * @param enabled Whether Safe Browsing is enabled.
+ */
+ public static void setSafeBrowsingEnabled(WebSettings webSettings, boolean enabled) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ webSettings.setSafeBrowsingEnabled(enabled);
+ } else {
+ getAdapter(webSettings).setSafeBrowsingEnabled(enabled);
+ }
+ }
+
+ /**
+ * Gets whether Safe Browsing is enabled.
+ * See {@link #setSafeBrowsingEnabled}.
+ *
+ * @return {@code true} if Safe Browsing is enabled and {@code false} otherwise.
+ */
+ public static boolean getSafeBrowsingEnabled(WebSettings webSettings) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ return webSettings.getSafeBrowsingEnabled();
+ } else {
+ return getAdapter(webSettings).getSafeBrowsingEnabled();
+ }
+ }
+
+ /**
+ * Disables the action mode menu items according to {@code menuItems} flag.
+ * @param menuItems an integer field flag for the menu items to be disabled.
+ */
+ public static void setDisabledActionModeMenuItems(WebSettings webSettings, int menuItems) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ webSettings.setDisabledActionModeMenuItems(menuItems);
+ } else {
+ getAdapter(webSettings).setDisabledActionModeMenuItems(menuItems);
+ }
+ }
+
+ /**
+ * Gets the action mode menu items that are disabled, expressed in an integer field flag.
+ * The default value is {@link WebSettings#MENU_ITEM_NONE}
+ *
+ * @return all the disabled menu item flags combined with bitwise OR.
+ */
+ public static int getDisabledActionModeMenuItems(WebSettings webSettings) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ return webSettings.getDisabledActionModeMenuItems();
+ } else {
+ return getAdapter(webSettings).getDisabledActionModeMenuItems();
+ }
+ }
+
+ private static WebSettingsAdapter getAdapter(WebSettings webSettings) {
+ return WebViewGlueCommunicator.getCompatConverter().convertSettings(webSettings);
+ }
+}
+
diff --git a/webkit/src/main/java/androidx/webkit/WebViewCompat.java b/webkit/src/main/java/androidx/webkit/WebViewCompat.java
index 3141918..ee328aa 100644
--- a/webkit/src/main/java/androidx/webkit/WebViewCompat.java
+++ b/webkit/src/main/java/androidx/webkit/WebViewCompat.java
@@ -16,16 +16,21 @@
package androidx.webkit;
+import android.content.Context;
+import android.net.Uri;
import android.os.Build;
import android.os.Looper;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.v4.os.BuildCompat;
+import android.webkit.ValueCallback;
import android.webkit.WebView;
import org.chromium.support_lib_boundary.WebViewProviderBoundaryInterface;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.List;
import androidx.webkit.internal.WebViewGlueCommunicator;
import androidx.webkit.internal.WebViewProviderAdapter;
@@ -120,6 +125,79 @@
}
}
+ /**
+ * Starts Safe Browsing initialization.
+ * <p>
+ * URL loads are not guaranteed to be protected by Safe Browsing until after {@code callback} is
+ * invoked with {@code true}. Safe Browsing is not fully supported on all devices. For those
+ * devices {@code callback} will receive {@code false}.
+ * <p>
+ * This should not be called if Safe Browsing has been disabled by manifest tag or {@link
+ * android.webkit.WebSettings#setSafeBrowsingEnabled}. This prepares resources used for Safe
+ * Browsing.
+ * <p>
+ * This should be called with the Application Context (and will always use the Application
+ * context to do its work regardless).
+ *
+ * @param context Application Context.
+ * @param callback will be called on the UI thread with {@code true} if initialization is
+ * successful, {@code false} otherwise.
+ */
+ public static void startSafeBrowsing(@NonNull Context context,
+ @Nullable ValueCallback<Boolean> callback) {
+ if (Build.VERSION.SDK_INT >= 27) {
+ WebView.startSafeBrowsing(context, callback);
+ } else { // TODO(gsennton): guard with WebViewApk.hasFeature(SafeBrowsing)
+ getFactory().getStatics().initSafeBrowsing(context, callback);
+ }
+ }
+
+ /**
+ * Sets the list of hosts (domain names/IP addresses) that are exempt from SafeBrowsing checks.
+ * The list is global for all the WebViews.
+ * <p>
+ * Each rule should take one of these:
+ * <table>
+ * <tr><th> Rule </th> <th> Example </th> <th> Matches Subdomain</th> </tr>
+ * <tr><td> HOSTNAME </td> <td> example.com </td> <td> Yes </td> </tr>
+ * <tr><td> .HOSTNAME </td> <td> .example.com </td> <td> No </td> </tr>
+ * <tr><td> IPV4_LITERAL </td> <td> 192.168.1.1 </td> <td> No </td></tr>
+ * <tr><td> IPV6_LITERAL_WITH_BRACKETS </td><td>[10:20:30:40:50:60:70:80]</td><td>No</td></tr>
+ * </table>
+ * <p>
+ * All other rules, including wildcards, are invalid.
+ * <p>
+ * The correct syntax for hosts is defined by <a
+ * href="https://tools.ietf.org/html/rfc3986#section-3.2.2">RFC 3986</a>.
+ *
+ * @param hosts the list of hosts
+ * @param callback will be called with {@code true} if hosts are successfully added to the
+ * whitelist. It will be called with {@code false} if any hosts are malformed. The callback
+ * will be run on the UI thread
+ */
+ public static void setSafeBrowsingWhitelist(@NonNull List<String> hosts,
+ @Nullable ValueCallback<Boolean> callback) {
+ if (Build.VERSION.SDK_INT >= 27) {
+ WebView.setSafeBrowsingWhitelist(hosts, callback);
+ } else { // TODO(gsennton): guard with WebViewApk.hasFeature(SafeBrowsing)
+ getFactory().getStatics().setSafeBrowsingWhitelist(hosts, callback);
+ }
+ }
+
+ /**
+ * Returns a URL pointing to the privacy policy for Safe Browsing reporting.
+ *
+ * @return the url pointing to a privacy policy document which can be displayed to users.
+ */
+ @NonNull
+ public static Uri getSafeBrowsingPrivacyPolicyUrl() {
+ if (Build.VERSION.SDK_INT >= 27) {
+ return WebView.getSafeBrowsingPrivacyPolicyUrl();
+ } else { // TODO(gsennton): guard with WebViewApk.hasFeature(SafeBrowsing)
+ return getFactory().getStatics().getSafeBrowsingPrivacyPolicyUrl();
+ }
+ }
+
private static WebViewProviderAdapter getProvider(WebView webview) {
return new WebViewProviderAdapter(createProvider(webview));
}
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebSettingsAdapter.java b/webkit/src/main/java/androidx/webkit/internal/WebSettingsAdapter.java
new file mode 100644
index 0000000..091879c
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/WebSettingsAdapter.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit.internal;
+
+import org.chromium.support_lib_boundary.WebSettingsBoundaryInterface;
+
+/**
+ * Adapter between WebSettingsCompat and
+ * {@link org.chromium.support_lib_boundary.WebSettingsBoundaryInterface} (the
+ * corresponding interface shared with the support library glue in the WebView APK).
+ */
+public class WebSettingsAdapter {
+ private WebSettingsBoundaryInterface mBoundaryInterface;
+
+ public WebSettingsAdapter(WebSettingsBoundaryInterface boundaryInterface) {
+ mBoundaryInterface = boundaryInterface;
+ }
+
+ /**
+ * Adapter method for {@link androidx.webkit.WebSettingsCompat#setOffscreenPreRaster}.
+ */
+ public void setOffscreenPreRaster(boolean enabled) {
+ mBoundaryInterface.setOffscreenPreRaster(enabled);
+ }
+
+ /**
+ * Adapter method for {@link androidx.webkit.WebSettingsCompat#getOffscreenPreRaster}.
+ */
+ public boolean getOffscreenPreRaster() {
+ return mBoundaryInterface.getOffscreenPreRaster();
+ }
+
+ /**
+ * Adapter method for {@link androidx.webkit.WebSettingsCompat#setSafeBrowsingEnabled}.
+ */
+ public void setSafeBrowsingEnabled(boolean enabled) {
+ mBoundaryInterface.setSafeBrowsingEnabled(enabled);
+ }
+
+ /**
+ * Adapter method for {@link androidx.webkit.WebSettingsCompat#getSafeBrowsingEnabled}.
+ */
+ public boolean getSafeBrowsingEnabled() {
+ return mBoundaryInterface.getSafeBrowsingEnabled();
+ }
+
+ /**
+ * Adapter method for {@link androidx.webkit.WebSettingsCompat#setDisabledActionModeMenuItems}.
+ */
+ public void setDisabledActionModeMenuItems(int menuItems) {
+ mBoundaryInterface.setDisabledActionModeMenuItems(menuItems);
+ }
+
+ /**
+ * Adapter method for {@link androidx.webkit.WebSettingsCompat#getDisabledActionModeMenuItems}.
+ */
+ public int getDisabledActionModeMenuItems() {
+ return mBoundaryInterface.getDisabledActionModeMenuItems();
+ }
+
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java b/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
index f97b2d8..24bb2d1 100644
--- a/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
@@ -42,10 +42,17 @@
return LAZY_FACTORY_HOLDER.INSTANCE;
}
+ public static WebkitToCompatConverter getCompatConverter() {
+ return LAZY_FACTORY_HOLDER.COMPAT_CONVERTER;
+ }
+
private static class LAZY_FACTORY_HOLDER {
static final WebViewProviderFactoryAdapter INSTANCE =
new WebViewProviderFactoryAdapter(
WebViewGlueCommunicator.createGlueProviderFactory());
+ static final WebkitToCompatConverter COMPAT_CONVERTER =
+ new WebkitToCompatConverter(
+ INSTANCE.getWebkitToCompatConverter());
}
private static InvocationHandler fetchGlueProviderFactoryImpl() {
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
index d961c09..80067ed 100644
--- a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
@@ -19,8 +19,10 @@
import android.webkit.WebView;
import org.chromium.support_lib_boundary.BoundaryInterfaceReflectionUtil;
+import org.chromium.support_lib_boundary.StaticsBoundaryInterface;
import org.chromium.support_lib_boundary.WebViewProviderBoundaryInterface;
import org.chromium.support_lib_boundary.WebViewProviderFactoryBoundaryInterface;
+import org.chromium.support_lib_boundary.WebkitToCompatConverterBoundaryInterface;
/**
* Adapter for WebViewProviderFactoryBoundaryInterface providing static WebView functionality
@@ -42,4 +44,23 @@
return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
WebViewProviderBoundaryInterface.class, mImpl.createWebView(webview));
}
+
+ /**
+ * Adapter method for creating a new support library version of
+ * {@link androidx.webkit.internal.WebkitToCompatConverter}, which converts android.webkit
+ * classes into their corresponding support library classes.
+ */
+ public WebkitToCompatConverterBoundaryInterface getWebkitToCompatConverter() {
+ return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+ WebkitToCompatConverterBoundaryInterface.class, mImpl.getWebkitToCompatConverter());
+ }
+
+ /**
+ * Adapter method for fetching the support library class representing
+ * {@link android.webkit.WebViewFactoryProvider#Statics}.
+ */
+ public StaticsBoundaryInterface getStatics() {
+ return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+ StaticsBoundaryInterface.class, mImpl.getStatics());
+ }
}
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebkitToCompatConverter.java b/webkit/src/main/java/androidx/webkit/internal/WebkitToCompatConverter.java
new file mode 100644
index 0000000..cb40530
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/WebkitToCompatConverter.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit.internal;
+
+import android.webkit.WebSettings;
+
+import org.chromium.support_lib_boundary.BoundaryInterfaceReflectionUtil;
+import org.chromium.support_lib_boundary.WebSettingsBoundaryInterface;
+import org.chromium.support_lib_boundary.WebkitToCompatConverterBoundaryInterface;
+
+/**
+ * A class providing functionality for converting android.webkit classes into support library
+ * classes.
+ */
+public class WebkitToCompatConverter {
+ private final WebkitToCompatConverterBoundaryInterface mImpl;
+
+ public WebkitToCompatConverter(WebkitToCompatConverterBoundaryInterface impl) {
+ mImpl = impl;
+ }
+
+ /**
+ * Return a WebSettingsAdapter linked to webSettings such that calls on either of those
+ * objects affect the other object. That WebSettingsAdapter can be used to implement
+ * {@link androidx.webkit.WebSettingsCompat}.
+ */
+ public WebSettingsAdapter convertSettings(WebSettings webSettings) {
+ return new WebSettingsAdapter(BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+ WebSettingsBoundaryInterface.class, mImpl.convertSettings(webSettings)));
+ }
+}